SSL On Apache With Self Signed Certificates

SSL Certificate Basics

There are 2 essential components of a Secure Socket Layer ( SSL), the private and public key. A SSL Certificate is a form of digital identity, it contains the public key and is signed by a trusted Certificate Authority (CA) that certifies the identity (domain) represented in the certificate. Before a SSL Certificate is issued by a CA, they will go through a series of steps to verify the identity of the company applying. The private key proves ownership of a certificate and should never be shared (more on this in the next section).

Root Certificate Authorities are an alliance of companies that decide who can be trusted and they hold a set of root certificates that are used to sign other certificates. These root certificates are self signed since there is no authority to verify the identity of the root. Browsers ship with a finite list of these trusted root certificates. A Root Certificate Authority can also decide to trust another company to issue certificates, these are called Intermediate Certificates. Intermediate Certificates can sign other certificates in contrast to normal Certificates which cannot.

Self Signed Certificates are in essence certificates that are signed by an unknown and hence untrusted authority. Browsers will explicitly warn the user when connecting securely to a website that is using a Self Signed Certificate.

How does SSL Work

As the diagram shows, the private key does prove ownership of the certificate. Without the private key counterpart of the public key contained in the certificate, the server would not be able to decrypt the Symmetric Encryption Key (SEK) generated by the browser. Subsequently it would not be able to decrypt the HTTP Request that is encrypted with the SEK.

Apache, SSL and Server Name Indication (SNI)

Apache is a popular and widely used web server that can be used to host multiple sites in the form of Virtual Hosts. A name based Virtual Host is a site configuration in Apache that is activated by the name in the Host header of an HTTP Request. Apache will inspect the incoming HTTP request and try to match the Host header to the ServerName or ServerAlias of a particular Virtual Host and subsequently serve a response based on the configuration of that Virtual Host. Below is an example of 2 name based Virtual Hosts. Note that multiple virtual hosts can be configured in a single file or one per file, usually in /etc/apache2/sites-enabled/ depending on the distribution.

SSL configuration is done inside the VirtualHost configuration. The problem with this is that Apache needs to read the Host header of the incoming HTTP Request to determine which VirtualHost to use, but when the request is encrypted the Host header cannot be read until the request is decrypted. Apache will use the first VirtualHost to setup the encryption layer. This might be acceptable if Apache is configured with a wildcard certificate and all the VirtualHosts are within the same domain, but with a configuration like above the SSL limitation will become evident.

Server Name Indication or SNI is an extension to the SSL protocol that overcomes this problem by providing a way for the client (usually a browser) to include the requested Host in the initial message of the SSL handshake. SNI enables Apache to resolve the correct Virtual Host before setting up the encryption layer. SNI only works if the client supports the extension. The SSLStrictSNIVHostCheck directive can be used to force a 403 HTTP Response for clients that do not support SNI. Below is the example adapted to support SSL.

Note that the Common Name is set to the Host name of the site. Wildcard certificates, that support multiple sub domains, can be configured using *.monkey-app-1.local as the Common Name during the openssl step that creates the Certificate Signing Request (CSR).

Now run the Docker Image and mount the volume that contains the secrets. The Docker Container also needs net-aliases to be able to resolve the 2 domain names www.monkey-app-1.local and www.monkey-app-2.local.

The last step is to add the 2 hosts to the local /etc/hosts file so that the browser can resolve the 2 domains. On OSX the domains should point to the IP of the Docker Machine VM (docker-machine ip will show the ip).