Configure Let's Encrypt SSL certificate for WebSphere / Open Liberty
Author(s): Tamas Bures | Created: 09 August 2019 | Last modified: 21 December 2024
Tested on: -
Table of contents
Configure Let's Encrypt SSL certificate for WebSphere / Open Liberty↑
It's very common and so called standard procedure to use Let's Encrypt services to generate simple SSL certificate for your webservers when publishing something to the great Internet. If you are using a simple HTTP server like IBM IHS, Apache or Nginx, you will found plenty of howto guides to achieve your goal and being a friendly HTTPS site.
If you are using WebSphere or Open Liberty application server, things get different a bit because this servers need to be configured a different way and Let's Encrypt has some limitations you need to deal with if you want to use HTTP-01 verification method.
In this guide, I'll show you how to generate an SSL certificate for your Liberty server.
Requirements↑
I assume, that you have already installed Liberty and created at least one server. I also assume you have installed Let's Encrypt's own tool called certbot
to generate certificates. If you want to know how to install certbot, Google is your friend, but here is a short bash snippet if you are using CentOS or Red Hat:
yum -y install epel-release yum-utils
yum -y install certbot
Configuration↑
Once you have installed everything, follow the steps below.
-
We need to start with the certbot tool by generating a certificate:
certbot certonly --manual --preferred-challenges http-01 -d example.com
Where:
certonly
instructcertbot
to generate a certificate only
--manual
certbot can configure automatically the most common webservers, but unfortunately there is no out of box Liberty support, therefore we need to do it manually
--preferred-challenges http-01
the http-01 domain validation method will be used A special file will be required to be placed under your server which need to be reachable by Let's Encrypt
-d <domain>
the domain name for you want to issue the certificate
-
Once you issued the command in step 1, follow the instructions printed on the screen, an example below:
root@host: certbot certonly --manual --preferred-challenges http-01 -d example.com Saving debug log to /var/log/letsencrypt/letsencrypt.log Plugins selected: Authenticator manual, Installer None Starting new HTTPS connection (1): acme-v02.api.letsencrypt.org Obtaining a new certificate Performing the following challenges: http-01 challenge for example.com - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - NOTE: The IP of this machine will be publicly logged as having requested this certificate. If you're running certbot in manual mode on a machine that is not your server, please ensure you're okay with that. Are you OK with your IP being logged? - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - (Y)es/(N)o: Y - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Create a file containing just this data: <a very long random string> And make it available on your web server at this URL: http://example.com/.well-known/acme-challenge/<very long random string 2> - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - Press Enter to Continue
Don't press enter because the fun part now comes.
-
Becuse application servers are using context roots to route the requests to the corresponding application, often there is no application configured without context root, or so called
/
. If you open your browser and navigate to your server's empty context root (i.e.:http://example.com/
), an application server will show up saying, Context root not found. To get around of this issue, create a simple web application with one servlet in it and make sure, that the context-root is mapped to the root (/
) and the servlet will return the required content on the given path printed by thecertbot
tool.Servlet implementation:
package hu.ibm.letsencrypt; import java.io.IOException; import java.io.PrintWriter; import javax.servlet.ServletException; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; /** * Servlet implementation class Validator */ @WebServlet(name = "Validator", urlPatterns = { "/.well-known/acme-challenge/<a very long random string>" }) public class Validator extends HttpServlet { private static final long serialVersionUID = 1L; public Validator() { } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/plain"); PrintWriter pw = response.getWriter(); pw.write("<a very long random string 2>"); pw.flush(); pw.close(); } }
ibm-web-ext.xml:
<?xml version="1.0" encoding="UTF-8"?> <web-ext xmlns="http://websphere.ibm.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://websphere.ibm.com/xml/ns/javaee http://websphere.ibm.com/xml/ns/javaee/ibm-web-ext_1_1.xsd" version="1.1"> <reload-interval value="3"/> <context-root uri="/"/> <enable-directory-browsing value="false"/> <enable-file-serving value="true"/> <enable-reloading value="true"/> <enable-serving-servlets-by-class-name value="false" /> </web-ext>
-
Once you finished the changes, wrap your app to a WAR file and deploy to Liberty. If you did everything right, you should be able to get the content in your browser by checking the URL:
http://example.com/.well-known/acme-challenge/<a very long random string>
. And content matched:<a very long random string 2>
. -
Head back to certbot and press
Enter
. Once the verification is done, you should see something similar:Waiting for verification... Resetting dropped connection: acme-v02.api.letsencrypt.org Resetting dropped connection: acme-v02.api.letsencrypt.org Cleaning up challenges IMPORTANT NOTES: - Congratulations! Your certificate and chain have been saved at: /etc/letsencrypt/live/example.com/fullchain.pem Your key file has been saved at: /etc/letsencrypt/live/example.com/privkey.pem Your cert will expire on 2019-11-07. To obtain a new or tweaked version of this certificate in the future, simply run certbot again. To non-interactively renew *all* of your certificates, run "certbot renew" - If you like Certbot, please consider supporting our work by: Donating to ISRG / Let's Encrypt: https://letsencrypt.org/donate Donating to EFF: https://eff.org/donate-le
-
Next step to create the initial keystore in Liberty, by first encoding the password and replace the
<liberty_keystore_password>
to your own password:<liberty_server_root>/bin/securityUtility encode <liberty_keystore_password>
Note the output:
{xor}<something random string>=
-
Edit
<liberty_server_root>/usr/servers/<server name>/server.xml
and add the following content and replace the values in<>
to match your environment:<keyStore id="defaultKeyStore" location="<liberty_server_root>/usr/servers/<server name>/resources/security/keystore.jks" password="{xor}<something random string>=" type="PKCS12"/>
-
Start, then stop the server by replacing the value in
<>
to match your environment:<liberty_server_root>/bin/server start <server name> <liberty_server_root>/bin/server stop <server name>
-
Add the certificate generated by
certbot
to Liberty server's freshly created keystore:To extract the certificate:
openssl pkcs12 -export -out ~/key.p12 \ -in /etc/letsencrypt/live/example.com/fullchain.pem \ -name default \ -inkey /etc/letsencrypt/live/example.com/privkey.pem \ -password 123456
Add the certificate to Liberty's keystore:
keytool -importkeystore \ -deststorepass <liberty_keystore_password> \ -destkeypass <liberty_keystore_password> \ -destkeystore <liberty_server_root>/usr/servers/<server name>/resources/security/keystore.jks \ -srckeystore ~/key.p12 \ -srcstoretype PKCS12 \ -srcstorepass <password used in previous command - 123456> \ -alias default
-
Start the server:
<liberty_server_root>/bin/server start <server name>
-
Enjoy HTTPS. :)