# Service Registry & SSO Integration with Self-Signed Certificate

When securing Service Registry using Red Hat SSO that has HTTPS endpoint set up with a self-signed certificate, you might end up with following error when starting the Service Registry container.

```log
__  ____  __  _____   ___  __ ____  ______
 --/ __ \/ / / / _ | / _ \/ //_/ / / / __/
 -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
--\___\_\____/_/ |_/_/|_/_/|_|\____/___/
2022-08-05 09:24:44,968 INFO  [org.apa.kaf.con.jso.JsonConverterConfig] (main) JsonConverterConfig values:
 converter.type = key
 decimal.format = BASE64
 schemas.cache.size = 0
 schemas.enable = true

Aug 05, 2022 9:24:47 AM org.jboss.threads.Version <clinit>
INFO: JBoss Threads version 3.2.0.Final-redhat-00003
Aug 05, 2022 9:24:48 AM io.quarkus.runtime.ApplicationLifecycleManager run
ERROR: Failed to start application (with profile prod)
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
 at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(SunCertPathBuilder.java:141)
 at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:126)
 at java.base/java.security.cert.CertPathBuilder.build(CertPathBuilder.java:297)
 at java.base/sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:434)
 at java.base/sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:306)
 at java.base/sun.security.validator.Validator.validate(Validator.java:264)
 at java.base/sun.security.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:313)
 at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(X509TrustManagerImpl.java:276)
 at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:141)
 at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.checkServerCerts(CertificateMessage.java:632)
 at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.onCertificate(CertificateMessage.java:473)
 at java.base/sun.security.ssl.CertificateMessage$T12CertificateConsumer.consume(CertificateMessage.java:369)
 at java.base/sun.security.ssl.SSLHandshake.consume(SSLHandshake.java:392)
 at java.base/sun.security.ssl.HandshakeContext.dispatch(HandshakeContext.java:443)
 at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1074)
 at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask$DelegatedAction.run(SSLEngineImpl.java:1061)
 at java.base/java.security.AccessController.doPrivileged(Native Method)
 at java.base/sun.security.ssl.SSLEngineImpl$DelegatedTask.run(SSLEngineImpl.java:1008)
 at io.netty.handler.ssl.SslHandler.runAllDelegatedTasks(SslHandler.java:1557)
 at io.netty.handler.ssl.SslHandler.runDelegatedTasks(SslHandler.java:1571)
 at io.netty.handler.ssl.SslHandler.unwrap(SslHandler.java:1455)
 at io.netty.handler.ssl.SslHandler.decodeJdkCompatible(SslHandler.java:1282)
 at io.netty.handler.ssl.SslHandler.decode(SslHandler.java:1329)
 at io.netty.handler.codec.ByteToMessageDecoder.decodeRemovalReentryProtection(ByteToMessageDecoder.java:501)
 at io.netty.handler.codec.ByteToMessageDecoder.callDecode(ByteToMessageDecoder.java:440)
 at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:276)
 at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
 at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
 at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:357)
 at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1410)
 at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:379)
 at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:365)
 at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:919)
 at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:163)
 at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:714)
 at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:650)
 at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:576)
 at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:493)
 at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:989)
 at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
 at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
 at java.base/java.lang.Thread.run(Thread.java:829)
```

## Problem

The reason behind the scence is basically Service Registry cannot connect to Red Hat SSO via HTTPS endpoint because self-signed certificate is unknown and the CA who sign the certificate is not trusted by JVM.

## Solution

