This is a overview of configuring one-way SSL between Tomcat and Keycloak.

  1. Keycloak Keystore
$JAVA_HOME/bin/keytool -genkeypair -alias keycloak -keyalg RSA -keysize 2048 -validity 365 \
-keystore keycloak-keystore.jks -storepass password -keypass password
$JAVA_HOME/bin/keytool -genkeypair -alias keycloak -keyalg RSA -keysize 2048 -validity 365 \
-keystore keycloak-keystore.jks -storepass password -keypass password \
-dname "CN=<KEYCLOAK_IP>, OU=<ORG>, O=<ORG_NAME>, L=<CITY>, ST=<STATE>, C=<COUNTRY>" \
-ext SAN=DNS:localhost,IP:<KEYCLOAK_IP>
  1. Keycloak Certificate Export :
$JAVA_HOME/bin/keytool -export -alias keycloak -file keycloak-public-cert.crt \
-keystore keycloak-keystore.jks -storepass password
  1. Tomcat Keystore Generation
$JAVA_HOME/bin/keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -validity 365 \
-keystore tomcat-keystore.jks -storepass password -keypass password
$JAVA_HOME/bin/keytool -genkeypair -alias tomcat -keyalg RSA -keysize 2048 -validity 365 \
-keystore tomcat-keystore.jks -storepass password -keypass password \
-dname "CN=<TOMCAT_IP>, OU=<ORG>, O=<ORG_NAME>, L=<CITY>, ST=<STATE>, C=<COUNTRY>" \
-ext SAN=DNS:localhost,IP:<TOMCAT_IP>
  1. Tomcat Certificate Export
$JAVA_HOME/bin/keytool -export -alias tomcat -file tomcat-public-cert.crt \
-keystore tomcat-keystore.jks -storepass password
  1. Import Keycloak's Certificate into Tomcat's Truststore
$JAVA_HOME/bin/keytool -import -trustcacerts -alias keycloak -file keycloak-public-cert.crt \
-keystore tomcat-truststore.jks -storepass password
  1. Keycloak Configuration (keycloak.conf)

hostname=localhost
https-listener-enabled=true
https-port=9443
https-client-auth=none
https-key-store-file=/path/to/keycloak-keystore.jks
https-key-store-password=password
  1. Tomcat SSL Configuration (server.xml)

<Connector port="8443" protocol="org.apache.coyote.http11.Http11NioProtocol"
      maxThreads="200" SSLEnabled="true" clientAuth="false">
    <UpgradeProtocol className="org.apache.coyote.http2.Http2Protocol" />
    <SSLHostConfig>
        <Certificate certificateKeystoreFile="conf/tomcat-keystore.jks"
                     certificateKeystorePassword="password" />
        <Truststore certificateKeystoreFile="conf/tomcat-truststore.jks"
                    certificateKeystorePassword="password" />
    </SSLHostConfig>
</Connector>
  1. Tomcat Truststore Configuration in catalina.sh
JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.trustStore=/path/to/tomcat-truststore.jks"
JAVA_OPTS="$JAVA_OPTS -Djavax.net.ssl.trustStorePassword=password"
JAVA_OPTS="$JAVA_OPTS -Djavax.net.debug=ssl,handshake"
  1. Keycloak Client Configurations for HTTPS
<VirtualHost *:443>
    ServerName <DOMAIN_NAME>
    ServerAlias <ALIAS_NAME>

    # SSL Certificate Files
    SSLEngine On
    SSLCertificateFile <SSL_CERTIFICATE_PATH>
    SSLCertificateKeyFile <SSL_KEY_PATH>
    SSLCertificateChainFile <SSL_CHAIN_CERTIFICATE_PATH>

    # Proxy Settings
    ProxyPreserveHost On
    ProxyRequests Off

    # Forward requests to Keycloak
    ProxyPass /admin-ui https://<KEYCLOAK_SERVER>:<KEYCLOAK_PORT>/admin-ui
    ProxyPassReverse /admin-ui https://<KEYCLOAK_SERVER>:<KEYCLOAK_PORT>/admin-ui

    ProxyPass / https://<KEYCLOAK_SERVER>:<KEYCLOAK_PORT>/
    ProxyPassReverse / https://<KEYCLOAK_SERVER>:<KEYCLOAK_PORT>/

    # Fix Cookie Paths for Reverse Proxy
    ProxyPassReverseCookiePath / /

    # Security Headers
    Header always set X-Frame-Options SAMEORIGIN
    Header always set X-XSS-Protection "1; mode=block"
    Header always set X-Content-Type-Options nosniff
    Header always set Strict-Transport-Security "max-age=63072000; includeSubDomains; preload"
    Header always set Referrer-Policy "no-referrer-when-downgrade"
    Header always set Content-Security-Policy "default-src 'self' https:; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
    Header always set Permissions-Policy "geolocation=(), microphone=(), camera=()"

    # Logging (optional)
    ErrorLog ${APACHE_LOG_DIR}/reverse-proxy-ssl-error.log
    CustomLog ${APACHE_LOG_DIR}/reverse-proxy-ssl-access.log combined
