Closed khba closed 6 years ago
Given https://github.com/moby/moby/issues/8460#issuecomment-312459310, you should be able to get pretty far:
$ docker run -it --rm --user 1000 --sysctl net.ipv4.ip_unprivileged_port_start=0 httpd
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.18.0.29. Set the 'ServerName' directive globally to suppress this message
AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.18.0.29. Set the 'ServerName' directive globally to suppress this message
[Tue Jul 10 20:36:16.676190 2018] [core:error] [pid 1:tid 140275100432256] (13)Permission denied: AH00099: could not create /usr/local/apache2/logs/httpd.pid
[Tue Jul 10 20:36:16.676463 2018] [core:error] [pid 1:tid 140275100432256] AH00100: httpd: could not log pid to file /usr/local/apache2/logs/httpd.pid
(Filesystem permissions are easier to deal with than kernel blocks, so this is good.)
I did this : setcap + chown + User www-data inside the Dockerfile + build and the image works fine on the host as www-data:
$ docker run --rm 43dee066c55f AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message [Wed Jul 11 09:51:33.316839 2018] [mpm_event:notice] [pid 1:tid 140008104651656] AH00489: Apache/2.4.33 (Unix) configured -- resuming normal operations [Wed Jul 11 09:51:33.316997 2018] [core:notice] [pid 1:tid 140008104651656] AH00094: Command line: 'httpd -D FOREGROUND'
But when I pull the same image and run it on another node , it falls back to the first error: $ docker run --rm 43dee066c55f AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message (13)Permission denied: AH00072: make_sock: could not bind to address [::]:80 (13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80
Is this binding to port 80 denied by the container's system or the host's system? Logically the "permission denied" was coming from the container's system and since we fixed that, the image should be able to run everywhere as non-root right?
Here is the Dockerfile:
FROM httpd:2.4-alpine
#Custom changes
RUN apk update; \
apk upgrade;
RUN apk -q add curl \
vim \
libcap ;
#Change access righs to conf, logs, bin from root to www-data
RUN chown -hR www-data:www-data /usr/local/apache2/
#setcap to bind to privileged ports as non-root
RUN setcap 'cap_net_bind_service=+ep' /usr/local/apache2/bin/httpd
RUN getcap /usr/local/apache2/bin/httpd
HEALTHCHECK --interval=60s --timeout=30s CMD nc -zv localhost 80 || exit 1
#Run as a www-data
USER www-data
Your setcap
probably doesn't round-trip through the graph drivers
properly.
Excuse my english but I don' t really understand "Your setcap
probably doesn't round-trip through the graph drivers properly", what do you mean by that?
Is there a way to fix it and make the image portable?
If it means what I think, the storage driver on the node where the image is running fine is aufs, and the one where it fails is overlay2. Even if I rebuild the image on the node with overlay2, still the same. Does that mean setcap is incompatible with overlay2 storage driver? Is that normal?
Thanks,
I'm not fully understanding your use case, you mention a node, do you mean you're using swarm and stack deploying to a node, and that this worker node is experiencing an anomaly with permissions of some sort?
By my understanding you're primarily concerned with test section 4.1 of the docker-bench-security
test which tests for running as normal user in the container. I'm not able to reproduce any error while deploying a stack to a swarm and testing the nodes.
Dockerfile
FROM httpd:2.4-alpine
#Custom changes
RUN apk update && apk upgrade
RUN apk -q add curl vim libcap
#Change access righs to conf, logs, bin from root to www-data
RUN chown -hR www-data:www-data /usr/local/apache2/
#setcap to bind to privileged ports as non-root
RUN setcap 'cap_net_bind_service=+ep' /usr/local/apache2/bin/httpd
RUN getcap /usr/local/apache2/bin/httpd
HEALTHCHECK --interval=60s --timeout=30s CMD nc -zv localhost 80 || exit 1
#Run as a www-data
USER www-data
docker-compose.yml
version: "3"
services:
httpd_test:
image: httpd_test
deploy:
replicas: 2
Manager node:
[INFO] 4 - Container Images and Build File
[PASS] 4.1 - Ensure a user for the container has been created
Worker node:
[INFO] 4 - Container Images and Build File
[PASS] 4.1 - Ensure a user for the container has been created
"I'm not able to reproduce any error while deploying a stack to a swarm and testing the nodes." => Yes it is normal that you pass the test 4.1 since "USER www-data" was added to the Dockerfile, therefore the container processes run as non-root. But are your nodes on everlay2 and is apache actually running fine?
Anyway the consequence of adding "User www-data" was that "www-data" user couldn't bind to port 80 and caused apache to fail, which led us to add the setcap instruction. Now the problem is that that new image runs normally if the node has aufs storage driver, but hits again the "Can't bind to port 80" error if you try to run it on a node with overlay2 storage driver.
Yes my initial use case is to deploy it on a swarm (where all the nodes are on everlay2), but to not complicate things, one can simply reproduce this with 2 simple docker hosts, one with aufs and the other with overlay2 like this:
With aufs: => works OK: $ docker run --rm image_name AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.3. Set the 'ServerName' directive globally to suppress this message [Wed Jul 11 09:51:33.316839 2018] [mpm_event:notice] [pid 1:tid 140008104651656] AH00489: Apache/2.4.33 (Unix) configured -- resuming normal operations [Wed Jul 11 09:51:33.316997 2018] [core:notice] [pid 1:tid 140008104651656] AH00094: Command line: 'httpd -D FOREGROUND'
With overlay2: works not despite setcap: $ docker run --rm image_name AH00558: httpd: Could not reliably determine the server's fully qualified domain name, using 172.17.0.2. Set the 'ServerName' directive globally to suppress this message (13)Permission denied: AH00072: make_sock: could not bind to address [::]:80 (13)Permission denied: AH00072: make_sock: could not bind to address 0.0.0.0:80
I'm using the default AUFS, if you're encountering anomalous behavior on a differing storage driver then you could create an issue on https://github.com/moby/moby as we maintain the official-images and not the underlying components of Docker
Manager node
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
645f15e02290 httpd_test:latest "httpd-foreground" 5 minutes ago Up 5 minutes (healthy) 80/tcp httpd_test_httpd_test.2.trty9eq62w0jo64b2h37w1cch
$ curl 127.0.0.1
<html><body><h1>It works!</h1></body></html>
Worker node
$ docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
8b9061c3725d httpd_test:latest "httpd-foreground" 5 minutes ago Up 5 minutes (healthy) 80/tcp httpd_test_httpd_test.1.xx14geqpdljybirs8nkj8jhzd
$ curl localhost:80
<html><body><h1>It works!</h1></body></html>
I'm not able to reproduce any issues with the image, if you want further help troubleshooting issues you should try the Docker Community Forums, the Docker Community Slack, or Stack Overflow.
I'm not fully understanding your use case, you mention a node, do you mean you're using swarm and stack deploying to a node, and that this worker node is experiencing an anomaly with permissions of some sort? By my understanding you're primarily concerned with test section 4.1 of the
docker-bench-security
test which tests for running as normal user in the container. I'm not able to reproduce any error while deploying a stack to a swarm and testing the nodes.
Dockerfile
FROM httpd:2.4-alpine #Custom changes RUN apk update && apk upgrade RUN apk -q add curl vim libcap #Change access righs to conf, logs, bin from root to www-data RUN chown -hR www-data:www-data /usr/local/apache2/ #setcap to bind to privileged ports as non-root RUN setcap 'cap_net_bind_service=+ep' /usr/local/apache2/bin/httpd RUN getcap /usr/local/apache2/bin/httpd HEALTHCHECK --interval=60s --timeout=30s CMD nc -zv localhost 80 || exit 1 #Run as a www-data USER www-data
docker-compose.yml
version: "3" services: httpd_test: image: httpd_test deploy: replicas: 2
Manager node Worker node Manager node:
[INFO] 4 - Container Images and Build File [PASS] 4.1 - Ensure a user for the container has been created
Worker node:
[INFO] 4 - Container Images and Build File [PASS] 4.1 - Ensure a user for the container has been created
Manager node container logs Worker node container logs
Helpful!!
Hello,
In order to respect the check 4.1 from the docker security tests https://github.com/docker/docker-bench-security, is there a way to run the container without ever using root?
I know the daemon is started as root to be able to bind to privileged ports like 80 and then start child processes as the user defined in httpd.conf file (daemon or www-data usually), but from a security standpoint, that's already a problem that the container can run as root in the beginning. Is there a workaround for this to avoid using root and if possible bind on port 80?
Thanks,