SSL Config
Introduction
There will be two setups for SSL/TLS one for the seaoffate.local and one for seaoffate.net. all of the Webservers will have a similar setup
External DNS
The external DNS and SSL is mainly done by Cloudflare. Cloudflare have an option on the control panel called "proxy" and if that is selected for any DNS name Cloudflare will handle the connection between the client browser and Cloudflare wit one of their SSL certs. Using their proxy means that any client will never get to see my internet facing IP address if they are using port 80 or 443. The connection between my webservers and Cloudflare is not so good as there is another setting buried a bit deeper in the control panel that determines how the origin hosts (my webserver/s) handle the encryption to Cloudflare. There are five possible connection methods and the client bowser has no knowledge of how this is set.
- Off meaning that there is no encryption at all and the client browser will show a warning.
- Flexible meaning that the connection from origin to Cloudflare will be optional HTTPS/HTTP but from Cloudflare to client browser will be HTTPS so client gets no warning.
- Full means that there is a SSL cert between Cloudflare and origin but it is not required to a publicly trusted one, eg a self cert is ok. If it is a self cert the main danger is that there coul;d be a man in the middle attack between origin and Cloudflare and it would never be known.
- Full Strict means that a Cloudflare origin cert or a publicly trusted cert is in use. Cloudflare generate a self cert and give it to the origin so Cloudflare can trust it and the origin can trust it but not anyone else, this is not as bad as it sounds because the cert only connects the origin to Cloudflare so as long as those two trust the cert all is well. Further to that the connection is encrypted all of the way from the browser to origin and there is no possibility of a man in the middle because the certs wouldn't match.
- Strict (SSL-Only Origin Pull) this mode forces a https connection in the origin. The cert can be either a Cloudflare Origin crt or SSL cert from a public CA like Letsencript. if the connection is not encrypted fully from end to end Cloudflare will reject the connection and issue a 526 warning. Could be a bit risky if Letsencrypt do the 7 day certs thing as it will be easy for a cert to expire and a badly configured acme cert tool doesn't update the certs in a timely manner.
It is fairly easy to get a Cloudflare origin Cert from their control panel so there is not much excuse to do flexible which is in essence lying to the clients.
Other Options
The Cloudflare proxied connection are very nice but they will only accept HTTP/S connections. If a direct connection to a host is needed we must select DNS only on the DNS control panel and if we are going to have PF sense do DDNS client we must remember to switch of the Proxy flag there as well or the first time Pfsense connects to Cloudflare it will make the connection a proxied one I guess the best thing to do with any DNS only domains is to get a public cert or issue a self cert and a permanent redirect to www.seaoffate.net on Rasin the proxy server and in that way anyone that does find a http/s port open will be immediately redirected to the default domain. Having said that it still would be better to get a public cert for it. It may be better to just install Apache and set a basic webpage and do a permanent redirect for those servers that are not expecting to be webservers. that way any hostile actor will still have to breach an Apache webserver.
Local DNS Names SSL Setup
We will do the SSL/TLS for the .local access first mainly because because it is better to see it working on a local level and if we did the global first there is a good chance we would never get a around to doing the local, in which case some of the access will be completely without any cert. It is part of the learning curve to generate SSL certificates. While it would be fairly easier to do a self cert for the local access it is better to experience the whole process from start to finish to get a complete understanding of how it is done and the failures that inevitably appear.
The Process Flow
The process flow is to get the Certificates generated on the webserver host, get it signed by the Certificate Authority then apply it to the webserver, once that is done the SSL config needs to be applied to the host, after that it we would make a config to the reverse proxy. The reverse proxy will have it's own certificate to use for all of the hosts that it is forwarding to and once the cert is applied it will not need to have it applied again, we would just refer to it in the individual SSL config.
Generating SSL Certificates
The first thing to do is to generate a private key, this is done on the webserver with the command
sudo openssl genrsa -out /etc/ssl/private/strawberry.seaoffate.local.key 2048
The out directive will specify where the private key will stored, in this case the default location is used. The .key does need to be stored privately as it is the key that will be used to encrypt or decrypt the internet traffic and is the core item in the security of the Internet. Once the private key has been generated access should be restricted to the root user only so we need to do the chmod/chown commanda s follows
sudo chmod 600 /etc/ssl/private/strawberry.seaoffate.local.key sudo chown root:root /etc/ssl/private/strawberry.seaoffate.local.key
Now that we have the private key we can look at getting the public certificate. To get the certificate with any sort of trust it has to be signed by a Certificate Authority. We have a personal CA available on Alpine, it will only be trusted by us and not the rest of the world as it is a personal CA. To have a cert signed we must generate a Certificate Signing Request and present it to the CA the command to generate a CSR is
sudo openssl req -new -key /etc/ssl/private/strawberry.seaoffate.local.key -out /etc/ssl/certs/strawberry.seaoffate.local.csr
As this script executes it will ask a numer of questions.
- Country Name (2 letter code) [AU]:GB
- State or Province Name (full name) [Some-State]:Hampshire
- Locality Name (eg, city) []:Basingstoke
- Organization Name (eg, company) [Internet Widgits Pty Ltd]:Sea of Fate
- Organizational Unit Name (eg, section) []: (Your department or unit, if applicable, or leave blank)
- Common Name (e.g. server FQDN or YOUR name) []: strawberry.seaoffate.local (This is crucial, it must match the hostname)
- Email Address []:[email protected]
- A challenge password []: (Leave blank, or add a password, but it is not needed for webserver certificates)
- An optional company name []: (Leave blank, or add an optional company name)
Note that the Common Name is critical The other fields are not so important but should be accurate (don't lie someone may read them), the fields could be left blank (except common name). the challenge password is rarely used for webserver certs and can be left blank.
Note that the command uses the private key that we just generated. The CSR is added to the certs directory it is not secret but it should not be modified so it still need to be stored in a form that has at least 744 on it. As this is a signing request we have to get is to the signing software, the CA, in a secure manner. generally SCP is the best option to transfer a file securely as it uses the same connection as SSH. An example is
scp /etc/ssl/certs/strawberry.seaoffate.local.csr user@alpine:~/easy-rsa/easyrsa3/pki/reqs/
If this doesn't work with the user that is available try copying to /tmp
scp /etc/ssl/certs/strawberry.seaoffate.local.csr user@alpine:/tmp
When the file is copied to Apline we must login to the Alpine host to do the signing. I the CSR file could not be added directly to the reqs directory it should be copied there now.
cp /tmp/strawberry.seaoffate.local.csr ~/easy-rsa/easyrsa3/pki/reqs
Unfortunately, easyrsa need to see CSRs with the extension of .req but the openssl generates them as .csr the solution is to mv the .csr to .req
mv ~/easy-rsa/easyrsa3/pki/reqs/strawberry.seaoffate.local.csr ~/easy-rsa/easyrsa3/pki/reqs/strawberry.seaoffate.local.req
Assuming that the CSR is in the /reqs directory and it has the correct extension we can proceed with the signing. We should be in the ~/easy-rsa/easyrsa3/ directory to run the script
./easyrsa sign-req server strawberry.seaoffate.local
the script will ask to confirm the details that would have been submitted when creating the signing request on the web host and the first answer has to be "yes" or it will not continue. The next question is to supply the passphrase for the script to have access to the CA.key, if it can't be given the request fails. Once the CSR/REQ has been signed the certificate will be created and stored in the issued directory and is ready to be returned to the webserver again using SCP. We could copy the .CRT directly to the /ect/ssl/certs dir on the web host but since we are using Ubuntu we can't because the permissions fail. We should create a dir off of the user's home dir and call it signed we can then SCP
SCP ~/easy-rsa/easyrsa3/pki/issued/strawberry.seaoffate.local.crt [email protected]:~/signed
When that is done swap back to the web host (strawberry) and mv the signed cert to the correct directory
sudo mv signed/strawberry.seaoffate.local.crt /etc/ssl/certs/
We should set the permissions on the cert to be read only and owned by root
sudo chmod 644 /etc/ssl/certs/strawberry.seaoffate.local.crt sudo chown root:root /etc/ssl/certs/strawberry.seaoffate.local.crt
As a final job we can verify that the cert and key match each other
sudo openssl x509 -noout -modulus -in /etc/ssl/certs/strawberry.seaoffate.local.crt | sudo openssl sha256 sudo openssl rsa -noout -modulus -in /etc/ssl/private/strawberry.seaoffate.local.key | sudo openssl sha256
check to make sure that the two hashes are identical, if they are not SSL will not work on the website.
Create Apache SSL Configuration
Now that we have a signed certificate we can proceed to configure Apache to listen & serve SSL/TLS request on port 443. As we have used Strawberry as the example for the cert generation we will continue to use the same host for the configs. First we should cd to the site-available so that the config file we create matches the existing and we get the correct docroot. We should create a config file,
sudo nano /etc/apache2/sites-available/strawberry.seaoffate.local-ssl.conf
and enter the following
<VirtualHost *:443> ServerName strawberry.seaoffate.local DocumentRoot /var/www/strawberry/public_html
SSLEngine on SSLCertificateFile /etc/ssl/certs/strawberry.seaoffate.local.crt SSLCertificateKeyFile /etc/ssl/private/strawberry.seaoffate.local.key
<Directory /var/www/strawberry/public_html/>
AllowOverride All
Require all granted
</Directory>
# Security Headers (Recommended) Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload" Header always set X-Frame-Options "SAMEORIGIN" Header always set X-Content-Type-Options "nosniff" Header always set Referrer-Policy "strict-origin-when-cross-origin"
# SSL Protocol and Cipher Configuration (Recommended) SSLProtocol all -SSLv3 -TLSv1 -TLSv1.1 SSLCipherSuite HIGH:!aNULL:!MD5
ErrorLog ${APACHE_LOG_DIR}/error.log
CustomLog ${APACHE_LOG_DIR}/access.log combined
</VirtualHost>
Save and exit. To enable the SSL site and enable the SSL modules.
sudo a2ensite strawberry.seaoffate.local-ssl.conf sudo a2enmod ssl sudo a2enmod headers
To restart Apache & check for errors
sudo systemctl restart apache2 sudo systemctl status apache2
To test with curl
curl -v https://strawberry.seaoffate.local
We should also look in a browser to be sure that the config works.
Raisin Nginx Reverse Proxy Configuration
Once we have tested the webserver SSL config we should do the same for Raisin, the Reverse Proxy, First of all ssh to raisin and cd to /etc/nginx/sites-available to check what the format is for the existing configs. Create anew config for strawberry
sudo nano strawberry.seaoffate.local.ssl.conf
fill in the following configuration
server {
listen 443 ssl;
server_name strawberry.seaoffate.local;
ssl_certificate /etc/nginx/ssl/raisin.crt; # Path to your SSL certificate on raisin ssl_certificate_key /etc/nginx/ssl/raisin.key; # Path to your SSL key on raisin
ssl_protocols TLSv1.2 TLSv1.3; ssl_ciphers 'HIGH:!aNULL:!MD5'; # !aNULL: This excludes ciphers that use anonymous Diffie-Hellman key exchange !MD5' excludes weak md5 hash
location / {
proxy_pass https://*.*.*.23; # IP of strawberry
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_ssl_verify off; # only needed if strawberry has a self signed cert.
}
}
Save and exit. If this is the first SSL website to be proxy, we will need to create the SSL directory for the certs.
sudo mkdir -p /etc/nginx/ssl
If keys and certs have not been created follow the instructions above. Assuming SSL dir creation is done we should make the site enabled
sudo ln -s /etc/nginx/sites-available/strawberry.seaoffate.local /etc/nginx/sites-enabled/
We can test the config with
sudo nginx -t
If all is well Restart Nginx to apply the changes
sudo systemctl restart nginx sudo systemctl status nginx
We can run a test with curl
curl -v https://strawberry.seaoffate.local
We should also open a browser to see if it can open the website
https://strawberry.seaoffate.local