1
0
mirror of https://github.com/thib8956/nginx-proxy synced 2024-11-22 03:46:29 +00:00

Merge pull request #589 from kamermans/feature_ssl_improvement

SSL security enhancement
This commit is contained in:
Jason Wilder 2017-06-22 11:54:51 -06:00 committed by GitHub
commit 02121df3b9
40 changed files with 327 additions and 48 deletions

1
.gitignore vendored
View File

@ -1,2 +1,3 @@
**/__pycache__/
**/.cache/
.idea/

View File

@ -9,9 +9,9 @@ RUN apt-get update \
&& apt-get clean \
&& rm -r /var/lib/apt/lists/*
# Configure Nginx and apply fix for very long server names
RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
&& sed -i 's/^http {/&\n server_names_hash_bucket_size 128;/g' /etc/nginx/nginx.conf \
&& sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf
# Install Forego
@ -29,7 +29,7 @@ WORKDIR /app/
ENV DOCKER_HOST unix:///tmp/docker.sock
VOLUME ["/etc/nginx/certs"]
VOLUME ["/etc/nginx/certs", "/etc/nginx/dhparam"]
ENTRYPOINT ["/app/docker-entrypoint.sh"]
CMD ["forego", "start", "-r"]

View File

@ -3,12 +3,12 @@ MAINTAINER Jason Wilder mail@jasonwilder.com
# Install wget and install/updates certificates
RUN apk add --no-cache --virtual .run-deps \
ca-certificates bash wget \
ca-certificates bash wget openssl \
&& update-ca-certificates
# Configure Nginx and apply fix for very long server names
RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
&& sed -i 's/^http {/&\n server_names_hash_bucket_size 128;/g' /etc/nginx/nginx.conf \
&& sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf
# Install Forego
@ -26,7 +26,7 @@ WORKDIR /app/
ENV DOCKER_HOST unix:///tmp/docker.sock
VOLUME ["/etc/nginx/certs"]
VOLUME ["/etc/nginx/certs", "/etc/nginx/dhparam"]
ENTRYPOINT ["/app/docker-entrypoint.sh"]
CMD ["forego", "start", "-r"]

View File

@ -100,6 +100,8 @@ In this example, the `my-nginx-proxy` container will be connected to `my-network
If you would like the reverse proxy to connect to your backend using HTTPS instead of HTTP, set `VIRTUAL_PROTO=https` on the backend container.
> Note: If you use `VIRTUAL_PROTO=https` and your backend container exposes port 80 and 443, `nginx-proxy` will use HTTPS on port 80. This is almost certainly not what you want, so you should also include `VIRTUAL_PORT=443`.
### uWSGI Backends
If you would like to connect to uWSGI backend, set `VIRTUAL_PROTO=uwsgi` on the
@ -171,9 +173,21 @@ By default, Docker is not able to mount directories on the host machine to conta
#### Diffie-Hellman Groups
If you have Diffie-Hellman groups enabled, the files should be named after the virtual host with a
Diffie-Hellman groups are enabled by default, with a pregenerated key in `/etc/nginx/dhparam/dhparam.pem`.
You can mount a different `dhparam.pem` file at that location to override the default cert.
To use custom `dhparam.pem` files per-virtual-host, the files should be named after the virtual host with a
`dhparam` suffix and `.pem` extension. For example, a container with `VIRTUAL_HOST=foo.bar.com`
should have a `foo.bar.com.dhparam.pem` file in the certs directory.
should have a `foo.bar.com.dhparam.pem` file in the `/etc/nginx/certs` directory.
> NOTE: If you don't mount a `dhparam.pem` file at `/etc/nginx/dhparam/dhparam.pem`, one will be generated
at startup. Since it can take minutes to generate a new `dhparam.pem`, it is done at low priority in the
background. Once generation is complete, the `dhparams.pem` is saved on a persistent volume and nginx
is reloaded. This generation process only occurs the first time you start `nginx-proxy`.
> COMPATIBILITY WARNING: The default generated `dhparam.pem` key is 2048 bits for A+ security. Some
> older clients (like Java 6 and 7) do not support DH keys with over 1024 bits. In order to support these
> clients, you must either provide your own `dhparam.pem`, or tell `nginx-proxy` to generate a 1024-bit
> key on startup by passing `-e DHPARAM_BITS=1024`.
#### Wildcard Certificates
@ -189,10 +203,13 @@ and `CERT_NAME=shared` will then use this shared cert.
#### How SSL Support Works
The SSL cipher configuration is based on [mozilla nginx intermediate profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx) which
The SSL cipher configuration is based on the [Mozilla nginx intermediate profile](https://wiki.mozilla.org/Security/Server_Side_TLS#Nginx) which
should provide compatibility with clients back to Firefox 1, Chrome 1, IE 7, Opera 5, Safari 1,
Windows XP IE8, Android 2.3, Java 7. The configuration also enables HSTS, and SSL
session caches.
Windows XP IE8, Android 2.3, Java 7. Note that the DES-based TLS ciphers were removed for security.
The configuration also enables HSTS, PFS, and SSL session caches. Currently TLS 1.0, 1.1 and 1.2
are supported. TLS 1.0 is deprecated but its end of life is not until June 30, 2018. It is being
included because the following browsers will stop working when it is removed: Chrome < 22, Firefox < 27,
IE < 11, Safari < 7, iOS < 5, Android Browser < 5.
The default behavior for the proxy when port 80 and 443 are exposed is as follows:

8
dhparam.pem.default Normal file
View File

@ -0,0 +1,8 @@
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEAzB2nIGzpVq7afJnKBm1X0d64avwOlP2oneiKwxRHdDI/5+6TpH1P
F8ipodGuZBUMmupoB3D34pu2Qq5boNW983sm18ww9LMz2i/pxhSdB+mYAew+A6h6
ltQ5pNtyn4NaKw1SDFkqvde3GNPhaWoPDbZDJhpHGblR3w1b/ag+lTLZUvVwcD8L
jYS9f9YWAC6T7WxAxh4zvu1Z0I1EKde8KYBxrreZNheXpXHqMNyJYZCaY2Hb/4oI
EL65qZq1GCWezpWMjhk6pOnV5gbvqfhoazCv/4OdRv6RoWOIYBNs9BmGho4AtXqV
FYLdYDhOvN4aVs9Ir+G8ouwiRnix24+UewIBAg==
-----END DH PARAMETERS-----

View File

@ -2,7 +2,7 @@
set -e
# Warn if the DOCKER_HOST socket does not exist
if [[ $DOCKER_HOST == unix://* ]]; then
if [[ $DOCKER_HOST = unix://* ]]; then
socket_file=${DOCKER_HOST#unix://}
if ! [ -S $socket_file ]; then
cat >&2 <<-EOT
@ -14,6 +14,10 @@ if [[ $DOCKER_HOST == unix://* ]]; then
fi
fi
# Generate dhparam file if required
# Note: if $DHPARAM_BITS is not defined, generate-dhparam.sh will use 2048 as a default
/app/generate-dhparam.sh $DHPARAM_BITS
# If the user has run the default command and the socket doesn't exist, fail
if [ "$socketMissing" = 1 -a "$1" = forego -a "$2" = start -a "$3" = '-r' ]; then
exit 1

45
generate-dhparam.sh Executable file
View File

@ -0,0 +1,45 @@
#!/bin/bash -e
# The first argument is the bit depth of the dhparam, or 2048 if unspecified
DHPARAM_BITS=${1:-2048}
# If a dhparam file is not available, use the pre-generated one and generate a new one in the background.
# Note that /etc/nginx/dhparam is a volume, so this dhparam will persist restarts.
PREGEN_DHPARAM_FILE="/app/dhparam.pem.default"
DHPARAM_FILE="/etc/nginx/dhparam/dhparam.pem"
GEN_LOCKFILE="/tmp/dhparam_generating.lock"
# The hash of the pregenerated dhparam file is used to check if the pregen dhparam is already in use
PREGEN_HASH=$(md5sum $PREGEN_DHPARAM_FILE | cut -d" " -f1)
if [[ -f $DHPARAM_FILE ]]; then
CURRENT_HASH=$(md5sum $DHPARAM_FILE | cut -d" " -f1)
if [[ $PREGEN_HASH != $CURRENT_HASH ]]; then
# There is already a dhparam, and it's not the default
echo "Custom dhparam.pem file found, generation skipped"
exit 0
fi
if [[ -f $GEN_LOCKFILE ]]; then
# Generation is already in progress
exit 0
fi
fi
cat >&2 <<-EOT
WARNING: $DHPARAM_FILE was not found. A pre-generated dhparam.pem will be used for now while a new one
is being generated in the background. Once the new dhparam.pem is in place, nginx will be reloaded.
EOT
# Put the default dhparam file in place so we can start immediately
cp $PREGEN_DHPARAM_FILE $DHPARAM_FILE
touch $GEN_LOCKFILE
# Generate a new dhparam in the background in a low priority and reload nginx when finished (grep removes the progress indicator).
(
(
nice -n +5 openssl dhparam -out $DHPARAM_FILE $DHPARAM_BITS 2>&1 \
&& echo "dhparam generation complete, reloading nginx" \
&& nginx -s reload
) | grep -vE '^[\.+]+'
rm $GEN_LOCKFILE
) &disown

View File

@ -38,6 +38,12 @@ map $http_upgrade $proxy_connection {
'' close;
}
# Apply fix for very long server names
server_names_hash_bucket_size 128;
# Default dhparam
ssl_dhparam /etc/nginx/dhparam/dhparam.pem;
# Set appropriate X-Forwarded-Ssl header
map $scheme $proxy_x_forwarded_ssl {
default off;
@ -178,7 +184,7 @@ server {
access_log /var/log/nginx/access.log vhost;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:ECDHE-ECDSA-DES-CBC3-SHA:ECDHE-RSA-DES-CBC3-SHA:EDH-RSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:DES-CBC3-SHA:!DSS';
ssl_ciphers 'ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA:ECDHE-RSA-AES256-SHA384:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA:ECDHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-RSA-AES256-SHA256:DHE-RSA-AES256-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:!DSS';
ssl_prefer_server_ciphers on;
ssl_session_timeout 5m;

8
test/lib/ssl/dhparam.pem Normal file
View File

@ -0,0 +1,8 @@
-----BEGIN DH PARAMETERS-----
MIIBCAKCAQEA1cae6HqPSgicEuAuSCf6Ii3d6qMX9Ta8lnwoX0JQ0CWK7mzaiiIi
dY7oHmc4cq0S3SH+g0tdLP9yqygFS9hdUGINwS2VV6poj2/vdL/dUshegyxpEH58
nofCPnFDeKkcPDMYAlGS8zjp60TsBkRJKcrxxwnjod1Q5mWuMN5KH3sxs842udKH
0nHFE9kKW/NfXb+EGsjpocGpf786cGuCO2d00THsoItOEcM9/aI8DX1QcyxAHR6D
HaYTFJnyyx8Q44u27M15idI4pbNoKORlotiuOwCTGYCfbN14aOV+Ict7aSF8FWpP
48j9SMNuIu2DlF9pNLo6fsrOjYY3c9X12wIBAg==
-----END DH PARAMETERS-----

View File

@ -1,5 +1,10 @@
FROM python:2.7
FROM python:2.7-alpine
# Note: we're using alpine because it has openssl 1.0.2, which we need for testing
RUN apk add --update bash openssl curl && rm -rf /var/cache/apk/*
COPY python-requirements.txt /requirements.txt
RUN pip install -r /requirements.txt
WORKDIR /test
ENTRYPOINT ["pytest"]

View File

@ -1,5 +1,5 @@
web1:
image: web
image: web
expose:
- "81"
environment:
@ -8,7 +8,7 @@ web1:
web2:
image: web
expose:
expose:
- "82"
environment:
WEB_PORTS: 82
@ -19,6 +19,6 @@ sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/f00.sock:ro
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
environment:
DOCKER_HOST: unix:///f00.sock

View File

@ -4,11 +4,12 @@ services:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
web:
image: web
image: web
expose:
- "81"
environment:
WEB_PORTS: 81
VIRTUAL_HOST: web.nginx-proxy.local
VIRTUAL_HOST: web.nginx-proxy.local

View File

@ -2,11 +2,12 @@ nginx-proxy:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/default_location:ro
- ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.local_location:ro
web1:
image: web
image: web
expose:
- "81"
environment:
@ -14,7 +15,7 @@ web1:
VIRTUAL_HOST: web1.nginx-proxy.local
web2:
image: web
image: web
expose:
- "82"
environment:
@ -22,9 +23,9 @@ web2:
VIRTUAL_HOST: web2.nginx-proxy.local
web3:
image: web
image: web
expose:
- "83"
environment:
WEB_PORTS: 83
VIRTUAL_HOST: web3.nginx-proxy.local
VIRTUAL_HOST: web3.nginx-proxy.local

View File

@ -4,10 +4,11 @@ services:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./my_custom_proxy_settings.conf:/etc/nginx/proxy.conf:ro
web1:
image: web
image: web
expose:
- "81"
environment:
@ -15,9 +16,9 @@ services:
VIRTUAL_HOST: web1.nginx-proxy.local
web2:
image: web
image: web
expose:
- "82"
environment:
WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.local
VIRTUAL_HOST: web2.nginx-proxy.local

View File

@ -4,10 +4,11 @@ services:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.local_location:ro
web1:
image: web
image: web
expose:
- "81"
environment:
@ -15,9 +16,9 @@ services:
VIRTUAL_HOST: web1.nginx-proxy.local
web2:
image: web
image: web
expose:
- "82"
environment:
WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.local
VIRTUAL_HOST: web2.nginx-proxy.local

View File

@ -4,10 +4,11 @@ services:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.local:ro
web1:
image: web
image: web
expose:
- "81"
environment:
@ -15,9 +16,9 @@ services:
VIRTUAL_HOST: web1.nginx-proxy.local
web2:
image: web
image: web
expose:
- "82"
environment:
WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.local
VIRTUAL_HOST: web2.nginx-proxy.local

View File

@ -4,10 +4,11 @@ services:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./my_custom_proxy_settings.conf:/etc/nginx/conf.d/my_custom_proxy_settings.conf:ro
web1:
image: web
image: web
expose:
- "81"
environment:
@ -15,9 +16,9 @@ services:
VIRTUAL_HOST: web1.nginx-proxy.local
web2:
image: web
image: web
expose:
- "82"
environment:
WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.local
VIRTUAL_HOST: web2.nginx-proxy.local

View File

@ -13,5 +13,6 @@ sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
environment:
DEFAULT_HOST: web1.tld

View File

@ -6,6 +6,7 @@ services:
container_name: nginx
volumes:
- /etc/nginx/conf.d
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
dockergen:
image: jwilder/docker-gen
@ -23,4 +24,4 @@ services:
- "80"
environment:
WEB_PORTS: 80
VIRTUAL_HOST: whoami.nginx.container.docker
VIRTUAL_HOST: whoami.nginx.container.docker

View File

@ -2,7 +2,7 @@ import os
import docker
import logging
import pytest
import re
def versiontuple(v):
"""

View File

@ -5,6 +5,7 @@ services:
container_name: nginx
volumes:
- nginx_conf:/etc/nginx/conf.d
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
dockergen:
image: jwilder/docker-gen
@ -24,4 +25,4 @@ services:
VIRTUAL_HOST: whoami.nginx.container.docker
volumes:
nginx_conf: {}
nginx_conf: {}

View File

@ -2,3 +2,4 @@ nginxproxy:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

View File

@ -10,4 +10,5 @@ web:
sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

View File

@ -13,3 +13,4 @@ sut:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./certs/web.nginx-proxy.tld.crt:/etc/nginx/certs/web.nginx-proxy.tld.crt:ro
- ./certs/web.nginx-proxy.tld.key:/etc/nginx/certs/web.nginx-proxy.tld.key:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

View File

@ -1,5 +1,5 @@
web1:
image: web
image: web
expose:
- "81"
environment:
@ -8,7 +8,7 @@ web1:
web2:
image: web
expose:
expose:
- "82"
environment:
WEB_PORTS: 82
@ -19,5 +19,6 @@ sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
environment:
ENABLE_IPV6: "true"

View File

@ -11,3 +11,4 @@ sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

View File

@ -9,12 +9,13 @@ services:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
networks:
- net1
- net2
web1:
image: web
image: web
expose:
- "81"
environment:
@ -24,11 +25,11 @@ services:
- net1
web2:
image: web
image: web
expose:
- "82"
environment:
WEB_PORTS: 82
VIRTUAL_HOST: web2.nginx-proxy.local
networks:
- net2
- net2

View File

@ -12,3 +12,4 @@ sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

View File

@ -11,3 +11,4 @@ sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

View File

@ -10,4 +10,5 @@ web:
sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

View File

@ -1,5 +1,5 @@
web1:
image: web
image: web
expose:
- "81"
environment:
@ -8,7 +8,7 @@ web1:
web2:
image: web
expose:
expose:
- "82"
environment:
WEB_PORTS: 82
@ -19,3 +19,4 @@ sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

View File

@ -0,0 +1,93 @@
import re
import subprocess
import backoff
import docker
import pytest
docker_client = docker.from_env()
###############################################################################
#
# Tests helpers
#
###############################################################################
@backoff.on_exception(backoff.constant, AssertionError, interval=2, max_tries=15, jitter=None)
def assert_log_contains(expected_log_line):
"""
Check that the nginx-proxy container log contains a given string.
The backoff decorator will retry the check 15 times with a 2 seconds delay.
:param expected_log_line: string to search for
:return: None
:raises: AssertError if the expected string is not found in the log
"""
sut_container = docker_client.containers.get("nginxproxy")
docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
assert expected_log_line in docker_logs
def require_openssl(required_version):
"""
This function checks that the required version of OpenSSL is present, and skips the test if not.
Use it as a test function decorator:
@require_openssl("2.3.4")
def test_something():
...
:param required_version: minimal required version as a string: "1.2.3"
"""
def versiontuple(v):
clean_v = re.sub("[^\d\.]", "", v)
return tuple(map(int, (clean_v.split("."))))
try:
command_output = subprocess.check_output(["openssl", "version"])
except OSError:
return pytest.mark.skip("openssl command is not available in test environment")
else:
if not command_output:
raise Exception("Could not get openssl version")
openssl_version = command_output.split()[1]
return pytest.mark.skipif(
versiontuple(openssl_version) < versiontuple(required_version),
reason="openssl v%s is less than required version %s" % (openssl_version, required_version))
###############################################################################
#
# Tests
#
###############################################################################
def test_dhparam_is_not_generated_if_present(docker_compose):
sut_container = docker_client.containers.get("nginxproxy")
assert sut_container.status == "running"
assert_log_contains("Custom dhparam.pem file found, generation skipped")
# Make sure the dhparam in use is not the default, pre-generated one
default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").split()
current_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").split()
assert default_checksum[0] != current_checksum[0]
def test_web5_https_works(docker_compose, nginxproxy):
r = nginxproxy.get("https://web5.nginx-proxy.tld/port", allow_redirects=False)
assert r.status_code == 200
assert "answer from port 85\n" in r.text
@require_openssl("1.0.2")
def test_web5_dhparam_is_used(docker_compose):
sut_container = docker_client.containers.get("nginxproxy")
assert sut_container.status == "running"
host = "%s:443" % sut_container.attrs["NetworkSettings"]["IPAddress"]
r = subprocess.check_output(
"echo '' | openssl s_client -verify 0 -connect %s -cipher 'EDH' | grep 'Server Temp Key'" % host, shell=True)
assert "Server Temp Key: DH, 2048 bits\n" == r

View File

@ -0,0 +1,16 @@
web5:
image: web
expose:
- "85"
environment:
WEB_PORTS: "85"
VIRTUAL_HOST: "web5.nginx-proxy.tld"
sut:
image: jwilder/nginx-proxy:test
container_name: nginxproxy
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./certs:/etc/nginx/certs:ro

View File

@ -0,0 +1,44 @@
import backoff
import docker
docker_client = docker.from_env()
###############################################################################
#
# Tests helpers
#
###############################################################################
@backoff.on_exception(backoff.constant, AssertionError, interval=2, max_tries=15, jitter=None)
def assert_log_contains(expected_log_line):
"""
Check that the nginx-proxy container log contains a given string.
The backoff decorator will retry the check 15 times with a 2 seconds delay.
:param expected_log_line: string to search for
:return: None
:raises: AssertError if the expected string is not found in the log
"""
sut_container = docker_client.containers.get("nginxproxy")
docker_logs = sut_container.logs(stdout=True, stderr=True, stream=False, follow=False)
assert expected_log_line in docker_logs
###############################################################################
#
# Tests
#
###############################################################################
def test_dhparam_is_generated_if_missing(docker_compose):
sut_container = docker_client.containers.get("nginxproxy")
assert sut_container.status == "running"
assert_log_contains("Generating DH parameters")
assert_log_contains("dhparam generation complete, reloading nginx")
# Make sure the dhparam in use is not the default, pre-generated one
default_checksum = sut_container.exec_run("md5sum /app/dhparam.pem.default").split()
generated_checksum = sut_container.exec_run("md5sum /etc/nginx/dhparam/dhparam.pem").split()
assert default_checksum[0] != generated_checksum[0]

View File

@ -0,0 +1,8 @@
sut:
image: jwilder/nginx-proxy:test
container_name: nginxproxy
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./certs:/etc/nginx/certs:ro
environment:
- DHPARAM_BITS=256

View File

@ -12,4 +12,5 @@ sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./certs:/etc/nginx/certs:ro

View File

@ -11,4 +11,5 @@ web:
sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro

View File

@ -12,4 +12,5 @@ sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./certs:/etc/nginx/certs:ro

View File

@ -10,4 +10,5 @@ sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
- ./certs:/etc/nginx/certs:ro

View File

@ -34,4 +34,5 @@ web4:
sut:
image: jwilder/nginx-proxy:test
volumes:
- /var/run/docker.sock:/tmp/docker.sock:ro
- /var/run/docker.sock:/tmp/docker.sock:ro
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro