From ad7c8d592029d1cc7c48962c6fc9b7461b30e0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20R?= Date: Fri, 19 Jan 2018 19:35:20 +0100 Subject: [PATCH 1/3] Add SSL proxy for http/2 use By default will generate a self signed certificate, however also supports mounting own trusted certificate. --- doc/docker/Dockerfile-nginx-ssl-proxy | 17 +++++++ .../ssl-proxy/docker-ssl-entrypoint | 28 ++++++++++++ doc/docker/entrypoint/ssl-proxy/nginx.conf | 45 +++++++++++++++++++ doc/docker/entrypoint/varnish/entrypoint.sh | 2 +- doc/docker/varnish.yml | 14 +++++- 5 files changed, 104 insertions(+), 2 deletions(-) create mode 100644 doc/docker/Dockerfile-nginx-ssl-proxy create mode 100755 doc/docker/entrypoint/ssl-proxy/docker-ssl-entrypoint create mode 100644 doc/docker/entrypoint/ssl-proxy/nginx.conf diff --git a/doc/docker/Dockerfile-nginx-ssl-proxy b/doc/docker/Dockerfile-nginx-ssl-proxy new file mode 100644 index 0000000000..efe934f908 --- /dev/null +++ b/doc/docker/Dockerfile-nginx-ssl-proxy @@ -0,0 +1,17 @@ +FROM nginx:stable +# Based on: https://github.com/clamorisse/nginx-ssl-container + +RUN mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak + +RUN apt-get update -q -y \ + && apt-get install -q -y --no-install-recommends ca-certificates openssl \ + && rm -rf /var/lib/apt/lists/* + +ADD entrypoint/ssl-proxy/nginx.conf /etc/nginx/ + +COPY entrypoint/ssl-proxy/docker-ssl-entrypoint /usr/local/bin/ + +EXPOSE 443 + +ENTRYPOINT ["docker-ssl-entrypoint"] +CMD ["nginx", "-g", "daemon off;"] diff --git a/doc/docker/entrypoint/ssl-proxy/docker-ssl-entrypoint b/doc/docker/entrypoint/ssl-proxy/docker-ssl-entrypoint new file mode 100755 index 0000000000..fbfbae089b --- /dev/null +++ b/doc/docker/entrypoint/ssl-proxy/docker-ssl-entrypoint @@ -0,0 +1,28 @@ +#!/bin/sh -e +# Based on among others: https://github.com/fsouza/docker-ssl-proxy + +DOMAIN=${DOMAIN:-localhost} + +CA_DIR=/etc/nginx/ca + +# If this change, then you'1ll also need ot change nginx.conf +OUTPUT_DIR=/etc/nginx/certs + +mkdir -p $OUTPUT_DIR $CA_DIR + +# Generate the root CA if it doesn't exist +if [ ! -f ${CA_DIR}/rootCA.crt ]; then + openssl genrsa -out ${CA_DIR}/rootCA.key 1024 + openssl req -x509 -new -nodes -key ${CA_DIR}/rootCA.key -sha256 -days 1024 -subj "/C=US/ST=Denial/L=Springfield/O=DisRoot/CN=CompanyRoot" -out ${CA_DIR}/rootCA.crt +fi + +# Generate the certificate, if it doesn't exist +if [ ! -f ${OUTPUT_DIR}/key.pem ]; then + openssl genrsa -out ${OUTPUT_DIR}/key.pem 1024 + openssl req -new -sha256 -key ${OUTPUT_DIR}/key.pem -nodes -subj "/C=US/ST=Denial/L=Springfield/O=Dis/CN=${DOMAIN}" -out ${OUTPUT_DIR}/csr.pem + openssl x509 -req -in ${OUTPUT_DIR}/csr.pem -CA ${CA_DIR}/rootCA.crt -CAkey ${CA_DIR}/rootCA.key -CAcreateserial -out ${OUTPUT_DIR}/cert.pem +fi + +echo ">> exec CMD" +echo "$@" +exec "$@" diff --git a/doc/docker/entrypoint/ssl-proxy/nginx.conf b/doc/docker/entrypoint/ssl-proxy/nginx.conf new file mode 100644 index 0000000000..d50525b642 --- /dev/null +++ b/doc/docker/entrypoint/ssl-proxy/nginx.conf @@ -0,0 +1,45 @@ +user nginx; +worker_processes 1; + +error_log /var/log/nginx/error.log warn; +pid /var/run/nginx.pid; + + +events { + worker_connections 1024; +} + +http { + access_log off; + + sendfile on; + tcp_nopush on; + tcp_nodelay on; + keepalive_timeout 15; + + server { + listen 443 ssl http2; + + client_max_body_size 40m; + ssl_certificate /etc/nginx/certs/cert.pem; + ssl_certificate_key /etc/nginx/certs/key.pem; + + ssl on; + ssl_session_cache builtin:1000 shared:SSL:10m; + ssl_session_timeout 10m; + ssl_protocols TLSv1 TLSv1.1 TLSv1.2; + ssl_ciphers HIGH:!aNULL:!eNULL:!EXPORT:!CAMELLIA:!DES:!MD5:!PSK:!RC4; + ssl_prefer_server_ciphers on; + + location / { + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + proxy_set_header X-Forwarded-Proto $scheme; + proxy_set_header X-Forwarded-Host $host; + proxy_set_header X-Forwarded-Port 443; + proxy_set_header Host $host; + + proxy_pass http://varnish:80; + } + } +} diff --git a/doc/docker/entrypoint/varnish/entrypoint.sh b/doc/docker/entrypoint/varnish/entrypoint.sh index 8b53cd2cd9..f8bfd1d18d 100755 --- a/doc/docker/entrypoint/varnish/entrypoint.sh +++ b/doc/docker/entrypoint/varnish/entrypoint.sh @@ -71,4 +71,4 @@ while (( "$#" )); do shift done -varnishd -F -a :80 -T :6082 -f /etc/varnish/default.vcl -s malloc,${VARNISH_MALLOC_SIZE} +varnishd -F -a :80 -T :6082 -f /etc/varnish/default.vcl -s malloc,${VARNISH_MALLOC_SIZE} -p feature=+http2 diff --git a/doc/docker/varnish.yml b/doc/docker/varnish.yml index e215eddd05..755b455a85 100644 --- a/doc/docker/varnish.yml +++ b/doc/docker/varnish.yml @@ -9,7 +9,7 @@ services: app: environment: - SYMFONY_HTTP_CACHE=0 - - SYMFONY_TRUSTED_PROXIES=varnish + - SYMFONY_TRUSTED_PROXIES=ssl,varnish - HTTPCACHE_PURGE_SERVER=http://varnish - HTTPCACHE_PURGE_TYPE=http @@ -29,6 +29,18 @@ services: - backend command: ["--acl-add", "app"] + ssl: + build: + context: . + dockerfile: Dockerfile-nginx-ssl-proxy + ports: + - "8443:443" + depends_on: + - varnish + networks: + - frontend + - backend + ## DEBUG?? # In need of debugging all request going to Varnish, use varnishlog, example: # docker-compose exec varnish varnishlog -c -i ReqURL,ReqMethod -I ReqHeader:xkey From c5248618fbf38c575f122d7dabc534455af388b4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20R?= Date: Wed, 24 Jan 2018 06:49:27 +0100 Subject: [PATCH 2/3] Add support for resolving host names passed to SYMFONY_TRUSTED_PROXIES --- web/app.php | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/web/app.php b/web/app.php index 8ae8d95335..5f768dcf77 100644 --- a/web/app.php +++ b/web/app.php @@ -60,9 +60,14 @@ $request = Request::createFromGlobals(); // If you are behind one or more trusted reverse proxies, you might want to set them in SYMFONY_TRUSTED_PROXIES environment -// variable in order to get correct client IP +// variable in order to get correct client IP, also by default supports passing in host name to lookup DNS A record (IPv4) if ($trustedProxies = getenv('SYMFONY_TRUSTED_PROXIES')) { - Request::setTrustedProxies(explode(',', $trustedProxies)); + Request::setTrustedProxies(array_map( + function ($adr) { + return is_string($adr) ? gethostbyname($adr) : $adr; + }, + explode(',', $trustedProxies) + )); } $response = $kernel->handle($request); From 78904a4d17fa888f272256085f68ee41862126ad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andre=CC=81=20R?= Date: Wed, 24 Jan 2018 14:56:24 +0100 Subject: [PATCH 3/3] Make it possible to inject port to SSL and Varnihs proxy In order to get symfony to use the right docker port: - make it possible to pass it from parent to Varnihs VCL in a trusted way - make it possible to dynamicaly inject port to ssl proxy image (using pear module in this case) --- doc/docker/Dockerfile-nginx-ssl-proxy | 2 +- doc/docker/entrypoint/ssl-proxy/nginx.conf | 9 ++++++++- doc/docker/entrypoint/varnish/parameters.vcl | 5 +++++ doc/docker/varnish.yml | 2 ++ doc/varnish/vcl/parameters.vcl | 5 +++++ doc/varnish/vcl/varnish4_xkey.vcl | 12 +++++++----- 6 files changed, 28 insertions(+), 7 deletions(-) diff --git a/doc/docker/Dockerfile-nginx-ssl-proxy b/doc/docker/Dockerfile-nginx-ssl-proxy index efe934f908..852e5c3ad4 100644 --- a/doc/docker/Dockerfile-nginx-ssl-proxy +++ b/doc/docker/Dockerfile-nginx-ssl-proxy @@ -1,4 +1,4 @@ -FROM nginx:stable +FROM nginx:stable-perl # Based on: https://github.com/clamorisse/nginx-ssl-container RUN mv /etc/nginx/nginx.conf /etc/nginx/nginx.conf.bak diff --git a/doc/docker/entrypoint/ssl-proxy/nginx.conf b/doc/docker/entrypoint/ssl-proxy/nginx.conf index d50525b642..901f1e9f05 100644 --- a/doc/docker/entrypoint/ssl-proxy/nginx.conf +++ b/doc/docker/entrypoint/ssl-proxy/nginx.conf @@ -4,6 +4,10 @@ worker_processes 1; error_log /var/log/nginx/error.log warn; pid /var/run/nginx.pid; +load_module /etc/nginx/modules/ngx_http_perl_module.so; + +# To pass in the public facing forward port we want to set +env X_FORWARD_PORT; events { worker_connections 1024; @@ -17,6 +21,9 @@ http { tcp_nodelay on; keepalive_timeout 15; + # Get SSL port to use from X_FORWARD_PORT env variable, or fallback to 443 + perl_set $x_forward_port 'sub { return $ENV{"X_FORWARD_PORT"} || 443; }'; + server { listen 443 ssl http2; @@ -36,7 +43,7 @@ http { proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; proxy_set_header X-Forwarded-Proto $scheme; proxy_set_header X-Forwarded-Host $host; - proxy_set_header X-Forwarded-Port 443; + proxy_set_header X-Forwarded-Port $x_forward_port; proxy_set_header Host $host; proxy_pass http://varnish:80; diff --git a/doc/docker/entrypoint/varnish/parameters.vcl b/doc/docker/entrypoint/varnish/parameters.vcl index c3f40c97e4..4a708edb10 100644 --- a/doc/docker/entrypoint/varnish/parameters.vcl +++ b/doc/docker/entrypoint/varnish/parameters.vcl @@ -16,3 +16,8 @@ acl debuggers { "127.0.0.1"; "172.16.0.0"/20; } + +// ACL for trusted proxies IP +acl proxies { + "ssl"; +} diff --git a/doc/docker/varnish.yml b/doc/docker/varnish.yml index 755b455a85..6248d17259 100644 --- a/doc/docker/varnish.yml +++ b/doc/docker/varnish.yml @@ -35,6 +35,8 @@ services: dockerfile: Dockerfile-nginx-ssl-proxy ports: - "8443:443" + environment: + - X_FORWARD_PORT=8443 depends_on: - varnish networks: diff --git a/doc/varnish/vcl/parameters.vcl b/doc/varnish/vcl/parameters.vcl index 00820f64c6..bf36a22f10 100644 --- a/doc/varnish/vcl/parameters.vcl +++ b/doc/varnish/vcl/parameters.vcl @@ -19,3 +19,8 @@ acl debuggers { "127.0.0.1"; "192.168.0.0"/16; } + +// ACL for trusted proxies IP +acl proxies { + "127.0.0.1"; +} diff --git a/doc/varnish/vcl/varnish4_xkey.vcl b/doc/varnish/vcl/varnish4_xkey.vcl index 981e2a8b00..24683b269d 100644 --- a/doc/varnish/vcl/varnish4_xkey.vcl +++ b/doc/varnish/vcl/varnish4_xkey.vcl @@ -30,11 +30,13 @@ sub vcl_recv { // To be removed in Symfony 3.3 unset req.http.Forwarded; - // Ensure that the Symfony Router generates URLs correctly with Varnish - if (req.http.X-Forwarded-Proto == "https" ) { - set req.http.X-Forwarded-Port = "443"; - } else { - set req.http.X-Forwarded-Port = "80"; + // Ensure that the Symfony Router generates URLs correctly with Varnish, if port is not set by trusted proxy already + if (! req.http.X-Forwarded-Port || ! client.ip ~ proxies) { + if (req.http.X-Forwarded-Proto == "https" ) { + set req.http.X-Forwarded-Port = "443"; + } else { + set req.http.X-Forwarded-Port = "80"; + } } // Trigger cache purge if needed