A generic WAF proxy layer
Clone or download
Pull request Compare This branch is 37 commits ahead, 35 commits behind UKHomeOffice:master.
rhowe-gds Merge pull request #20 from alphagov/update_naxsi_container
PP-4152: Update packages when building the container
Latest commit 3f3ff84 Aug 24, 2018
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
client_certs Add support for verifying the upstream server cert Oct 27, 2016
docs Uses new name nginx-proxy. Fixes mocking-server tests. Nov 17, 2015
html Conditionally present debug msg in SSI Sep 1, 2017
lua Enable setting UUID var name and passing in Sep 21, 2017
naxsi PP-3559: Change denied url to request-denied Apr 11, 2018
.dockerignore Builds Openresty nginx with sample functional config Aug 21, 2015
.drone.yml Migrate to nginx-proxy's dedicated Quay.io account Aug 2, 2017
.drone.yml.sig New drone sig Nov 22, 2017
.gitignore Will deny a location if not using cert Oct 22, 2015
.travis.yml travis_retry Sep 1, 2016
CONTRIBUTING.md Added contributing.md Sep 18, 2015
Dockerfile PP-4152: Update packages when building the container Aug 24, 2018
Jenkinsfile bau: BuildApp no longer exists Apr 12, 2018
LICENSE.md Added MIT license Aug 24, 2015
README.md PP-2604 AWS Region is now passed as an environment variable and not d… Oct 31, 2017
build.sh Remove extraneous 'cd -' before attempting to remove source trees Nov 15, 2017
ci-build.sh PP-3359: Remove verbose error tests Apr 12, 2018
code_of_conduct.md Improved the readme Aug 24, 2015
defaults.sh PP-3500 Remove defautl mapping to show nginx error page for some 5XX … Mar 19, 2018
enable_location.sh Enable setting UUID var name and passing in Sep 21, 2017
go.sh Make better use of bash's variable tests Jul 7, 2018
helper.sh Added docker tests and readyness check to verify it all still works Oct 23, 2015
location_template.conf PP-3359: Clearing email addresses in request and referer fields. Jun 21, 2018
logging.conf PP-3359: Clearing email addresses in request and referer fields. Jun 21, 2018
monkey-business.yaml add a slow service Sep 1, 2016
nginx.conf Enable setting UUID var name and passing in Sep 21, 2017
nginx_rate_limits_null.conf Added rate and connection limits per location Jun 21, 2016
nginx_statsd_metrics.conf Made statsd metrics a configuration option Aug 16, 2016
nginx_statsd_server.conf Made statsd metrics a configuration option Aug 16, 2016
nginx_web_sockets_proxy.conf Added web sockets support Nov 10, 2015
publish.sh Bug-fix: Don't hard-code source image Aug 17, 2017
readyness.sh Improved tests and verified redirect content for 403 Jul 4, 2016
refresh_GeoIP.sh Added GeoIP country whitelist options Jul 1, 2016
test-servers.yaml Add support for individual custom error pages Sep 28, 2016

README.md

OpenResty Docker Container

Build Status

This container aims to be a generic proxy layer for your web services. It includes OpenResty with Lua and NAXSI filtering compiled in.

Getting Started

In this section I'll show you some examples of how you might run this container with docker.

Prerequisites

In order to run this container you'll need docker installed.

Usage

Environment Variables

Multi-location Variables

