Skip to content

How to Utilise Let's Encrypt with Docker

Paul McCann edited this page Nov 3, 2022 · 1 revision

About

Let's Encrypt is a nonprofit Certificate Authority providing TLS certificates. The following guide will demonstrate how to utilise this service to use a valid certificate within the application server instead of using the self signed certificate.

This guide is provided by @rudosch

Guide

To use a letsencrypt certificate the following steps are needed:

  1. Edit the Dockerfile
Copy the following into the Dockerfile
ARG TOMCAT_DOCKER_VERSION

FROM docker AS builder
ARG TLS_KEYSTORE_FILE
ARG TLS_KEYSTORE_PASS
ARG ALIAS
ARG HTTPS_PORT
ARG DB_DRIVER=org.gjt.mm.mysql.Driver
ARG DB_SCHEMA=core
ARG DB_USER
ARG DB_PASS
ARG MARIADB_URI
ARG MONGO_HOST
ARG MONGO_PORT
ARG MONGO_CONN_TIMEOUT
ARG MONGO_SOCK_TIMEOUT
ARG MONGO_SVR_TIMEOUT

USER root
WORKDIR /workdir

COPY target/owaspSecurityShepherd.war ROOT.war
# --- use self-signed certificate
# COPY target/docker/tomcat/$TLS_KEYSTORE_FILE $TLS_KEYSTORE_FILE
# COPY docker/tomcat/serverxml.patch serverxml.patch
# --- use letsencrypt certificate
COPY docker/tomcat/letsencrypt letsencrypt
COPY docker/tomcat/serverxml.patch serverxml.letsencrypt.patch
COPY docker/tomcat/webxml.patch webxml.patch

RUN printf "databaseConnectionURL=$MARIADB_URI/\nDriverType=$DB_DRIVER\ndatabaseSchema=$DB_SCHEMA\ndatabaseUsername=$DB_USER\ndatabasePassword=$DB_PASS\ndatabaseOptions=useUnicode=true&character_set_server=utf8mb4\n" >> database.properties
RUN printf "connectionHost=$MONGO_HOST\nconnectionPort=$MONGO_PORT\ndatabaseName=shepherdGames\nconnectTimeout=$MONGO_CONN_TIMEOUT\nsocketTimeout=$MONGO_SOCK_TIMEOUT\nserverSelectionTimeout=$MONGO_SVR_TIMEOUT"  >> mongo.properties
# --- not needed if using serverxml.letsencrypt.patch
# RUN sed -i 's/keystoreFile="conf\/TLS_KEYSTORE_FILE" keystorePass="TLS_KEYSTORE_PASS" keyAlias="ALIAS">/keystoreFile="conf\/'"$TLS_KEYSTORE_FILE"'" keystorePass="'"$TLS_KEYSTORE_PASS"'" keyAlias="'"$ALIAS"'">/g' serverxml.patch &&\
RUN sed -i 's/redirectPort="HTTPS_PORT" \/>/redirectPort="'"$HTTPS_PORT"'" \/>/g' serverxml.patch


FROM tomcat:${TOMCAT_DOCKER_VERSION}
COPY --from=builder /workdir/ROOT.war /usr/local/tomcat/webapps/
# --- not needed if using serverxml.letsencrypt.patch
# COPY --from=builder /workdir/$TLS_KEYSTORE_FILE /usr/local/tomcat/conf/
COPY --from=builder /workdir/letsencrypt /usr/local/tomcat/conf/letsencrypt
COPY --from=builder /workdir/serverxml.patch /usr/local/tomcat/conf/
COPY --from=builder /workdir/webxml.patch /usr/local/tomcat/conf/
COPY --from=builder /workdir/database.properties /usr/local/tomcat/conf/
COPY --from=builder /workdir/mongo.properties /usr/local/tomcat/conf/

ENV RUN_USER tomcat
RUN apt-get -qq update && apt-get install -y patch libargon2-0
RUN adduser --system --group ${RUN_USER} --home ${CATALINA_HOME}
RUN chown -R ${RUN_USER}:${RUN_GROUP} $CATALINA_HOME
USER ${RUN_USER}

ENV CATALINA_OPTS "-Duser.timezone=Europe/Dublin"

RUN rm -rf /usr/local/tomcat/webapps/ROOT
# --- not needed if using serverxml.letsencrypt.patch
# RUN patch /usr/local/tomcat/conf/server.xml /usr/local/tomcat/conf/serverxml.patch
RUN patch /usr/local/tomcat/conf/server.xml /usr/local/tomcat/conf/serverxml.letsencrypt.patch
RUN patch /usr/local/tomcat/conf/web.xml /usr/local/tomcat/conf/webxml.patch

EXPOSE 8080 8443
CMD ["catalina.sh", "run"]
  1. Edit the serverxml.patch
Copy the following into the serverxml.patch
--- server.xml	2022-10-20 23:27:06.000000000 +0200
+++ server.letsencrypt.xml	2022-10-21 09:33:07.013326579 +0200
@@ -65,17 +65,16 @@
          Java AJP  Connector: /docs/config/ajp.html
          APR (HTTP/AJP) Connector: /docs/apr.html
          Define a non-SSL/TLS HTTP/1.1 Connector on port 8080
-    -->
     <Connector port="8080" protocol="HTTP/1.1"
                connectionTimeout="20000"
                redirectPort="8443" />
+    -->
     <!-- A "Connector" using the shared thread pool-->
-    <!--
     <Connector executor="tomcatThreadPool"
                port="8080" protocol="HTTP/1.1"
                connectionTimeout="20000"
-               redirectPort="8443" />
-    -->
+               redirectPort="HTTPS_PORT" />
+
     <!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443
          This connector uses the NIO implementation. The default
          SSLImplementation will depend on the presence of the APR/native
@@ -83,15 +82,15 @@
          Either JSSE or OpenSSL style configuration may be used regardless of
          the SSLImplementation selected. JSSE style configuration is used below.
     -->
-    <!--
     <Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
-               maxThreads="150" SSLEnabled="true">
-        <SSLHostConfig>
-            <Certificate certificateKeystoreFile="conf/localhost-rsa.jks"
-                         type="RSA" />
+               maxThreads="150" SSLEnabled="true" scheme="https" secure="true">
+        <SSLHostConfig certificateVerification="none" protocols="TLSv1.2">
+            <Certificate certificateFile="conf/letsencrypt/cert.pem"
+                         certificateKeyFile="conf/letsencrypt/privkey.pem"
+                         certificateChainFile="conf/letsencrypt/chain.pem" />
         </SSLHostConfig>
     </Connector>
-    -->
+
     <!-- Define an SSL/TLS HTTP/1.1 Connector on port 8443 with HTTP/2
          This connector uses the APR/native implementation which always uses
          OpenSSL for TLS.
  1. Add generated Let's Encrypt certificate files (*.pem) to new directory docker/tomcat/letsencrypt

  2. Build the project docker-compose build

  3. Run the project docker-compose run -d