Skip to content

Commit

Permalink
Add Authentication Feature + updates/improvements
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielDent committed Aug 12, 2018
1 parent 982f68e commit f5f378e
Show file tree
Hide file tree
Showing 7 changed files with 83 additions and 15 deletions.
11 changes: 7 additions & 4 deletions Dockerfile
Expand Up @@ -8,7 +8,7 @@ ENV CLOUDFLARE_V6_SHA256 e7d84e6f9f8668279312a4ed836ce69cab1750d6745062c7e73d953

RUN DEBIAN_FRONTEND=noninteractive apt-get update -q \
&& DEBIAN_FRONTEND=noninteractive apt-get dist-upgrade -y \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends wget curl certbot \
&& DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends wget curl certbot pwgen \
&& echo "---> INSTALLING s6-overlay" \
&& wget https://github.com/just-containers/s6-overlay/releases/download/v1.17.0.0/s6-overlay-amd64.tar.gz \
&& echo $S6_OVERLAY_SHA256 s6-overlay-amd64.tar.gz | sha256sum -c \
Expand All @@ -27,18 +27,21 @@ RUN DEBIAN_FRONTEND=noninteractive apt-get update -q \
&& wget https://www.cloudflare.com/ips-v6 \
&& echo $CLOUDFLARE_V6_SHA256 ips-v6 | sha256sum -c \
&& cat ips-v6 | sed -e 's/^/set_real_ip_from /' >> /etc/nginx/cloudflare.conf \
&& echo "real_ip_header CF-Connecting-IP;" >> /etc/nginx/cloudflare.conf \
&& echo "real_ip_header X-Forwarded-For;" >> /etc/nginx/cloudflare.conf \
&& echo "real_ip_recursive on;" >> /etc/nginx/cloudflare.conf \
&& rm ips-v6 ips-v4 \
&& echo "---> Creating directories" \
&& mkdir -p /etc/services.d/nginx /etc/services.d/certbot \
&& echo "---> Cleaning up" \
&& DEBIAN_FRONTEND=noninteractive apt-get remove -y wget \
&& rm -Rf /var/lib/apt /var/cache/apt
&& rm -Rf /var/lib/apt /var/cache/apt \
&& touch /etc/nginx/auth_part1.conf /etc/nginx/auth_part2.conf /tmp/htpasswd

