diff --git a/doc/docker/Dockerfile-nginx-ssl-proxy b/doc/docker/Dockerfile-nginx-ssl-proxy new file mode 100644 index 0000000000..852e5c3ad4 --- /dev/null +++ b/doc/docker/Dockerfile-nginx-ssl-proxy @@ -0,0 +1,17 @@ +FROM nginx:stable-perl +# 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..901f1e9f05 --- /dev/null +++ b/doc/docker/entrypoint/ssl-proxy/nginx.conf @@ -0,0 +1,52 @@ +user nginx; +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; +} + +http { + access_log off; + + sendfile on; + tcp_nopush on; + 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; + + 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 $x_forward_port; + 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/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 e215eddd05..6248d17259 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,20 @@ services: - backend command: ["--acl-add", "app"] + ssl: + build: + context: . + dockerfile: Dockerfile-nginx-ssl-proxy + ports: + - "8443:443" + environment: + - X_FORWARD_PORT=8443 + 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 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 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);