How to Configure Apache httpd to Provide TLS-encrypted Virtual Hosts
Transport Layer Security(TLS)
Transport Layer Security (TLS) is a method for encrypting network communications. TLS is the successor to Secure Sockets Layer (SSL). TLS allows a client to verify the identity of the server and, optionally, allows the server to verify the identity of the client.
TLS is based on the concepts of certificates. A certificate has multiple parts: a public key, server identity, and a signature from a certificate authority. The corresponding private key is never made public. Any data encrypted with the private key can only be decrypted with the public key and vice versa.
During the initial handshake, when setting up the encrypted connection, the client and server agree on a set of encryption ciphers supported by both the server and the client, and they exchange bits of random data. The client uses this random data to generate a session key, a key that will be used for much faster symmetric encryption, where the same key is used for both encryption and decryption. To make sure that this key is not compromised, it is sent to the server encrypted with the server’s public key (part of the server certificate).
The following diagram shows a (simplified) version of a TLS handshake.
- The client initiates a connection to the server with a ClientHello message. As part of this message, the client sends a 32-byte random number including a timestamp and a list of encryption protocols and ciphers supported by the client.
- The server responds with a ServerHello message, containing another 32-byte random number with a timestamp, and the encryption protocol and ciphers the client should use. The server also sends the server certificate, which consists of a public key, general server identity information like the FQDN, and a signature from a trusted certificate authority (CA). This certificate can also include the public certificates for all certificate authorities that have signed the certificate, up to a root CA.
- The client verifies the server certificate by checking if the supplied identity information matches, and by verifying all signatures, checking if they are made by a CA trusted by the client. If the certificate verifies, the client creates a session key using the random numbers previously exchanged. The client then encrypts this session key using the public key from the server certificate and sends it to the server using a ClientKeyExchange message.
- The server decrypts the session key, and the client and server both start encrypting and decrypting all data sent over the connection using the session key.
Configuring TLS Certificates
To configure a virtual host with TLS, multiple steps must be completed:
- Obtain a (signed) certificate.
- Install Apache HTTPD extension modules to support TLS.
- Configure a virtual host to use TLS, using the certificates obtained earlier.
Obtaining a Certificate
When obtaining a certificate, there are two options: creating a self-signed certificate (a certificate signed by itself, not an actual CA), or creating a certificate request, and having a reputable CA sign that request so it becomes a certificate.
The crypto-utils package contains a utility called genkey that supports both methods. To create a certificate (signing request) with genkey, run the following command, where ****is the fully qualified domain name clients will use to connect to your server:
# genkey
During the creation, genkey will ask for the desired key size (choose at least 2048 bits), if a signing request should be made (answering no will create a self-signed certificate), whether the private key should be protected with a passphrase and general information about the identity of the server.
After the process has completed, a number of files will be generated:
- /etc/pki/tls/private/.key: This is the private key. The private key should be kept at 0600 or 0400 permissions, and an SELinux context of cert_t. This key file should never be shared with the outside world.
- /etc/pki/tls/certs/.0.csr: This file is only generated if you requested a signing request. This is the file that you send to your CA to get it signed. You never need to send the private key to your CA.
- /etc/pki/tls/certs/.crt: This is the public certificate. This file is only generated when a self-signed certificate is requested. If a signing request was requested and sent to a CA, this is the file that will be returned from the CA. Permissions should be kept at 0644, with an SELinux context of cert_t.
Install Apache HTTPD modules
Apache HTTPD needs an extension module to be installed to activate TLS support. On Red Hat Enterprise Linux 7, you can install this module using the mod_ssl package.
This package will automatically enable httpd for a default virtual host listening on port 443/TCP. This default virtual host is configured in the file /etc/httpd/conf.d/ssl.conf.
Configure a virtual host with TLS
Virtual hosts with TLS are configured in the same way as regular virtual hosts, with some additional parameters. It is possible to use name-based virtual hosting with TLS, but some older browsers are not compatible with this approach.
The following is a simplified version of /etc/httpd/conf.d/ssl.conf:
1. This directive instructs https to listen on port 443/TCP. The second argument (https) is optional, since https is the default protocol for port 443/TCP.
2. If the private key is encrypted with a passphrase, httpd needs a method of requesting a passphrase from a user at the console at startup. This directive specifies what program to execute to retrieve that passphrase.
3. This is the virtual host definition for a catch-all virtual host on port 443/TCP.
4. This is the directive that actually turns on TLS for this virtual host.
5. This directive specifies the list of protocols that httpd is willing to speak with clients. For security, the older, unsafe SSLv3 protocol should also be disabled:
SSLProtocol all -SSLv2 -SSLv3
6. This directive lists what encryption ciphers httpd is willing to use when communicating with clients. The selection of ciphers can have big impacts on both performance and security.
7. This directive instructs httpd where it can read the certificate for this virtual host.
8. This directive instructs httpd where it can read the private key for this virtual host. httpd reads all private keys before privileges are dropped, so file permissions on the private key can remain locked down.
If a certificate signed by a CA is used, and the certificate itself does not have copies of all the CA certificates used in signing, up to a root CA, embedded in it, the server will also need to provide a certificate chain, a copy of all CA certificates used in the signing process concatenated together. The SSLCertificateChainFile directive is used to identify such a file
When defining a new TLS-encrypted virtual host, it is not needed to copy the entire contents of ssl.conf. Only a <VirtualHost> block with the SSLEngine On directive, and configuration for certificates, is strictly needed. The following is an example of a name-based TLS virtual host:
<VirtualHost *:443>
ServerName demo.example.com
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/demo.example.com.crt
SSLCertificateKeyFile /etc/pki/tls/private/demo.example.com.key
SSLCertificateChainFile /etc/pki/tls/certs/example-ca.crt
<VirtualHost>
This example misses some important directives such as DocumentRoot; these will be inherited from the main configuration.
Configuring Forward Secrecy
As mentioned earlier, the client and the server select the encryption cipher to be used to secure the TLS connection based on a negotiation during the initial handshake. Both the client and the server must find a cipher that both sides of the communication support.
If a weaker encryption cipher has been used, and the private key of the server has been compromised—for example, after a server break-in or due to a bug in the cryptography code—an attacker could possibly decrypt a recorded session.
One way to protect against these types of attacks is to use ciphers that ensure forward secrecy. Sessions encrypted using ciphers with this characteristic can not be decrypted if the private key is compromised at some later date. Forward secrecy can be established by carefully tuning the allowed ciphers in the SSLCipherSuite directive, to preferentially pick ciphers that support forward secrecy which both the server and client can use.
The following is an example that, at the date of publication, was considered a very good set of ciphers to allow. This list prioritizes ciphers that perform the initial session key exchange using elliptic curve Diffie-Hellman (EECDH) algorithms which support forward secrecy before falling back to less secure algorithms. Using Diffie-Hellman, the actual session key is never transmitted, but rather calculated by both sides.
SSLCipherSuite "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH
+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH EDH+aRSA DES-CBC3-SHA !
RC4 !aNULL !eNULL !LOW !DES !MD5 !EXP !PSK !SRP !DSS"
SSLHonorCipherOrder On
The example also disables RC4, due to its increasing vulnerability. This has the somewhat negative side effect of removing server-side BEAST (CVE-2011-3389) mitigation for very old web clients that only support TLSv1.0 and earlier. DES-CBC3-SHA is used in place of RC4 as a “last resort” cipher for support of old Internet Explorer 8 / Microsoft Windows XP clients. (In addition, to protect against other issues, the insecure SSLv3 and SSLv2 protocols should also be disabled on the web server, as previously discussed in this section.)
The SSLHonorCipherOrder On directive instructs httpd to preferentially select ciphers based on the order of the SSLCipherSuite list, regardless of the order preferred by the client.
NOTE: Security research is an always ongoing arms race. It is recommended that administrators re-evaluate their selected ciphers on a regular basis.
Configuring HTTP Strict Transport Security (HSTS)
A common misconfiguration, and one that will result in warnings in most modern browsers, is having a web page that is served out over https include resources served out over clear-text http. To protect against this type of misconfiguration, add the following line inside a <VirtualHost> block that has TLS enabled:
Header always set Strict-Transport-Security "max-age=15768000"
Sending this extra header informs clients that they are not allowed to fetch any resources for this page that are not served using TLS. Another possible issue comes from clients connecting over http to a resource they should have been using https for. Simply not serving any content over http would alleviate this issue, but a more subtle approach is to automatically redirect clients connecting over http to the same resource using https.
Simply not serving any content over http would alleviate this issue, but a more subtle approach is to automatically redirect clients connecting over http to the same resource using https. To set up these redirects, configure a http virtual host for the same ServerName and ServerAlias as the TLS protected virtual host (a catch-all virtual host can be used), and add the following lines inside the <VirtualHost *:80> block:
RewriteEngine on
RewriteRule ^(/.*)$ https://%{HTTP_HOST}$1 [redirect=301]
The RewriteEngine on directive turns on the URL rewrite module for this virtual host, and the RewriteRule matches any resource (^(/.*)$) and redirects it using a http Moved Permanently message ([redirect=301]) to the same resource served out over https. The** %{HTTP_HOST}** variable uses the hostname that was requested by the client, while the $1 part is a back-refereference to whatever was matched between the first set of parentheses in the regular expression.