mirror of
https://github.com/thib8956/nginx-proxy
synced 2024-11-22 11:56:31 +00:00
Merge pull request #589 from kamermans/feature_ssl_improvement
SSL security enhancement
This commit is contained in:
commit
02121df3b9
1
.gitignore
vendored
1
.gitignore
vendored
@ -1,2 +1,3 @@
|
|||||||
**/__pycache__/
|
**/__pycache__/
|
||||||
**/.cache/
|
**/.cache/
|
||||||
|
.idea/
|
||||||
|
@ -9,9 +9,9 @@ RUN apt-get update \
|
|||||||
&& apt-get clean \
|
&& apt-get clean \
|
||||||
&& rm -r /var/lib/apt/lists/*
|
&& rm -r /var/lib/apt/lists/*
|
||||||
|
|
||||||
|
|
||||||
# Configure Nginx and apply fix for very long server names
|
# Configure Nginx and apply fix for very long server names
|
||||||
RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
|
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
|
&& sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf
|
||||||
|
|
||||||
# Install Forego
|
# Install Forego
|
||||||
@ -29,7 +29,7 @@ WORKDIR /app/
|
|||||||
|
|
||||||
ENV DOCKER_HOST unix:///tmp/docker.sock
|
ENV DOCKER_HOST unix:///tmp/docker.sock
|
||||||
|
|
||||||
VOLUME ["/etc/nginx/certs"]
|
VOLUME ["/etc/nginx/certs", "/etc/nginx/dhparam"]
|
||||||
|
|
||||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||||
CMD ["forego", "start", "-r"]
|
CMD ["forego", "start", "-r"]
|
||||||
|
@ -3,12 +3,12 @@ MAINTAINER Jason Wilder mail@jasonwilder.com
|
|||||||
|
|
||||||
# Install wget and install/updates certificates
|
# Install wget and install/updates certificates
|
||||||
RUN apk add --no-cache --virtual .run-deps \
|
RUN apk add --no-cache --virtual .run-deps \
|
||||||
ca-certificates bash wget \
|
ca-certificates bash wget openssl \
|
||||||
&& update-ca-certificates
|
&& update-ca-certificates
|
||||||
|
|
||||||
|
|
||||||
# Configure Nginx and apply fix for very long server names
|
# Configure Nginx and apply fix for very long server names
|
||||||
RUN echo "daemon off;" >> /etc/nginx/nginx.conf \
|
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
|
&& sed -i 's/worker_processes 1/worker_processes auto/' /etc/nginx/nginx.conf
|
||||||
|
|
||||||
# Install Forego
|
# Install Forego
|
||||||
@ -26,7 +26,7 @@ WORKDIR /app/
|
|||||||
|
|
||||||
ENV DOCKER_HOST unix:///tmp/docker.sock
|
ENV DOCKER_HOST unix:///tmp/docker.sock
|
||||||
|
|
||||||
VOLUME ["/etc/nginx/certs"]
|
VOLUME ["/etc/nginx/certs", "/etc/nginx/dhparam"]
|
||||||
|
|
||||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||||
CMD ["forego", "start", "-r"]
|
CMD ["forego", "start", "-r"]
|
||||||
|
27
README.md
27
README.md
@ -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.
|
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
|
### uWSGI Backends
|
||||||
|
|
||||||
If you would like to connect to uWSGI backend, set `VIRTUAL_PROTO=uwsgi` on the
|
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
|
#### 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`
|
`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
|
#### Wildcard Certificates
|
||||||
|
|
||||||
@ -189,10 +203,13 @@ and `CERT_NAME=shared` will then use this shared cert.
|
|||||||
|
|
||||||
#### How SSL Support Works
|
#### 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,
|
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
|
Windows XP IE8, Android 2.3, Java 7. Note that the DES-based TLS ciphers were removed for security.
|
||||||
session caches.
|
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:
|
The default behavior for the proxy when port 80 and 443 are exposed is as follows:
|
||||||
|
|
||||||
|
8
dhparam.pem.default
Normal file
8
dhparam.pem.default
Normal 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-----
|
@ -2,7 +2,7 @@
|
|||||||
set -e
|
set -e
|
||||||
|
|
||||||
# Warn if the DOCKER_HOST socket does not exist
|
# Warn if the DOCKER_HOST socket does not exist
|
||||||
if [[ $DOCKER_HOST == unix://* ]]; then
|
if [[ $DOCKER_HOST = unix://* ]]; then
|
||||||
socket_file=${DOCKER_HOST#unix://}
|
socket_file=${DOCKER_HOST#unix://}
|
||||||
if ! [ -S $socket_file ]; then
|
if ! [ -S $socket_file ]; then
|
||||||
cat >&2 <<-EOT
|
cat >&2 <<-EOT
|
||||||
@ -14,6 +14,10 @@ if [[ $DOCKER_HOST == unix://* ]]; then
|
|||||||
fi
|
fi
|
||||||
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 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
|
if [ "$socketMissing" = 1 -a "$1" = forego -a "$2" = start -a "$3" = '-r' ]; then
|
||||||
exit 1
|
exit 1
|
||||||
|
45
generate-dhparam.sh
Executable file
45
generate-dhparam.sh
Executable 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
|
@ -38,6 +38,12 @@ map $http_upgrade $proxy_connection {
|
|||||||
'' close;
|
'' 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
|
# Set appropriate X-Forwarded-Ssl header
|
||||||
map $scheme $proxy_x_forwarded_ssl {
|
map $scheme $proxy_x_forwarded_ssl {
|
||||||
default off;
|
default off;
|
||||||
@ -178,7 +184,7 @@ server {
|
|||||||
access_log /var/log/nginx/access.log vhost;
|
access_log /var/log/nginx/access.log vhost;
|
||||||
|
|
||||||
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
|
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_prefer_server_ciphers on;
|
||||||
ssl_session_timeout 5m;
|
ssl_session_timeout 5m;
|
||||||
|
8
test/lib/ssl/dhparam.pem
Normal file
8
test/lib/ssl/dhparam.pem
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
-----BEGIN DH PARAMETERS-----
|
||||||
|
MIIBCAKCAQEA1cae6HqPSgicEuAuSCf6Ii3d6qMX9Ta8lnwoX0JQ0CWK7mzaiiIi
|
||||||
|
dY7oHmc4cq0S3SH+g0tdLP9yqygFS9hdUGINwS2VV6poj2/vdL/dUshegyxpEH58
|
||||||
|
nofCPnFDeKkcPDMYAlGS8zjp60TsBkRJKcrxxwnjod1Q5mWuMN5KH3sxs842udKH
|
||||||
|
0nHFE9kKW/NfXb+EGsjpocGpf786cGuCO2d00THsoItOEcM9/aI8DX1QcyxAHR6D
|
||||||
|
HaYTFJnyyx8Q44u27M15idI4pbNoKORlotiuOwCTGYCfbN14aOV+Ict7aSF8FWpP
|
||||||
|
48j9SMNuIu2DlF9pNLo6fsrOjYY3c9X12wIBAg==
|
||||||
|
-----END DH PARAMETERS-----
|
@ -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
|
COPY python-requirements.txt /requirements.txt
|
||||||
RUN pip install -r /requirements.txt
|
RUN pip install -r /requirements.txt
|
||||||
|
|
||||||
WORKDIR /test
|
WORKDIR /test
|
||||||
ENTRYPOINT ["pytest"]
|
ENTRYPOINT ["pytest"]
|
||||||
|
@ -19,6 +19,6 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
volumes:
|
||||||
- /var/run/docker.sock:/f00.sock:ro
|
- /var/run/docker.sock:/f00.sock:ro
|
||||||
|
- ./lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||||
environment:
|
environment:
|
||||||
DOCKER_HOST: unix:///f00.sock
|
DOCKER_HOST: unix:///f00.sock
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ services:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
|
|
||||||
web:
|
web:
|
||||||
image: web
|
image: web
|
||||||
|
@ -2,6 +2,7 @@ nginx-proxy:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/default_location: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
|
- ./my_custom_proxy_settings_bar.conf:/etc/nginx/vhost.d/web3.nginx-proxy.local_location:ro
|
||||||
|
|
||||||
|
@ -4,6 +4,7 @@ services:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
- ./my_custom_proxy_settings.conf:/etc/nginx/proxy.conf:ro
|
- ./my_custom_proxy_settings.conf:/etc/nginx/proxy.conf:ro
|
||||||
|
|
||||||
web1:
|
web1:
|
||||||
|
@ -4,6 +4,7 @@ services:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.local_location:ro
|
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.local_location:ro
|
||||||
|
|
||||||
web1:
|
web1:
|
||||||
|
@ -4,6 +4,7 @@ services:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.local:ro
|
- ./my_custom_proxy_settings.conf:/etc/nginx/vhost.d/web1.nginx-proxy.local:ro
|
||||||
|
|
||||||
web1:
|
web1:
|
||||||
|
@ -4,6 +4,7 @@ services:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
- ./my_custom_proxy_settings.conf:/etc/nginx/conf.d/my_custom_proxy_settings.conf:ro
|
- ./my_custom_proxy_settings.conf:/etc/nginx/conf.d/my_custom_proxy_settings.conf:ro
|
||||||
|
|
||||||
web1:
|
web1:
|
||||||
|
@ -13,5 +13,6 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
environment:
|
environment:
|
||||||
DEFAULT_HOST: web1.tld
|
DEFAULT_HOST: web1.tld
|
||||||
|
@ -6,6 +6,7 @@ services:
|
|||||||
container_name: nginx
|
container_name: nginx
|
||||||
volumes:
|
volumes:
|
||||||
- /etc/nginx/conf.d
|
- /etc/nginx/conf.d
|
||||||
|
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||||
|
|
||||||
dockergen:
|
dockergen:
|
||||||
image: jwilder/docker-gen
|
image: jwilder/docker-gen
|
||||||
|
@ -2,7 +2,7 @@ import os
|
|||||||
import docker
|
import docker
|
||||||
import logging
|
import logging
|
||||||
import pytest
|
import pytest
|
||||||
|
import re
|
||||||
|
|
||||||
def versiontuple(v):
|
def versiontuple(v):
|
||||||
"""
|
"""
|
||||||
|
@ -5,6 +5,7 @@ services:
|
|||||||
container_name: nginx
|
container_name: nginx
|
||||||
volumes:
|
volumes:
|
||||||
- nginx_conf:/etc/nginx/conf.d
|
- nginx_conf:/etc/nginx/conf.d
|
||||||
|
- ../lib/ssl/dhparam.pem:/etc/nginx/dhparam/dhparam.pem:ro
|
||||||
|
|
||||||
dockergen:
|
dockergen:
|
||||||
image: jwilder/docker-gen
|
image: jwilder/docker-gen
|
||||||
|
@ -2,3 +2,4 @@ nginxproxy:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
|
@ -11,3 +11,4 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
|
@ -13,3 +13,4 @@ sut:
|
|||||||
- /var/run/docker.sock:/tmp/docker.sock:ro
|
- /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.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
|
- ./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
|
||||||
|
@ -19,5 +19,6 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
environment:
|
environment:
|
||||||
ENABLE_IPV6: "true"
|
ENABLE_IPV6: "true"
|
||||||
|
@ -11,3 +11,4 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
|
@ -9,6 +9,7 @@ services:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
networks:
|
networks:
|
||||||
- net1
|
- net1
|
||||||
- net2
|
- net2
|
||||||
|
@ -12,3 +12,4 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
|
@ -11,3 +11,4 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
|
@ -11,3 +11,4 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
|
@ -19,3 +19,4 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
|
93
test/test_ssl/test_dhparam.py
Normal file
93
test/test_ssl/test_dhparam.py
Normal 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
|
16
test/test_ssl/test_dhparam.yml
Normal file
16
test/test_ssl/test_dhparam.yml
Normal 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
|
44
test/test_ssl/test_dhparam_generation.py
Normal file
44
test/test_ssl/test_dhparam_generation.py
Normal 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]
|
8
test/test_ssl/test_dhparam_generation.yml
Normal file
8
test/test_ssl/test_dhparam_generation.yml
Normal 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
|
@ -12,4 +12,5 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
- ./certs:/etc/nginx/certs:ro
|
- ./certs:/etc/nginx/certs:ro
|
||||||
|
@ -12,3 +12,4 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
|
@ -12,4 +12,5 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
- ./certs:/etc/nginx/certs:ro
|
- ./certs:/etc/nginx/certs:ro
|
||||||
|
@ -10,4 +10,5 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
- ./certs:/etc/nginx/certs:ro
|
- ./certs:/etc/nginx/certs:ro
|
||||||
|
@ -35,3 +35,4 @@ sut:
|
|||||||
image: jwilder/nginx-proxy:test
|
image: jwilder/nginx-proxy:test
|
||||||
volumes:
|
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
|
||||||
|
Loading…
Reference in New Issue
Block a user