Variables to control how to configure the proxy (can be set per location, see Using Multiple Locations).

  • PROXY_SERVICE_HOST - The upstream host you want this service to proxy.
  • PROXY_SERVICE_PORT - The port of the upstream host you want this service to proxy.
  • NAXSI_RULES_URL_CSV - A CSV of Naxsi URL's of files to download and use. (Files must end in .rules to be loaded)
  • NAXSI_RULES_MD5_CSV - A CSV of md5 hashes for the files specified above
  • EXTRA_NAXSI_RULES - Allows NAXSI rules to be specified as an environment variable. This allows one or two extra rules to be specified without downloading or mounting in a rule file.
  • NAXSI_USE_DEFAULT_RULES - If set to "FALSE" will delete the default rules file.
  • ENABLE_UUID_PARAM - If set to "FALSE", will NOT add a UUID url parameter to all requests. The Default will add this for easy tracking in down stream logs e.g. nginxId=50c91049-667f-4286-c2f0-86b04b27d3f0. If set to HEADER it will add nginxId to the headers, not append to the get params.
  • CLIENT_CERT_REQUIRED - if set to TRUE, will deny access at this location, see Client Certs.
  • VERIFY_SERVER_CERT - if set to TRUE, will verify the upstream server's TLS certificate is valid and signed by the CA, see Verifying Upstream Server.
  • USE_UPSTREAM_CLIENT_CERT - if set to TRUE, will use the set of upstream client certs when connecting upstream, see Upstream Client Certs.
  • ERROR_REDIRECT_CODES - Can override when Nginx will redirect requests to its own error page. Defaults to "500 501 502 503 504". To support a new code, say 505, an error page must be provided at /usr/local/openresty/nginx/html/505.shtml, see Useful File Locations.
  • ADD_NGINX_LOCATION_CFG - Arbitrary extra NGINX configuration to be added to the location context, see Arbitrary Config.
  • PORT_IN_HOST_HEADER - If FALSE will remove the port from the http Host header.
  • BASIC_AUTH - Define a path for username and password file (in username:password format), this will turn the file into a .htpasswd file.
  • REQS_PER_MIN_PER_IP - Will limit requests based on IP e.g. set to 60 to allow one request per second.
  • CONCURRENT_CONNS_PER_IP - Will limit concurrent connections based on IP e.g. set to 10 to allow max of 10 connections per browser or proxy!
  • REQS_PER_PAGE - Will limit requests to 'bursts' of x requests at a time before terminating (will default to 20)
  • DENY_COUNTRY_ON - Set to TRUE to deny access to countries not listed in ALLOW_COUNTRY_CSV with 403 status for a location (set location for 403 with ADD_NGINX_LOCATION_CFG).
  • VERBOSE_ERROR_PAGES - Set to TRUE to display debug info in 418 error pages.

Single set Variables

Note the following variables can only be set once:

  • ADD_NGINX_SERVER_CFG - Arbitrary extra NGINX configuration to be added to the server context, see Arbitrary Config
  • ADD_NGINX_HTTP_CFG - Arbitrary extra NGINX configuration to be added to the http context, see Arbitrary Config
  • AWS_REGION - Sets the AWS region this container is running in. Used to construct urls from which to download resources from. Defaults to 'eu-west-1' if not set.
  • LOCATIONS_CSV - Set to a list of locations that are to be independently proxied, see the example Using Multiple Locations. Note, if this isn't set, / will be used as the default location.
  • LOAD_BALANCER_CIDR - Set to preserve client IP addresses. Important, to enable, see Preserve Client IP.
  • NAME_RESOLVER - Can override the default DNS server used to re-resolve the backend proxy (based on TTL). The Default DNS Server is the first entry in the resolve.conf file in the container and is normally correct and managed by Docker or Kubernetes.
  • CLIENT_MAX_BODY_SIZE - Can set a larger upload than Nginx defaults in MB.
  • HTTPS_REDIRECT_PORT - Only required for http to https redirect and only when a non-standard https port is in use. This is useful when testing or for development instances or when a load-balancer mandates a non-standard port.
  • LOG_FORMAT_NAME - Can be set to text or json (default).
  • NO_LOGGING_URL_PARAMS - Can be set to TRUE if you don't want to log url params. Default is empty which means URL params are logged
  • NO_LOGGING_BODY - Defaults to true TRUE. Set otherwise and nginx should log the request_body.
  • NO_LOGGING_RESPONSE - Defaults to true TRUE. Set otherwise and nginx should log the response_body
  • SERVER_CERT - Can override where to find the server's SSL cert.
  • SERVER_KEY - Can override where to find the server's SSL key.
  • SSL_CIPHERS - Change the SSL ciphers support default only AES256+EECDH:AES256+EDH:!aNULL
  • SSL_PROTOCOLS - Change the SSL protocols supported default only TLSv1.2
  • HTTP_LISTEN_PORT - Change the default inside the container from 10080.
  • HTTPS_LISTEN_PORT - Change the default inside the container from 10443.
  • INTERNAL_LISTEN_PORT - Change the default inside the container from 10418. Note: This is used for internal processing and is not available externally.
  • HTTPS_REDIRECT - Toggle whether or not we force redirects to HTTPS. Defaults to true.
  • ALLOW_COUNTRY_CSV - List of country codes to allow.
  • STATSD_METRICS_ENABLED - Toggle if metrics are logged to statsd (defaults to true)
  • STATSD_SERVER - Server to send statsd metrics to, defaults to 127.0.0.1
  • DISABLE_SYSDIG_METRICS - Set to any non-empty string to disable support for Sysdig's metric collection

Ports

This container exposes

  • 10080 - HTTP
  • 10443 - HTTPS

N.B. see HTTP(S)_LISTEN_PORT above

