Configure Let's Encrypt SSL certificate for WebSphere / Open Liberty


Author(s): Tamas Bures | Created: 09 August 2019 | Last modified: 23 April 2024
Tested on: -

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.

  1. We need to start with the certbot tool by generating a certificate:

     certbot certonly --manual --preferred-challenges http-01 -d example.com

    Where:

    • certonly instruct certbot 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
  2. 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.

  3. 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 the certbot 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>
    
  4. 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>.

  5. 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
  6. 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>=

  7. 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"/>
  8. 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>
  9. 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
  10. Start the server:

     <liberty_server_root>/bin/server start <server name>
  11. Enjoy HTTPS. :)