July 31, 2018

SSL Termination

^ Ad space to help offset hosting costs :D

We'll set up SSL-termination on the load balancer. In this setup, the load balancer decrypts the SSL connection and sends an http request on port 80 over the local private network to the application servers.

SSL Termination is a common setup, however there are setups that keep the connection encrypted all the way to the application servers.

We'll get an SLL certificate for free using Lets Encrypt.

So, first, we'll install Lets Encrypt!

Creating a certificiate here will work because we don't disallow access to directories that start with a period, but if you do like on many standard setups, see the video on using Lets Encrypt for more details.

cd /opt
sudo git clone https://github.com/certbot/certbot
cd certbot
./certbot-auto -h

OK, so, certbot is installed but if we have it attempt to connect to our server, Nginx will attempt to proxy the authentication request to our application servers, but we don't want that!

So, let's setup Nginx to work with Lets Encrypt requests:

upstream app {
    server 172.31.9.200:80;
    server 172.31.0.30:80;
}

server {
    listen 80 default_server;

    server_name lb.serversforhackers.com;    

    charset utf-8;

    # Requests to /.well-known should look for local files
    location /.well-known {
        root /var/www/html;
        try_files $uri $uri/ =404;
    }

    # All other requests get load-balanced
    location / {
        include proxy_params;
        proxy_pass http://app;
        proxy_redirect off;

        # Handle Web Socket connections
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

The details of what's going on here is explained more in the Let's Encrypt video! This includes how to have the certificate automatically update.

We need to test this config and have Nginx suck it in:

sudo nginx -t
sudo service nginx reload

Now we're ready to install our certificate!

cd /opt/certbot

# Let's create the cert
sudo ./certbot-auto certonly --webroot -w /var/www/html \
    -d lb.serversforhackers.com \
    --non-interactive --agree-tos --email admin@example.com

Finally, we can update our Nginx configuration to use the SSL (this is a bit different than the video, which doesn't cover ensuring Let's Encrypt continues to work after the SSL is installed):

upstream app {
    server IPHERE:80;
    server IPHERE:80;
}

server {
    listen 80 default_server;
    server_name lb.serversforhackers.com;

    # Requests to /.well-known should look for local files
    location /.well-known {
        root /var/www/html;
        try_files $uri $uri/ =404;
    }

    # All other requests get load-balanced
    location / {
        return 301 https://$server_name$request_uri;
    }
}

server {
    listen 443 ssl default_server;

    server_name lb.serversforhackers.com;

    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_prefer_server_ciphers  on;
    ssl_session_cache          shared:SSL:10m;
    ssl_session_timeout        24h;
    keepalive_timeout          300s;

    ssl_certificate      /etc/letsencrypt/live/lb.serversforhackers.com/fullchain.pem;
    ssl_certificate_key  /etc/letsencrypt/live/lb.serversforhackers.com/privkey.pem;

    charset utf-8;

    location / {
        include proxy_params;
        proxy_pass http://app;
        proxy_redirect off;

        # Handle Web Socket connections
        proxy_http_version 1.1;
        proxy_set_header Upgrade $http_upgrade;
        proxy_set_header Connection "upgrade";
    }
}

In this setup, all requests to port 80 are redirected to port 443 to use the SSL certificate. If a request on port 80 is sent to /.well-known, it should function.

Finally we can test that out and reload Nginx:

sudo nginx -t
sudo service nginx reload

We should then be able to access our server over SSL using https://lb.serversforhackers.com.

All Topics