Let’s Encrypt is a free Certificate Authority. To enable HTTPS on a website, one needs to get a certificate from a Certificate Authority. Let’s Encrypt recommends to use Certbot - a tool that validates your ownership over the target domain and fetches the certificates.
Intalling Certbot on CentOS7
sudo yum install epel-release sudo yum install certbot
Validating a domain to fetch a certificate
Fetching certificates is described in detail in thethe official documentation, which needs to be consulted to understand the command below. Briefly, Certbot attempts to validate that you own the domain for which you ask a certificate. When a user opts for http-based verification, Certbot asks to create two files with tiny contents specified by Certbot so that they are accessible at some urls in your domain also specified by Certbot.
sudo certbot certonly --manual --preferred-challenges http -d food-diary-online.com -d www.food-diary-online.com --manual-auth-hook /opt/SSLCertificates/authenticator.sh --non-interactive --manual-public-ip-logging-ok
--manual-auth-hook option points on the script authenticator.sh creating files in a web application folder .well-known/acme-challenge that is accessible by CertBot via web:
#!/bin/bash TARGET_DIR=/opt/wildfly-10.1.0.Final/standalone/deployments/FoodApp.war/.well-known/acme-challenge mkdir -p $TARGET_DIR echo $CERTBOT_VALIDATION > $TARGET_DIR/$CERTBOT_TOKEN
As the result the certificates are downloaded
Strangely, a normal user could not access the certificates because of the permissions on the created by Certbot parent folders. So I adjusted the permissions:
sudo chmod 755 /etc/letsencrypt/archive sudo chmod 755 /etc/letsencrypt/live cat /etc/letsencrypt/live/food-diary-online.com/fullchain.pem
The indicated directory /etc/letsencrypt/live/food-diary-online.com/ contains symbolic links privkey.pem and fullchain.pem to the most recently downloaded certificate files. For example, when I downloaded the certificates second time, the directory contents were:
What happens without manual-auth-hook
Importing the private key with the fetches certificate into a Java key store (jks)
The following files has been created:
- privkey.pem - Private key for the certificate.
- fullchain.pem - The server certificate followed by intermediate certificates that web browsers use to validate the server certificate.
However, Wildfly 10 accepts only jks. So the fullchain.pem has to be imported into jks. However, keytool can import a certificate or an entire keystore, but does not import a private key separated from the paired public key with the certificate. Therefore, a private key has to be combined with the certificate in a acceptable PKCS12 keystore with openssl command. Then the keystore can be imported into jks. The keystore will be created in /opt/SSLCertificates/
cd /opt/SSLCertificates/ openssl pkcs12 -export -in /etc/letsencrypt/live/food-diary-online.com/fullchain.pem -inkey /etc/letsencrypt/live/food-diary-online.com/privkey.pem -out keystore.p12 -name wildfly -passout pass:changeit
changeit is the password for the keystrore to be created. File keystore.p12 is created.
keytool -importkeystore -deststorepass changeit -destkeypass changeit -destkeystore keystore.jks -srckeystore keystore.p12 -srcstoretype PKCS12 -srcstorepass changeit -v -noprompt
Jks keystore.jks is created when the command is executed for the first time. During the second import the existing alias will be overwritten:
Configuring SSL in Wildfly
Stop the server and edit standalone.xml so that it contains:
<security-realm name="ApplicationRealm"> <server-identities> <ssl> <keystore path="/opt/SSLCertificates/keystore.jks" keystore-password="changeit" alias="wildfly" key-password="changeit"/> </ssl> </server-identities> <authentication> <local default-user="$local" allowed-users="*" skip-group-loading="true"/> <properties path="application-users.properties" relative-to="jboss.server.config.dir"/> </authentication> <authorization> <properties path="application-roles.properties" relative-to="jboss.server.config.dir"/> </authorization> </security-realm>
Start the server. Well, that's it, we're done.
Automatic certificate renewal Incomplete yet
The only problem with the Let's Encrypt certificates is that they last for 90 days, so they have to be regularly renewed. This can be achieved with a script scheduled in crontab.
cerbot renew command attempts to renew any previously-obtained certificates that expire in less than 30 days. The same plugin and options that were used at the time the certificate was originally issued will be used for the renewal attempt, unless you specify other plugins or options. renew can be run as frequently as you want since it will usually take no action.
I created deployhook.sh script in /opt/SSLCertificates/. The script merely executes the commands used above to import the certificates into the java keystore and restart wildfly.
#!/bin/bash service wildfly stop cd /opt/SSLCertificates/ openssl pkcs12 -export -in /etc/letsencrypt/live/food-diary-online.com/fullchain.pem -inkey /etc/letsencrypt/live/food-diary-online.com/privkey.pem -out keystore.p12 -name wildfly -passout pass:changeit keytool -importkeystore -deststorepass changeit -destkeypass changeit -destkeystore keystore.jks -srckeystore keystore.p12 -srcstoretype PKCS12 -srcstorepass changeit -v -noprompt service wildfly start
Now, to renew certificates one single-line command is sufficient. The script indicated by --deploy-hook is executed only after a successful certificate renewal.
sudo certbot renew --deploy-hook deployhook.sh
The output of the command:
[centos@ip-172-31-42-159 SSLCertificates]$ sudo certbot renew --deploy-hook ./deployhook.sh Saving debug log to /var/log/letsencrypt/letsencrypt.log ------------------------------------------------------------------------------- Processing /etc/letsencrypt/renewal/food-diary-online.com.conf ------------------------------------------------------------------------------- Cert is due for renewal, auto-renewing... Plugins selected: Authenticator manual, Installer None Starting new HTTPS connection (1): acme-v01.api.letsencrypt.org Renewing an existing certificate Performing the following challenges: http-01 challenge for food-diary-online.com http-01 challenge for www.food-diary-online.com Waiting for verification... Cleaning up challenges Running deploy-hook command: ./deployhook.sh Output from deployhook.sh: Stopping wildfly (via systemctl): [ OK ] Starting wildfly (via systemctl): [ OK ] Error output from deployhook.sh: Warning: Overwriting existing alias wildfly in destination keystore Entry for alias wildfly successfully imported. Import command completed: 1 entries successfully imported, 0 entries failed or cancelled [Storing keystore.jks] ------------------------------------------------------------------------------- new certificate deployed without reload, fullchain is /etc/letsencrypt/live/food-diary-online.com/fullchain.pem ------------------------------------------------------------------------------- ------------------------------------------------------------------------------- Congratulations, all renewals succeeded. The following certs have been renewed: /etc/letsencrypt/live/food-diary-online.com/fullchain.pem (success) ------------------------------------------------------------------------------- [centos@ip-172-31-42-159 SSLCertificates]$
To automate the renewals, the command has to be scheduled in the crontab.
Do you really need to restart your Wildfly to enable renewed certificates?
ReplyDeleteyou can use the --webroot plugin with the -w option to save the challenges directly in the .well-known/challenges folder, but you need to run this with umask 022 otherwise the files are owned by root and the test will return a 404
ReplyDelete