From 224ff0ea4be2f1fbe7445736dc1a005e80d7f9df Mon Sep 17 00:00:00 2001 From: Bryan Latten Date: Fri, 22 May 2020 12:56:11 -0400 Subject: [PATCH] Feature: HTTPS support (#74) Co-authored-by: Bryan Latten --- .travis.yml | 6 +++ Dockerfile | 3 +- Dockerfile-alpine | 1 + Dockerfile-centos | 2 +- README.md | 52 ++++++++++++++++--- .../root/etc/cont-init.d/10-nginx-config.sh | 9 ++++ .../root/etc/nginx/sites-available/default | 11 ++++ 7 files changed, 74 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index f1a8acf..9772818 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,8 +10,14 @@ services: script: - docker build -t nginxtest -f ${DOCKERFILE} . +- mkdir certs +- openssl genrsa -out ./certs/ca.key 2048 +- openssl req -new -key ./certs/ca.key -out ./certs/ca.csr -subj '/CN=localhost' +- openssl x509 -req -days 365 -in ./certs/ca.csr -signkey ./certs/ca.key -out ./certs/ca.crt - docker run -p 8080:8080 -d nginxtest - docker run -p 8081:8080 -d --env-file ./.test.env nginxtest +- docker run -p 8082:8080 -d -e SERVER_ENABLE_HTTPS=true -v $(pwd)/certs:/etc/nginx/certs:ro nginxtest - sleep 5 - curl localhost:8080 | grep "Welcome to nginx!" - curl localhost:8081 | grep "Welcome to nginx!" +- curl -k https://localhost:8082 | grep "Welcome to nginx!" diff --git a/Dockerfile b/Dockerfile index 648f4d7..ba7772a 100644 --- a/Dockerfile +++ b/Dockerfile @@ -13,7 +13,7 @@ ENV CONTAINER_ROLE=web \ # Using a non-privileged port to prevent having to use setcap internally EXPOSE ${CONTAINER_PORT} -# - Update security packages, only +# - Update security packages, plus ca-certificates required for https # - Install pre-reqs # - Install latest nginx (development PPA is actually mainline development) # - Perform cleanup, ensure unnecessary packages are removed @@ -25,6 +25,7 @@ RUN /bin/bash -e /security_updates.sh && \ apt-get update -yqq && \ apt-get install -yqq --no-install-recommends \ nginx-light \ + ca-certificates \ && \ apt-get remove --purge -yq \ manpages \ diff --git a/Dockerfile-alpine b/Dockerfile-alpine index 584a0da..e84f531 100644 --- a/Dockerfile-alpine +++ b/Dockerfile-alpine @@ -18,6 +18,7 @@ RUN adduser -D -S -H $NOT_ROOT_USER RUN apk update --no-cache && \ apk add \ + ca-certificates \ nginx \ && \ /bin/bash -e /clean.sh diff --git a/Dockerfile-centos b/Dockerfile-centos index 212acfa..64865db 100644 --- a/Dockerfile-centos +++ b/Dockerfile-centos @@ -16,7 +16,7 @@ EXPOSE ${CONTAINER_PORT} # - Update security packages, only RUN /bin/bash -e /security_updates.sh && \ yum -y -q install epel-release && \ - yum -y -q install nginx && \ + yum -y -q install nginx ca-certificates && \ yum -y -q remove epel-release && \ /bin/bash -e /clean.sh diff --git a/README.md b/README.md index c968ccb..6e4e374 100644 --- a/README.md +++ b/README.md @@ -2,17 +2,18 @@ https://hub.docker.com/r/behance/docker-nginx/tags/ -Ubuntu used by default -Alpine builds available tagged as `-alpine` -Centos builds available tagged as `-centos` - Provides base OS, patches and stable nginx for quick and easy spinup. -[S6](https://github.com/just-containers/s6-overlay) process supervisor is used for `only` for zombie reaping (as PID 1), boot coordination, and termination signal translation +- Ubuntu used by default +- Alpine builds available tagged as `-alpine` +- Centos builds available tagged as `-centos` + + +[S6](https://github.com/just-containers/s6-overlay) process supervisor is used for `only` for zombie reaping (as PID 1), boot coordination, and termination signal translation -[Goss](https://github.com/aelsabbahy/goss) is used for build-time testing. +[Goss](https://github.com/aelsabbahy/goss) is used for build-time testing. -See parent(s) [docker-base](https://github.com/behance/docker-base) for additional configuration +See parent(s) [docker-base](https://github.com/behance/docker-base) for additional configuration ### Expectations @@ -22,11 +23,45 @@ See parent(s) [docker-base](https://github.com/behance/docker-base) for addition - NOTE: Nginx is exposed and bound to an unprivileged port, `8080` -### Security +### Container Security See parent [configuration](https://github.com/behance/docker-base#security) +### HTTPS usage + +To enable this container to serve HTTPS over its primary exposed port: +- `SERVER_ENABLE_HTTPS` environment variable must be `true` +- Certificates must be present in `/etc/nginx/certs` under the following names: + - `ca.crt` + - `ca.key` +- Additionally, they must be marked read-only (0600) + +#### Local development usage + +To generate a self-signed certificate (won't work in most browsers): +``` +openssl genrsa -out ca.key 2048 +openssl req -new -key ca.key -out ca.csr -subj '/CN=localhost' +openssl x509 -req -days 365 -in ca.csr -signkey ca.key -out ca.crt +``` + +Run the image in background, bind external port (443), flag HTTPS enabled, mount certificate: +``` +docker run \ + -d + -p 443:8080 \ + -e SERVER_ENABLE_HTTPS=true \ + -v {directory-containing-ca.crt-and-ca.key}:/etc/nginx/certs:ro + behance/docker-nginx +``` + +Test +``` +curl -k -vvv https://{your-docker-machine-ip} +``` + + ### Environment Variables Variable | Example | Description @@ -36,6 +71,7 @@ SERVER_INDEX | SERVER_INDEX index.html index.html index.php | Changes the defaul SERVER_APP_NAME | SERVER_APP_NAME='view' | Gets appended to the default logging format SERVER_GZIP_OPTIONS | SERVER_GZIP_OPTIONS=1 | Allows default set of static content to be served gzipped SERVER_SENDFILE | SERVER_SENDFILE=off | Allows runtime to specify value of nginx's `sendfile` (default, on) +SERVER_ENABLE_HTTPS | SERVER_ENABLE_HTTPS=true | Enable encrypted transmission using certificates SERVER_KEEPALIVE | SERVER_KEEPALIVE=30 | Define HTTP 1.1's keepalive timeout SERVER_WORKER_PROCESSES | SERVER_WORKER_PROCESSES=4 | Set to the number of cores in the machine, or the number of cores allocated to container SERVER_WORKER_CONNECTIONS | SERVER_WORKER_CONNECTIONS=2048 | Sets up the number of connections for worker processes diff --git a/container/root/etc/cont-init.d/10-nginx-config.sh b/container/root/etc/cont-init.d/10-nginx-config.sh index 4685143..1510664 100755 --- a/container/root/etc/cont-init.d/10-nginx-config.sh +++ b/container/root/etc/cont-init.d/10-nginx-config.sh @@ -74,3 +74,12 @@ then echo "[nginx] setting client_body_buffer_size to ${SERVER_CLIENT_BODY_BUFFER_SIZE}" sed -i "s/client_body_buffer_size .*;/client_body_buffer_size ${SERVER_CLIENT_BODY_BUFFER_SIZE};/" $CONF_NGINX_SERVER fi + +if [[ $SERVER_ENABLE_HTTPS ]] +then + echo "[nginx] enabling HTTPS" + # Uncomment all ssl* directives in site configuration + sed -i "s/^[ ]*#ssl/ ssl/" $CONF_NGINX_SITE + # Add SSL to listen directive + sed -i "s/^[ ]*listen ${CONTAINER_PORT}/ listen ${CONTAINER_PORT} ssl/" $CONF_NGINX_SITE +fi diff --git a/container/root/etc/nginx/sites-available/default b/container/root/etc/nginx/sites-available/default index 653ebf4..ba95047 100644 --- a/container/root/etc/nginx/sites-available/default +++ b/container/root/etc/nginx/sites-available/default @@ -1,6 +1,17 @@ server { listen 8080; + # Enable with env variable SERVER_ENABLE_HTTPS=true + #ssl_certificate /etc/nginx/certs/ca.crt; + #ssl_certificate_key /etc/nginx/certs/ca.key; + + # https://ssl-config.mozilla.org/#server=nginx&version=1.17.7&config=intermediate&openssl=1.1.1d&hsts=false&ocsp=false&guideline=5.4 + #ssl_protocols TLSv1.2 TLSv1.3; + #ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384; + #ssl_prefer_server_ciphers off; + #ssl_session_cache shared:SSL:10m; + #ssl_session_timeout 10m; + root /var/www/html; # Doesn't broadcast version level of server software