COPY services.d/nginx/* /etc/services.d/nginx/
COPY services.d/certbot/* /etc/services.d/certbot/
COPY nginx.conf /etc/nginx/
COPY nginx.conf security_headers.conf /etc/nginx/
COPY proxy.conf /etc/nginx/conf.d/default.conf
COPY auth_part*.conf /root/
COPY dhparams.pem /etc/nginx/
COPY temp-setup-cert.pem /etc/nginx/temp-server-cert.pem
COPY temp-setup-key.pem /etc/nginx/temp-server-key.pem
Expand Down
28 changes: 21 additions & 7 deletions README.md
Expand Up @@ -16,11 +16,7 @@ Prior versions of this image used simp_le. It has been changed to use certbot du

## WARNING

This image's default configuration includes a String-Transport-Security header with expiry set to 18 weeks (~ 4 months). Visitors' browsers will cache this header for 6 months and will refuse to connect except over SSL.

Eventually, you may wish to:
* Increase the header's expiration time.
* Have your domain included in browser [HSTS Preload](https://hstspreload.appspot.com/) lists.
This image's default configuration includes a `Strict-Transport-Security` header with expiry set to 1 year. Visitors' browsers will cache this header and will refuse to connect except over SSL. Eventually, you may wish to have your domain included in browser [HSTS Preload](https://hstspreload.appspot.com/) lists.

## Example Use (via docker-compose)

Expand All @@ -41,6 +37,24 @@ Create a docker-compose.yml file as follows:

Then simply `docker-compose up`.

## Optional: Enable Simple Authentication

If the `DO_AUTH` environment variable is set to `required`, the proxy implements a simple authentication system.

A user meeting any of these three criteria will be allowed access to the proxied service:

* Users coming from an IP or CIDR range listed in the space-separated `WHITELIST_IPS` variable.
* Users presenting a cookie named `magic_ssl_proxy_auth` set to the value of the `COOKIE_VALUE` variable.
* Users providing HTTP Basic Authentication credentials, username `admin` with a password matching the `PROXY_PASSWORD` variable.

A user that correctly authenticates with HTTP Basic Authentication will have their `magic_ssl_proxy_auth` cookie set so that they are not required to re-authenticate.

By default, no IPs are whitelisted. When authentication is enabled, the `COOKIE_VALUE` and `PROXY_PASSWORD` values will be chosen randomly if they are not provided. If randomly chosen, the randomly chosen values will be output to the console during container startup. The `PROXY_PASSWORD` value will also be available in the `/tmp/proxy_password` file within the container, while the chosen `COOKIE_VALUE` will be available in the `/etc/nginx/auth_part1.conf` file.

When configuring IP based authentication, be mindful that reverse proxies and your Docker configuration may result in an apparent source IP that does not match the client's true IP address. Additional instances of the `set_real_ip_from` directive can be provided with the IP addresses of your trusted HTTP proxies. By default, Cloudflare IP addresses will be trusted to provide an `X-Forwarded-For` header. Directly exposing this image to the internet (e.g. via the `ports` directive as in the above example) will remove one source of potential problems with IP based authentication.

Nginx limits the length of your `COOKIE_VALUE` for performance reasons. If your `COOKIE_VALUE` is too long, nginx will refuse to start and will display errors relating to `server_names_hash_bucket_size` and `server_names_hash_max_size`. If you have difficulties, try decreasing the legnth of your cookie or add directives to your Nginx configuration to increase the maximum size.

## Certificate Data

A `/etc/letsencrypt` volume is used to maintain certificate data. An `account_key.json` file holds the key to your Let's Encrypt account - which provides a convenient way to revoke a certificate.
Expand All @@ -60,7 +74,7 @@ Reasonable defaults have been chosen for SSL cipher suites using [Mozilla's Reco

## Security Headers

Reasonable defaults have been chosen with an eye towards a configuration which is more secure by default. See https://www.owasp.org/index.php/List_of_useful_HTTP_headers for more information on the headers used.
Reasonable defaults have been chosen with an eye towards a configuration which is more secure by default. See https://www.owasp.org/index.php/List_of_useful_HTTP_headers for more information on the headers used. These headers can be disabled by setting the `SECURITY_HEADERS` variable to `skip`. If your upstream server is itself sending these headers, setting the `SECURITY_HEADERS` variable will avoid the presence of multiple instances of these headers in responses.

## Dependencies

Expand All @@ -76,7 +90,7 @@ Please file a pull request or create a new issue for problems or potential impro

# License

Copyright 2015 [Daniel Dent](https://www.danieldent.com/).
Copyright 2015-2018 [Daniel Dent](https://www.danieldent.com/).

Licensed under the Apache License, Version 2.0 (the "License");
you may not use these files except in compliance with the License.
Expand Down
16 changes: 16 additions & 0 deletions auth_part1.conf
@@ -0,0 +1,16 @@
map $cookie_magic_ssl_proxy_auth $checkifcookieok {
"${COOKIE_VALUE}" "yes";
default "no";
}

geo $checkifipok {
${IPR_EXPANDED}
default "no";
}

map $checkifcookieok$checkifipok $do_proxy_auth {
"yesyes" "off";
"yesno" "off";
"noyes" "off";
default "Authentication Required";
}
3 changes: 3 additions & 0 deletions auth_part2.conf
@@ -0,0 +1,3 @@
auth_basic $do_proxy_auth;
auth_basic_user_file /tmp/htpasswd;
add_header Set-Cookie "magic_ssl_proxy_auth=${COOKIE_VALUE};max-age=3153600000;Secure;HttpOnly;path=/";
9 changes: 5 additions & 4 deletions proxy.conf
Expand Up @@ -2,6 +2,8 @@ upstream origin {
server ${UPSTREAM:-127.0.0.1};
}

include /etc/nginx/auth_part1.conf;

server {
listen 443 ssl http2;
server_name ${SERVERNAME:-example.com};
Expand All @@ -24,10 +26,8 @@ server {
ssl_dhparam /etc/nginx/dhparams.pem;

# https://www.owasp.org/index.php/List_of_useful_HTTP_headers
add_header Strict-Transport-Security "max-age=10886400";
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
add_header Strict-Transport-Security "max-age=31536000";
include "/etc/nginx/security_headers.conf";

location /.well-known/acme-challenge {
default_type "text/plain";
Expand All @@ -36,6 +36,7 @@ server {
}

location / {
include /etc/nginx/auth_part2.conf;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Port $server_port;
Expand Down
3 changes: 3 additions & 0 deletions security_headers.conf
@@ -0,0 +1,3 @@
add_header X-Content-Type-Options "nosniff";
add_header X-Frame-Options "SAMEORIGIN";
add_header X-XSS-Protection "1; mode=block";
28 changes: 28 additions & 0 deletions services.d/nginx/run
@@ -1,6 +1,34 @@
#!/usr/bin/with-contenv bash
/usr/local/bin/ep -v /etc/nginx/conf.d/*

if [ "$DO_AUTH" == "required" ]; then
cp /root/auth* /etc/nginx

# Set random cookie/password values if not provided
if [ "x$COOKIE_VALUE" == "x" ]; then
COOKIE_VALUE=$(pwgen -s -B 25)
echo Cookie Value: $COOKIE_VALUE
fi
if [ "x$PROXY_PASSWORD" == "x" ]; then
PROXY_PASSWORD=$(pwgen -s -B 25)
echo Proxy Password: $PROXY_PASSWORD
echo Proxy Password: $PROXY_PASSWORD > /tmp/proxy_password
fi
echo -n "admin:" > /tmp/htpasswd
echo $PROXY_PASSWORD | openssl passwd -apr1 -stdin >> /tmp/htpasswd

IPR_EXPANDED=""
for ip in $WHITELIST_IPS; do
IPR_EXPANDED="$IPR_EXPANDED $ip \"yes\"; "
done

COOKIE_VALUE="$COOKIE_VALUE" IPR_EXPANDED="$IPR_EXPANDED" /usr/local/bin/ep -v /etc/nginx/auth_part*.conf
fi

if [ "$SECURITY_HEADERS" == "skip" ]; then
echo "" > /etc/nginx/security_headers.conf
fi

if [ ! -e /etc/letsencrypt/fullchain-copy.pem ]; then
cp /etc/nginx/temp-server-cert.pem /etc/letsencrypt/fullchain-copy.pem
fi
Expand Down

0 comments on commit f5f378e

Please sign in to comment.