Useful File Locations

  • nginx.conf is stored at /usr/local/openresty/nginx/conf/nginx.conf
  • /etc/keys/crt & /etc/keys/key - A certificate can be mounted here to make OpenResty use it. However a self signed one is provided if they have not been mounted.
  • /etc/keys/client-ca If a client CA is mounted here, it will be loaded and configured. See CLIENT_CERT_REQUIRED above in Environment Variables.
  • /etc/keys/upstream-server-ca A CA public cert must be mounted here when verifying the upstream server's certificate is required. See VERIFY_SERVER_CERT above in Environment Variables.
  • /etc/keys/upstream-client-crt A public client cert must be mounted here when when the upstream server requires client cert authentication. See USE_UPSTREAM_CLIENT_CERT above in Environment Variables.
  • /etc/keys/upstream-client-key A private client key must be mounted here when when the upstream server requires client cert authentication. See USE_UPSTREAM_CLIENT_CERT above in Environment Variables.
  • /usr/local/openresty/naxsi/*.conf - Naxsi rules location in default nginx.conf.
  • /usr/local/openresty/nginx/html/$CODE.shtml - HTML (with SSI support) displayed when a the status code $CODE is encountered upstream and the proxy is configured to intercept. See ERROR_REDIRECT_CODES to change this.
  • /usr/local/openresty/nginx/html/418-request-denied.shtml - HTML (with SSI support) displayed when NAXSI blocks a request.

Examples

Self signed SSL Certificate

docker run -e 'PROXY_SERVICE_HOST=http://stackexchange.com' \
           -e 'PROXY_SERVICE_PORT=80' \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

Custom SSL Certificate

docker run -e 'PROXY_SERVICE_HOST=http://stackexchange.com' \
           -e 'PROXY_SERVICE_PORT=80' \
           -p 8443:443 \
           -v /path/to/key:/etc/keys/key:ro \
           -v /path/to/crt:/etc/keys/crt:ro \
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

Preserve Client IP

This proxy supports Proxy Protocol.

To use this feature you will need:

  • To enable proxy protocol on your load balancer. For AWS, see Enabling Proxy Protocol for AWS.
  • Find the private address range of your load balancer. For AWS, this could be any address in the destination network. E.g. if you have three compute subnets defined as 10.50.0.0/24, 10.50.1.0/24 and 10.50.2.0/24, then a suitable range would be 10.50.0.0/22 see CIDR Calculator.
docker run -e 'PROXY_SERVICE_HOST=http://stackexchange.com' \
           -e 'PROXY_SERVICE_PORT=80' \
           -e 'LOAD_BALANCER_CIDR=10.50.0.0/22' \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

Extra NAXSI Rules from Environment

The example below allows large documents to be POSTED to the /documents/uploads and /documents/other_uploads locations. See Whitelist NAXSI rules for more examples.

docker run -e 'PROXY_SERVICE_HOST=http://myapp.svc.cluster.local' \
           -e 'PROXY_SERVICE_PORT=8080' \
           -e 'EXTRA_NAXSI_RULES=BasicRule wl:2 "mz:$URL:/documents/uploads|BODY";
               BasicRule wl:2 "mz:$URL:/documents/other_uploads|BODY";' \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

Using Multiple Locations

When the LOCATIONS_CSV option is set, multiple locations can be proxied. The settings for each proxy location can be controlled with the use of any Multi-location Variables by suffixing the variable name with both a number, and the '_' character, as listed in the LOCATIONS_CSV variable.

Two servers

The example below configures a simple proxy with two locations '/' (location 1) and '/api' (location 2):

docker run -e 'PROXY_SERVICE_HOST_1=http://stackexchange.com' \
           -e 'PROXY_SERVICE_PORT_1=80' \
           -e 'PROXY_SERVICE_HOST_2=https://api.svc.cluster.local' \
           -e 'PROXY_SERVICE_PORT_2=8888' \
           -e 'LOCATIONS_CSV=/,/api' \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

For more detail, see the generated config.

One Server, Multiple locations

The example below will proxy the same address for two locations but will disable the UUID (nginxId) parameter for the /about location only.

See the generated config for below:

docker run -e 'PROXY_SERVICE_HOST=http://stackexchange.com' \
           -e 'PROXY_SERVICE_PORT=80' \
           -e 'LOCATIONS_CSV=/,/about' \
           -e 'ENABLE_UUID_PARAM_2=FALSE' \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

Client Certs

If a client CA certificate is mounted, the proxy will be configured to load it. If a client has the cert, the client CN will be set in the X-Username header and logged.

docker run -e 'PROXY_SERVICE_HOST=http://stackexchange.com' \
           -e 'PROXY_SERVICE_PORT=80' \
           -v "${PWD}/client_certs/ca.crt:/etc/keys/client-ca" \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

The following example will specifically deny access to clients without a cert:

docker run -e 'PROXY_SERVICE_HOST=http://serverfault.com' \
           -e 'PROXY_SERVICE_PORT=80' \
           -e 'LOCATIONS_CSV=/,/about' \
           -e 'CLIENT_CERT_REQUIRED_2=TRUE' \
           -v "${PWD}/client_certs/ca.crt:/etc/keys/client-ca" \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

See ./client_certs for scripts that can be used to generate a CA and client certs.

Upstream Client Certs

If the environment variable USE_UPSTREAM_CLIENT_CERT is set to TRUE then the client certs at /etc/keys/upstream-client-crt and /etc/keys/upstream-client-key will be used to authenticate with the upstream HTTPS service.

docker run -e 'PROXY_SERVICE_HOST=https://stackexchange.com' \
           -e 'PROXY_SERVICE_PORT=443' \
           -e 'USE_UPSTREAM_CLIENT_CERT=TRUE' \
           -v "/path/to/client-public.crt:/etc/keys/upstream-client-crt" \
           -v "/path/to/client-private.key:/etc/keys/upstream-client-key" \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v2.1.0

Verifying Upstream Server

If the environment variable VERIFY_SERVER_CERT is set to TRUE then the upstream server's certificate will be validated against the CA public cert at /etc/keys/upstream-server-ca.

docker run -e 'PROXY_SERVICE_HOST=https://stackexchange.com' \
           -e 'PROXY_SERVICE_PORT=443' \
           -e 'VERIFY_SERVER_CERT=TRUE' \
           -v "/path/to/ca.crt:/etc/keys/upstream-server-ca" \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v2.1.0

Arbitrary Config

The example below will return "ping ok" for the URL /ping.

docker run -e 'PROXY_SERVICE_HOST=http://stackexchange.com' \
           -e 'PROXY_SERVICE_PORT=80' \
           -e 'ADD_NGINX_LOCATION_CFG=if ($uri = /proxy-ping) return 200 "ping ok";' \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

The example below will return "404" for the URL /notfound.

docker run -e 'PROXY_SERVICE_HOST=http://stackexchange.com' \
           -e 'PROXY_SERVICE_PORT=80' \
           -e 'ADD_NGINX_SERVER_CFG=location /notfound { return 404; };' \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

The example below enables proxy_cache_path directive. Allows you to define where cached files are stored.

docker run -e 'PROXY_SERVICE_HOST=http://stackexchange.com' \
           -e 'PROXY_SERVICE_PORT=80' \
           -e 'ADD_NGINX_HTTP_CFG=proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=static:10m;' \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

Basic Auth

To add basic auth to your server you need to define the username and password by mounting a file and defining that file in the BASIC_AUTH variable, then add the location config to you config.

docker run -e 'PROXY_SERVICE_HOST=http://stackexchange.com' \
           -e 'PROXY_SERVICE_PORT=80' \
           -e 'ADD_NGINX_LOCATION_CFG='auth_basic "Restricted"; auth_basic_user_file /etc/secrets/.htpasswd;' \
           -e BASIC_AUTH='/etc/secrets/basic-auth'
           -p 8443:443 \
           -v ~/Documents:/etc/secrets/
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

The basic auth file will look like this.

admin:testing
username:password
Basic Auth on mutliple Locations

If you're using multiple locations then we need to define the location that basic_auth will be set in relation to the LOCATIONS_CSV

docker run -e 'PROXY_SERVICE_HOST=http://serverfault.com' \
           -e 'PROXY_SERVICE_PORT=80' \
           -e 'LOCATIONS_CSV=/,/about' \
           -e 'CLIENT_CERT_REQUIRED_2=TRUE' \
           -e BASIC_AUTH_2=/etc/secrets/basic-auth \
           -v "${PWD}/client_certs/ca.crt:/etc/keys/client-ca" \
           -p 8443:443 \
           quay.io/ukhomeofficedigital/nginx-proxy:v1.0.0

this will setup basic-auth for the the /about location or simply swap the 2 for a 1 to setup basic auth for the root location.

Built With

  • OpenResty - OpenResty (aka. ngx_openresty) is a full-fledged web application server by bundling the standard Nginx core, lots of 3rd-party Nginx modules, as well as most of their external dependencies.
  • Nginx - The proxy server core software.
  • ngx_lua - Embed the power of Lua into Nginx
  • Naxsi - NAXSI is an open-source, high performance, low rules maintenance WAF for NGINX
  • GeoLite data This product includes GeoLite data created by MaxMind.

Find Us

Contributing

Feel free to submit pull requests and issues. If it's a particularly large PR, you may wish to discuss it in an issue first.

Please note that this project is released with a Contributor Code of Conduct. By participating in this project you agree to abide by its terms.

Versioning

We use SemVer for the version tags available See the tags on this repository.

Authors

See also the list of contributors who participated in this project.

License

This project is licensed under the MIT License - see the LICENSE.md file for details