To fix this issue, in summary, you need to add the self-signed certificate (the one that's used to setup HTTPS endpoint for SSO) or the certificate of CA who signed the certificate itself to JVM truststore/keystore file so the certificate is known or trusted by JVM. To do so, follow the steps below:

1. Get list of Service Registry pod(s) with follwing command.

   ```
   oc get pod | grep service
   ```

   Sample output:

   ```
   $ oc get pod | grep service
   NAME                                                          READY   STATUS      RESTARTS   AGE
   service-registry-deployment-79bd796c6b-5tpdg                  1/1     Running     0               53s
   service-registry-deployment-79bd796c6b-bzmst                  1/1     Running     0               52s
   service-registry-deployment-79bd796c6b-qg6vp                  1/1     Running     0               32s
   ```
2. SSH to Service Registry pod using `oc rsh` command and find JVM truststore/keystore path in the container with `ls -l $JAVA_HOME/lib/security/` command. Look for the `cacerts` file which is the default JVM truststore/keystore file.

   However, in this case, the `cacerts` file is a symbolic link to `/etc/pki/java/cacerts` file which is another symbolic link to `/etc/pki/ca-trust/extracted/java/cacerts` file which is the file that we need to copy from container.

   ```
   oc rsh <POD_NAME>
   ```

   ```
   ls -l $JAVA_HOME/lib/security/
   ```

   Sample output:

   ```
   $ oc rsh service-registry-deployment-79bd796c6b-5tpdg
   sh-4.4$ ls -l $JAVA_HOME/lib/security/
   total 244
   -rw-r--r--. 1 root root   2488 Oct 15 23:15 blocked.certs
   lrwxrwxrwx. 1 root root     21 Oct 15 23:17 cacerts -> /etc/pki/java/cacerts
   -rw-r--r--. 1 root root   9694 Oct 15 23:15 default.policy
   -rw-r--r--. 1 root root 232158 Oct 15 23:15 public_suffix_list.dat
   sh-4.4$
   sh-4.4$ ls -l /etc/pki/java/cacerts
   lrwxrwxrwx. 1 root root 40 Jul 28 18:59 /etc/pki/java/cacerts -> /etc/pki/ca-trust/extracted/java/cacerts
   sh-4.4$
   sh-4.4$ ls -l /etc/pki/ca-trust/extracted/java/cacerts
   -r--r--r--. 1 root root 156478 Oct 24 14:41 /etc/pki/ca-trust/extracted/java/cacerts
   sh-4.4$
   sh-4.4$ exit
   ```
3. Use `oc rsync` command to copy file from Servie Registry container.

   ```
   oc rsh <POD_NAME>:<PATH_TO_FILE_IN_CONTAINER> <LOCAL_HOST_PATH>
   ```

   Sample output:

   ```
   $ oc rsync service-registry-deployment-79bd796c6b-5tpdg:/etc/pki/ca-trust/extracted/java/cacerts ~/Temp
   receiving file list ... done
   cacerts

   sent 38 bytes  received 156602 bytes  313280.00 bytes/sec
   total size is 156478  speedup is 1.00
   ```
4. Add self-signed certificate to the `cacerts` file with following command line or [GUI tool](https://keystore-explorer.org/).

   ```
   $JDK_HOME/bin/keytool -importcert -file $CERT -alias $ALIAS -keystore cacerts -storepass changeit
   ```

   * Replace `$JDK_HOME` with your actual JDK home path.
   * Replace `$CERT` with the path to your certificate the you previously installed to the system.
   * Replace `$ALIAS` with the preferred alias to be used in the keystore.
   * Note that `changeit` is the default password for Java's cacerts file.
5. Create a Secret object for the `cacerts` truststore file.

   ![Create a Secret object](/files/BkLa5E2A8Xbbn5PAvn8B)

   ![Create a Secret object](/files/XNEXuxZtBU3nAjozcN3X)

   **Note.** If you encounter a `java.io.IOException: Invalid keystore format` error in Service Registry container log, the upload of the binary file did not work properly. As an alternative, encode the file as a base64 string using `cat registry-keystore.jks | base64 -w0 > data.txt` and edit the Secret resource as yaml to manually add the encoded file.
6. Add the Secret to Service Registry Deployment.

   ![Add the Secret object to Service Registry Deployment](/files/6EFHqmY0qeaELrCfpYv8)
7. You'll be directed to the Service Registry Deployment page.

   ![Service Registry Deployment](/files/pYV0tjV7f5Evjznr6eBo)
8. Go to **Environment** tab and add two new environment variables as screenshot below.

   * `TRUSTSTORE_PASSWORD` environment variable value is read from the Secret object you've created above.
   * `JAVA_OPTIONS` environment value is `-Djavax.net.ssl.trustStore=/etc/pki/java/custom/truststore -Djavax.net.ssl.trustStorePassword=$(TRUSTSTORE_PASSWORD)`

   ![Add TRUSTSTORE\_PASSWORD environment variable](/files/G5lyXfrnuE65yxEiwCf8)

   ![Add JAVA\_OPTIONS environment variable](/files/dvAA3aXliDVcfJl0ucVE)
9. After new pods are created, open one of the and go to **Terminal** tab then type `ls -l /etc/pki/java/custom/` command. You should see the `truststore` file which is mounted from the Secret object.

   ![Truststore file is mounted to container](/files/yQs7FNDQ1C1FgVKllQCz)
10. Go to **Logs** tab, you should see the value of `JAVA_OPTIONS` environment variable get added as the `java` command arguments. And the application should start without any error about certificate.

    ![JAVA\_OPTIONS is added as one of java command arguments](/files/xzOGjmoWMJuHDGuJXJtb)

## References

* [Import a certificate to the Java Keystore](https://docs.plm.automation.siemens.com/content/polarion/19.3/help/en_US/polarion_windows_installation/manually_updating_third_party_software/import_a_certificate_to_the_java_keystore.html)
* [How to Import a .cer Certificate into a Java KeyStore](https://www.geeksforgeeks.org/how-to-import-a-cer-certificate-into-a-java-keystore/)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://audomsak.gitbook.io/red-hat-service-registry/appendix/self-signed-cert.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
