Security Can Be A Headache But It's Important
Before we tackle installing our SSL certificate, it must be said that even in FileMaker, SSL certificates can be a headache to deal with. We all talk about the need for security and encryption but the barriers and complexity for the average user works against this goal and we're sure many give up in frustration - which is frustrating to those of us who want to promote and encourage security within the FileMaker community (and beyond).
Security and SSL certificates should be easier to install and update by now, and we hope that we're headed in that direction. That said, if you're struggling with encryption, reach out to the community for help because it is really important. Right then, buckle up, we're in for a heck of a ride...
Let's Encrypt
Yes, we agree, let's encrypt and we're going to do that by using a free Let's Encrypt SSL certificate. This organization, backed by some big players, wants to allow everyone access to encryption on the web and provides SSL certificates at no charge to further their goal. As of the time of writing, their certificates are not officially supported by FileMaker Server but we can only hope that soon they will be.
Although they are free, they do have a short lifespan of just 90 days, so our plan is to first get one for our Keycloak server, then install it and then set it up so it will renew automatically. So, let's encrypt...
Installing Certbot And Obtaining A SSL Certificate
Before we begin, you'll need to have a domain or subdomain set up that is pointing at your server. The details of this fall outside of the scope of this article but if you've done this for FileMaker Server then it's the same principle. Go to your domain registrar, edit the DNS records for your domain name, create a new A record with a value of, say, keycloak, and enter the external IP address of your Keycloak server. Your server should then be accessible at http://keycloak.mydomain.com:8080. Bear in mind you will likely have to open the 8080 firewall port on your router or Security Groups if you're using AWS, and potentially take care of some port forwarding.
Talking of firewall ports, we'll be installing a small utility called Certbot that will handle retrieving and updating our SSL certificate. When requesting the certificate, it needs to verify that the server exists at the address you're requesting the certificate for, and it does this over port 80. We don't want to leave port 80 open all the time, so we'll open it, get our certificate and then close it, but again you may need to add external firewall rules too. Note that there are other possible verification methods and head over to the Let's Encrypt website if you want to explore those.
Moving on, let's get Certbot downloaded. We have a bunch of commands to run through here, so just plug away at them confirming yes as needed, being sure to check for errors:
sudo snap install core
sudo snap refresh core
sudo snap install --classic certbot
sudo ln -s /snap/bin/certbot /usr/bin/certbot
sudo shutdown -r now
Wait for the server to reboot and log back in again. Next, let's open that firewall port:
sudo ufw allow 80/tcp
Now we can request our certificate by running the below, ensuring you update the domain to the one you wish to use. Note the use of the parameter --dry-run allows for testing without consequence. Use this first time round and then remove it to request the certificate for real.
sudo certbot certonly --standalone --preferred-challenges http -d keycloak.mydomain.com --dry-run
You'll be prompted for your email address and to accept the terms of service. If all your firewall settings are right then you should get a message to say the dry run was successful. If it wasn't successful then you'll need to check those firewall settings both on the Linux machine and your external firewall. Assuming your dry run was successful, run the above command again but remove the --dry-run parameter at the end - you'll be asked an additional question about sharing your email address. Read the message carefully and answer as you wish.
Congratulations! Your certificate and chain have been saved and you should see your expiry date. Let's close that firewall port now that we have our certificate downloaded:
sudo ufw deny 80/tcp
However, we're not done... Now we have to install the certificate and then get it to renew automatically... Gulp... Let's press on...
Installing The SSL Certificate
So, now we need to install the certificate to the Java keystore. There's about to be a bunch of passwords and things to remember so we'd recommend making a list of these now, getting your names and passwords decided on and then proceed. We'll list them below and use these placeholders in the commands for you to substitute your chosen values:
- DOMAIN_SUBDOMAIN - for example mykeycloak.com or keycloak.mydomain.com
- KEYCLOAK_SSL_ALIAS - the alias for your SSL certificate which can be anything but avoid weird characters
- KEYCLOAK_SSL_PASSWORD - the password for your SSL certificate, again avoid weird characters
- KEYSTORE_PASSWORD - this will be the password to access the Java keystore where your certificate will live
First we have to combine the private key and certificate into a PKCS12 format file. If you're using your own certificate, the steps will be a little different and we may do a separate article on that in the future. Run the command below, ensuring that you replace all the placeholder values with your own:
sudo openssl pkcs12 -export -in /etc/letsencrypt/live/DOMAIN_SUBDOMAIN/fullchain.pem -inkey /etc/letsencrypt/live/DOMAIN_SUBDOMAIN/privkey.pem -out /etc/letsencrypt/live/DOMAIN_SUBDOMAIN/pkcs.p12 -name KEYCLOAK_SSL_ALIAS -passout pass:KEYCLOAK_SSL_PASSWORD
Now we'll create our Java keystore and import the file we just made. Navigate to the configuration folder first:
cd /opt/keycloak/current/standalone/configuration
This command creates the Java keystore by actually creating a private key, but we don't need that key so once it's made we'll delete it:
sudo keytool -keystore keycloak.jks -genkey -alias key_to_be_deleted
After executing that command you'll be asked a series of questions. The only important question is the first one, which is the keystore password and you should use the value for KEYSTORE_PASSWORD that you set up above. The rest is not important as we'll be deleting the key it makes, so just enter "test" or hit Enter to get through the questions. It will create a file called keycloak.jks in the current directory and our next step will be to import our certificates into that keystore. You can ignore the "Warning: The JKS keystore uses a proprietary format" message. Before we move on, let's check out what's in that file and delete the key that was just made. Replace KEYSTORE_PASSWORD for your actual password:
sudo keytool -list -v -keystore keycloak.jks -storepass KEYSTORE_PASSWORD
You should see that you have one entry with the alias name of key_to_be_deleted. So let's do that:
sudo keytool -delete -noprompt -alias key_to_be_deleted -keystore keycloak.jks -storepass KEYSTORE_PASSWORD
And check the keystore is now empty:
sudo keytool -list -v -keystore keycloak.jks -storepass KEYSTORE_PASSWORD
Excellent, now we can import our certificate into the keystore:
sudo keytool -importkeystore -deststorepass KEYSTORE_PASSWORD -destkeypass KEYCLOAK_SSL_PASSWORD -destkeystore keycloak.jks -srckeystore /etc/letsencrypt/live/DOMAIN_SUBDOMAIN/pkcs.p12 -srcstoretype PKCS12 -srcstorepass KEYCLOAK_SSL_PASSWORD -alias KEYCLOAK_SSL_ALIAS
Configuring Keycloak To Use The SSL Certificate
Awesome, we've imported the certificate into our keystore. So we're done right? You wish... Now we have to configure Keycloak to actually use the certificate.
NOTE: As of Keycloak 16, configuring it to use the SSL certificate has changed and the below instructions are no longer applicable. Visit our new article Setting Up A Keycloak Server For Authenticating To FileMaker: Part 10: Keycloak 16 & SSL Configuration to learn how to do this in Keycloak 16, and then return here to complete the Renewing The SSL Certificate Automatically section below.
We're going to edit the standalone.xml file, which, conveniently, is in the same directory as we are currently in, so:
sudo nano standalone.xml
First up, we need to add a security-realm which you'll find near the top under all the extension listings. Add this UndertowRealm section just above the ManagementRealm but after the <security-realms> tag (note the s on the end of the tag), ensuring the format, indents etc match what's there already. Be sure to switch out the placeholders for your values:
<security-realm name="UndertowRealm">
<server-identities>
<ssl>
<keystore path="keycloak.jks" relative-to="jboss.server.config.dir" keystore-password="KEYSTORE_PASSWORD" alias="KEYCLOAK_SSL_ALIAS" key-password="KEYCLOAK_SSL_PASSWORD"/>
</ssl>
</server-identities>
</security-realm>
The next edit we need to do is a bit hard to find but if you hit Ctrl-W you can search for
https-listener name="https"
You need to make that section match the below (the parts in bold are the items to adjust):
<server name="default-server"> <http-listener name="default" socket-binding="http" redirect-socket="https" enable-http2="true"/> <https-listener name="https" socket-binding="https" security-realm="UndertowRealm" enable-http2="true"/> <host name="default-host" alias="localhost"> <location name="/" handler="welcome-content"/> <http-invoker security-realm="UndertowRealm"/> </host> </server>
Hit Ctrl-O and then Enter to save and then Ctrl-X to exit the editor and let's reboot:
sudo shutdown -r now
Once the machine has rebooted, give it a couple minutes to get all services up and running and then try going here in a browser:
https://DOMAIN_SUBDOMAIN:8443/auth/
We're crossing our fingers for you and hoping that you see the Welcome to Keycloak page along with a lock icon to indicate the connection is encrypted. If not, then pour over the details above making sure that you got everything right as the smallest thing can break the entire application.
If that works fine, then awesome, and let's check that the port forwarding we set up earlier works:
https://DOMAIN_SUBDOMAIN/auth/
You should land at the same place but note that this time we omitted the port number in the web address. It's important that this works, because as of FileMaker Server 19.2.1, you can not use a port number in the Keycloak web address - hopefully this will change in the future.
Renewing The SSL Certificate Automatically
So as we mentioned above, Let's Encrypt certificates are free but they only last 90 days. You could go through the process we've outlined here every 90 days but you're going to forget and then your authentication server is going to go down and your users won't be able to log in to their application (in our case their FileMaker database). So, getting it to renew automatically is the way to go, and our friend Certbot has already got us started.
When we installed Certbot, it created a timer for us. We can confirm that with:
sudo systemctl list-timers
You should see one called snap.certbot.renew.timer. If you don't then try enabling it and run the above command again:
sudo systemctl enable snap.certbot.renew.timer
It's also possible to check on the status of the timer using:
sudo systemctl status snap.certbot.renew.timer
When Certbot checks for a new certificate, it again does so over port 80. As we'd rather not leave port 80 open all the time, we'll use Let's Encrypt's pre and post hook functions to open and close the port for us.
cd /etc/letsencrypt/renewal-hooks/pre
Make a new file called pre-hook.sh
sudo nano pre-hook.sh
And then paste the below into that file - be sure that it looks like the below and those commands are not all on one line after pasting:
#!/bin/bash # Open port 80 ufw allow 80/tcp
Hit Ctrl-O and Enter to save and Ctrl-X to exit the editor. Now we need to make that file executable:
sudo chmod +x pre-hook.sh
And now let's do the same procedure for the post hook and closing the port:
cd /etc/letsencrypt/renewal-hooks/post
Make a new file called post-hook.sh
sudo nano post-hook.sh
Paste the below into that file - again make sure there are multiple lines after pasting:
#!/bin/bash # Close port 80 ufw deny 80/tcp
Hit Ctrl-O and Enter to save and Ctrl-X to exit the editor. Again we need to make that file executable:
sudo chmod +x post-hook.sh
Ok, so Certbot is ready to update our certificate, but we need to automate the transfer to PKCS12 format and get it into our keystore, and for that we'll run a script after a new certificate is deployed. Go to this directory:
cd /etc/letsencrypt/renewal-hooks/deploy
Make a new file called new-cert-to-keystore.sh
sudo nano new-cert-to-keystore.sh
Paste the below into that file and be sure to update all the placeholders:
#!/bin/bash # Convert the private key and certificate to a PKCS12 file openssl pkcs12 -export -in /etc/letsencrypt/live/DOMAIN_SUBDOMAIN/fullchain.pem -inkey /etc/letsencrypt/live/DOMAIN_SUBDOMAIN/privkey.pem -out /etc/letsencrypt/live/DOMAIN_SUBDOMAIN/pkcs.p12 -name KEYCLOAK_SSL_ALIAS -passout pass:KEYCLOAK_SSL_PASSWORD # Remove the old certificate from our keystore keytool -delete -noprompt -alias KEYCLOAK_SSL_ALIAS -keystore /opt/keycloak/current/standalone/configuration/keycloak.jks -storepass KEYSTORE_PASSWORD # Import the new certificate to our keystore keytool -importkeystore -deststorepass KEYSTORE_PASSWORD -destkeypass KEYCLOAK_SSL_PASSWORD -destkeystore /opt/keycloak/current/standalone/configuration/keycloak.jks -srckeystore /etc/letsencrypt/live/DOMAIN_SUBDOMAIN/pkcs.p12 -srcstoretype PKCS12 -srcstorepass KEYCLOAK_SSL_PASSWORD -alias KEYCLOAK_SSL_ALIAS # Restart Keycloak systemctl restart keycloak
Hit Ctrl-O and Enter to save and Ctrl-X to exit the editor. Make that file executable:
sudo chmod +x new-cert-to-keystore.sh
You can test the renewal procedure by executing this command:
sudo certbot renew --dry-run
Although we will not be getting into it here, if you wish you can put the deploy script/code into the post directory to ensure it executes correctly. After doing that, if you delete the certificate from the keystore and run the renew command, you should find the keystore gets re-populated with the certificate again. Be sure to remove that code from the post directory as you don't want it running each time Certbot checks for a renewal.
Your certificate should renew about 30 days before it expires, so add a calendar reminder to check that it has around that time.
Summary
Good grief... If you scroll up, keep scrolling, keep scrolling, all the way back up to the top, you'll be reminded of the section where we talked about how SSL certificates should be easier. Are we in agreement yet? On a positive note, we're in good shape now with our traffic being encrypted and we can move on to our next task, which is detailed in our next blog article.