There are multiple approaches to allowing a process to run as a non-root user but still provide access to privileged ports (<1024).
There are applications like Apache that handle this by starting the master process as root, and then worker processes as a less privileged user. Another way is setting the privilege on a binary using ‘setcap cap_net_bind_service‘ to allow binding to privileged ports. Yet another is to use the authbind utility.
In this article I will show how to run Tomcat as a non-privileged user on port 8080, and then use an iptables local redirect rule to forward traffic from the privileged port on 80 to Tomcat.
Install Tomcat
First install Tomcat7, which is available in the main repository on both Ubuntu trusty and xenial.
$ sudo apt-get install tomcat7
This creates a user named “tomcat7” and the start-stop-daemon (Ubuntu 14.04) or systemd (Ubuntu 16.04) creates the process running as this user. This can be verified with “ps -ef | grep tomcat”.
The Tomcat process is running insecure HTTP by default on port 8080 (/etc/tomcat7/server.xml), which is a non-privileged port. This can be verified with “sudo lsof -i :8080” or “sudo netstat -tulnp | grep 8080”.
Now check an HTTP request to Tomcat on port 8080 using curl, and you should receive back a Tomcat welcome page.
$ curl http://<IP>:8080
Create iptables local forwarding rule
There is only a single iptables rule you need to create in order to do local port forwarding.
$ sudo iptables -t nat -A PREROUTING -p tcp --dport 80 -j REDIRECT --to-ports 8080
Now all packets attempting to reach privileged port 80 will be forwarded to the Tomcat service running on port 8080. From a different host console, now do a curl against port 80, and the Tomcat welcome page will be returned.
$ curl http://<IP>:80
Note that curl directly from the host itself will not work (http://127.0.0.1:80) because local packets do not go through PREROUTING. But you can add to the iptables OUTPUT chain in order to enable this port forwarding locally.
$ sudo iptables -t nat -A OUTPUT -p tcp --dport 80 --dst 127.0.0.1 --src 0/0 -j REDIRECT --to-ports 8080
Now a local curl to http://127.0.0.1 should return the Tomcat welcome page also.
iptables maintenance
The rules can be listed using:
$ sudo iptables -L -t nat -v --line-numbers
Rules can be deleted using this syntax:
$ sudo iptables -t nat -D <chain=PREROUTING|OUTPUT|etc> <number>
Persisting the rules
By default, the rules you just added will not be persisted through a reboot. In order to save them:
# Ubuntu trusty 14.04 $ sudo apt-get install iptables-persistent $ sudo iptables-save > /etc/iptables/rules.v4 # Ubuntu xenial 16.04 $ sudo apt-get install iptables-persistent $ sudo netfilter-persistent save
REFERENCES
https://superuser.com/questions/710253/allow-non-root-process-to-bind-to-port-80-and-443/892391#892391 (CAP_NET_BIND_SERVICE)
https://unix.stackexchange.com/questions/10735/allowing-a-user-to-let-listen-to-a-port-below-1024 (iptables redirect, inetd alternatives)
http://randomthoughtsonjavaprogramming.blogspot.com/2015/10/running-glassfish-on-port-80.html
https://superuser.com/questions/710253/allow-non-root-process-to-bind-to-port-80-and-443 (cap_net_bind_service and authbind)
https://httpd.apache.org/docs/2.4/mod/worker.html (worker processes, non-root)
https://askubuntu.com/questions/694036/apache-as-non-root
https://wiki.apache.org/httpd/NonRootPortBinding (set_cap and alternative iptables method)
https://wiki.debian.org/Firewalls-local-port-redirection (single iptables redirect rule)