</VirtualHost>

<VirtualHost *:80>
    ServerName <DOMAIN_NAME>
    ServerAlias <ALIAS_NAME>

    # Redirect HTTP to HTTPS
    RewriteEngine On
    RewriteCond %{HTTPS} !=on
    RewriteRule ^/(.*)$ https://<DOMAIN_NAME>/$1 [R=301,L]

    # Logging (optional)
    ErrorLog ${APACHE_LOG_DIR}/reverse-proxy-error.log
    CustomLog ${APACHE_LOG_DIR}/reverse-proxy-access.log combined
</VirtualHost>

  1. Tomcat Admin UI Configuration
spring.security.oauth2.client.logout.keycloak.base.url=https://localhost:9443/realms/<REALM>/protocol/openid-connect/logout
spring.security.oauth2.client.provider.keycloak.token-uri=https://localhost:9443/realms/<REALM>/protocol/openid-connect/token
spring.security.oauth2.client.provider.keycloak.jwk.set.uri=https://localhost:9443/realms/<REALM>/protocol/openid-connect/certs
spring.security.oauth2.client.provider.keycloak.authorization.uri=https://localhost:9443/realms/<REALM>/protocol/openid-connect/auth


Login with OAuth 2.0
[invalid_token_response] An error occurred while attempting to retrieve the OAuth 2.0 Access Token Response: I/O error on POST request for "https://<ip>:9443/realms/demo-realm/protocol/openid-connect/token": PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
keycloak again this is coming
tail -f /path/tomcat/logs/catalina.out
29-Jan-2025 00:35:35.883 INFO [main] org.apache.tomcat.util.net.AbstractEndpoint.logCertificate Connector [https-jsse-nio-8443], TLS virtual host [_default_], certificate type [UNDEFINED] configured from keystore [/path/tomcat-11.0.2/conf/tomcat-keystore.jks] using alias [tomcat] with trust store [null]
check where you added $JAVA_OPTS in tomcat server.xml and added it under JAVA_OPTS parameter set.

Two way SSL Configuration for module-a and module-b Platform Server

Generating key, certificate and keystore for module-a-gw

openssl genrsa -out module-a-key.pem 2048
openssl req -x509 -new -nodes -key module-a-key.pem -sha256 -days 365 \
-out module-a-cert.pem \
-subj "/C=LK/ST=WP/L=CMB/O=HMS/OU=module-a/CN=localhost"
openssl pkcs12 -export -out module-a-keystore.p12 \
-inkey module-a-key.pem -in module-a-cert.pem -name module-a \
-password pass:password
$JAVA_HOME/bin/keytool -importkeystore -destkeystore module-a-keystore.jks \
-srckeystore module-a-keystore.p12 -srcstoretype pkcs12 \
-alias module-a -deststorepass password -srcstorepass password

Generating key, certificate and keystore for module-b Platform Server

openssl genrsa -out eqp-key.pem 2048
openssl req -x509 -new -nodes -key eqp-key.pem -sha256 -days 365 \
-out eqp-cert.pem \
-subj "/C=LK/ST=WP/L=CMB/O=HMS/OU=eqp/CN=localhost"
openssl pkcs12 -export -out eqp-keystore.p12 \
-inkey eqp-key.pem -in eqp-cert.pem -name eqp \
-password pass:password
$JAVA_HOME/bin/keytool -importkeystore -destkeystore eqp-keystore.jks \
-srckeystore eqp-keystore.p12 -srcstoretype pkcs12 \
-alias eqp -deststorepass password -srcstorepass password

Generating truststore for module-a-gw and module-buery server

$JAVA_HOME/bin/keytool -import -trustcacerts -alias eqp -file eqp-cert.pem \
    -keystore module-a-truststore.jks -storepass password
$JAVA_HOME/bin/keytool -import -trustcacerts -alias module-a -file module-a-cert.pem \
    -keystore eqp-truststore.jks -storepass password

Application Configuration

Note:

wrapper.java.additional.1=-Djavax.net.ssl.trustStore=<relevant-trustore.jks>
wrapper.java.additional.2=-Djavax.net.ssl.trustStorePassword=<truststore-password>

Written by A.M. Rinas