Question

I am have a working spring boot + tomcat8 embedded application that bind to ports 8080 (http) and 8888 (https). Now I am looking for a way to configure the application to run

a) on a privileged port i.e. port that is lower then 1024 i.e. port 80 and 443

b) the application should run under a non root user account.

c) the OS environment could be any Linux distro for example: debian/ubuntu or OpenBSD distro.

d) it is preferable for the solution to be configurable later on over the web interface i.e. some script.

All I found so far on the INTERNET was a manual to configure non embedded tomcat instance together with “authbind”. However I have an embedded tomcat. The man page of “authbind” says:

“ You must invoke the program using authbind. authbind will set up some environment variables, including an LD_PRELOAD, which will allow the program (including any subprocesses it may run) to bind to low-numbered (<512) ports if the system is configured to allow this. “

I issued “ps – aux” and I got the user name under which the application is running. I have configured the embedded tomcat to run on ports 80 and 443 the ports i.e. and issued the commands in the cli:

sudo touch /etc/authbind/byport/80
sudo chmod 500 /etc/authbind/byport/80
chown tito /etc/authbind/byport/80
sudo touch /etc/authbind/byport/443
sudo chmod 500 /etc/authbind/byport/443
chown tito /etc/authbind/byport/443

Now how do I invoke the embedded tomcat under the “authbind”. If “authbind” is not the right solution for this problem then how to solve this problem with spring boot.

The error message I am getting is:

2014-05-09 09:46:48.403  INFO 7880 --- [           main] .t.TomcatEmbeddedServletContainerFactory : Server initialized with port: 80
2014-05-09 09:46:48.604 ERROR 7880 --- [           main] o.a.coyote.http11.Http11NioProtocol      : Failed to initialize end point associated with ProtocolHandler ["http-nio-80"]

java.net.SocketException: Permission denied
    at sun.nio.ch.Net.bind0(Native Method)
    at sun.nio.ch.Net.bind(Net.java:414)
    at sun.nio.ch.Net.bind(Net.java:406)
    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:214)
    at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
    at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:351)
    at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:683)
    at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:456)
    at org.apache.coyote.http11.AbstractHttp11JsseProtocol.init(AbstractHttp11JsseProtocol.java:120)
    at org.apache.catalina.connector.Connector.initInternal(Connector.java:960)
    at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
    at org.apache.catalina.core.StandardService.initInternal(StandardService.java:567)
    at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
    at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:826)
    at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:139)
    at org.apache.catalina.startup.Tomcat.start(Tomcat.java:340)
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.initialize(TomcatEmbeddedServletContainer.java:79)
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.<init>(TomcatEmbeddedServletContainer.java:69)
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getTomcatEmbeddedServletContainer(TomcatEmbeddedServletContainerFactory.java:270)
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getEmbeddedServletContainer(TomcatEmbeddedServletContainerFactory.java:145)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:159)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:132)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:476)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:648)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:909)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:898)
    at org.syncServer.core.Application.main(Application.java:123)

2014-05-09 09:46:48.606 ERROR 7880 --- [           main] o.apache.catalina.core.StandardService   : Failed to initialize connector [Connector[HTTP/1.1-80]]

org.apache.catalina.LifecycleException: Failed to initialize component [Connector[HTTP/1.1-80]]
    at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:106)
    at org.apache.catalina.core.StandardService.initInternal(StandardService.java:567)
    at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
    at org.apache.catalina.core.StandardServer.initInternal(StandardServer.java:826)
    at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:139)
    at org.apache.catalina.startup.Tomcat.start(Tomcat.java:340)
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.initialize(TomcatEmbeddedServletContainer.java:79)
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer.<init>(TomcatEmbeddedServletContainer.java:69)
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getTomcatEmbeddedServletContainer(TomcatEmbeddedServletContainerFactory.java:270)
    at org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory.getEmbeddedServletContainer(TomcatEmbeddedServletContainerFactory.java:145)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.createEmbeddedServletContainer(EmbeddedWebApplicationContext.java:159)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.onRefresh(EmbeddedWebApplicationContext.java:132)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:476)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:120)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:648)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:311)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:909)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:898)
    at org.syncServer.core.Application.main(Application.java:123)
Caused by: org.apache.catalina.LifecycleException: Protocol handler initialization failed
    at org.apache.catalina.connector.Connector.initInternal(Connector.java:962)
    at org.apache.catalina.util.LifecycleBase.init(LifecycleBase.java:102)
    ... 19 common frames omitted
Caused by: java.net.SocketException: Permission denied
    at sun.nio.ch.Net.bind0(Native Method)
    at sun.nio.ch.Net.bind(Net.java:414)
    at sun.nio.ch.Net.bind(Net.java:406)
    at sun.nio.ch.ServerSocketChannelImpl.bind(ServerSocketChannelImpl.java:214)
    at sun.nio.ch.ServerSocketAdaptor.bind(ServerSocketAdaptor.java:74)
    at org.apache.tomcat.util.net.NioEndpoint.bind(NioEndpoint.java:351)
    at org.apache.tomcat.util.net.AbstractEndpoint.init(AbstractEndpoint.java:683)
    at org.apache.coyote.AbstractProtocol.init(AbstractProtocol.java:456)
    at org.apache.coyote.http11.AbstractHttp11JsseProtocol.init(AbstractHttp11JsseProtocol.java:120)
    at org.apache.catalina.connector.Connector.initInternal(Connector.java:960)
    ... 20 common frames omitted

2014-05-09 09:46:48.840  INFO 7880 --- [           main] o.apache.catalina.core.StandardService   : Starting service Tomcat
2014-05-09 09:46:48.841  INFO 7880 --- [           main] org.apache.catalina.core.StandardEngine  : Starting Servlet Engine: Apache Tomcat/8.0.3
2014-05-09 09:46:48.913  INFO 7880 --- [ost-startStop-1] o.a.c.c.C.[Tomcat].[localhost].[/]       : Initializing Spring embedded WebApplicationContext
2014-05-09 09:46:48.913  INFO 7880 --- [ost-startStop-1] o.s.web.context.ContextLoader            : Root WebApplicationContext: initialization completed in 1898 ms
SERVLET REGISTRATION
DISPATCHER INIT

ADDTION 1 i found a way how to do it from the command line i.e. from spring i do maven build with the goal set to "package" then i go to the target folder where my jar/war file is and then i do

exec authbind --deep java -jar application.jar 

The application is bound to the ports 80 and 443 but somehow my mvc thymeleaf templates got messed up. I need to automate this process trough spring sts

Was it helpful?

Solution

Reading between the lines you are trying to expose your Spring Boot application on port 80/443, but you don't really need to have it listening on one of those ports itself. Instead, you should use a reverse proxy such as HAProxy, which will start up as root, but then jails itself in a chroot so that it has no root privileges.

You then configure the proxy to forward requests to whatever port your application is listening on.

Beyond security, this has additional advantages such as being able to forward based on the URL being used to multiple services. This is fantastic for Spring Boot micro-services, as it lets you expose multiple services at ports 80/443 on the same server, without giving any of those applications root privileges. It can also be used to provide hot-switching between application instances, which can help you achieve zero-downtime deployments.

Popular alternatives to HAProxy are Apache HTTPD and Nginx.

OTHER TIPS

All staff you want is implemented in Apache Daemon Tools.

It provides chroot for java applications. So you can start it as root and bind to privileged port, then downgrade it to unprivileged user.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top