Trusting custom or self-signed certificates (Docker/Podman)

Build and mount a Java trust store so CAST Imaging components running on Docker/Podman trust internal or self-signed certificates for repositories, proxies, SSO, and Extend

Overview

Available in ≥ 3.6.1-funcrel

Starting with 3.6.1-funcrel, CAST Imaging is delivered as hardened Docker/Podman images - minimal images that contain only what is required to run the application. Because these images do not include a shell or package manager, you cannot import certificates into them interactively.

This page explains how to build a Java trust store from the certificates already bundled in the image, add your own certificate to it, and mount it into the relevant CAST Imaging components. Do this when the components need to trust an internal or self-signed certificate authority (CA) for outbound connections, for example:

  • a Nexus/Maven or .NET artifact repository,
  • an intercepting HTTPS proxy,
  • AIP SSO,
  • CAST Extend.

The instructions apply to the Imaging Services components (control-panel, console, auth-service, gateway) and to the analysis-node.

Prerequisites

  • A certificate to trust, referred to as self_signed_cert.crt below. This can be the public certificate of the associated key or a CA certificate.
  • Access to the Docker (or Podman) CLI, and the ability to pull a CAST Imaging image locally.
  • The ability to mount a local folder into a container.

Step 1 - Build the trust store

Start a container with a local folder mounted, and call the bundled keytool to create a new trust store from the cacerts file inside the image:

$ docker run --rm -it --entrypoint keytool -v ./:/certs docker.io/castimaging/auth-service:<version> -importkeystore -srckeystore /usr/lib/jvm/temurin-25/lib/security/cacerts -destkeystore /certs/new_trust_store.p12 -srcstoretype PKCS12 -deststoretype PKCS12

You are prompted three times - twice to set and confirm the password for the new trust store, and once for the current password of the source cacerts (which defaults to changeit):

Enter destination keystore password:
Re-enter new password:
Enter source keystore password:

This creates a new_trust_store.p12 file in the current folder containing a copy of the certificates from the image’s Java distribution.

Notes:

  • Podman with SELinux: mounting ./ may fail. Instead, create a named volume (podman volume create my_volume_name) and mount it in place of ./ in the command above. Use podman inspect my_volume_name to locate the volume on disk if you want to copy the trust store out, or keep it in the volume to mount into the other containers later.
  • The certificates in cacerts eventually expire. If trust errors start occurring, rebuild the trust store. Tools such as keytool can list certificates and their expiry dates.

Step 2 - Import your certificate

Reuse the bundled keytool to import your certificate into the trust store created above:

$ docker run --rm -it --entrypoint keytool -v ./:/certs docker.io/castimaging/auth-service:<version> -importcert -alias nexus-cert -file /certs/self_signed_cert.crt -keystore /certs/new_trust_store.p12

You are prompted for the trust store password and whether to trust the certificate. Sample (trimmed) output:

Enter keystore password:
Owner: CN=, OU=, O=, L=, ST=, C=
Issuer: CN=, OU=, O=, L=, ST=, C=
Serial number: 4acf945a4c5a3c51
...
Trust this certificate? [no]:  yes
Certificate was added to keystore

Notes:

  • Accepted certificate file extensions are .pem, .crt, and .cer. Other extensions may work but have not been tested.
  • If you have another trust store rather than a single certificate, you can merge the two together - see the keytool documentation.
  • Podman with SELinux: copy your certificate into the volume folder before running the command. Use podman inspect my_volume_name to find the folder location.

Step 3 - Mount the trust store for Imaging Services

To make the components use the new trust store, add the trust store folder and JVM options to the .env file, then reference them from a docker-compose.override.yml file so that your changes persist across updates. See also Managing docker-compose.yml files and Managing .env files.

Edit /opt/cast/installation/imaging-services/.env and add:

# Path to the folder containing the new_trust_store (or the volume name)
JAVA_SSL_HOST_FOLDER=/path/to/folder
# Java options to customize the trust store used by the JVM
JAVA_SSL_OPTIONS="-Djavax.net.ssl.trustStore=/certs/new_trust_store.p12 -Djavax.net.ssl.trustStorePassword=********** -Djavax.net.ssl.trustStoreType=pkcs12"

Replace /path/to/folder with your host folder (or volume name), and set trustStorePassword to the trust store password you chose in Step 1.

Then create (or edit) /opt/cast/installation/imaging-services/docker-compose.override.yml and enable the trust store for the services that need it:

services:
  control-panel:
    volumes:
      - ${JAVA_SSL_HOST_FOLDER}:/certs
    environment:
      - JDK_JAVA_OPTIONS=${JAVA_SSL_OPTIONS}
#  auth-service:
#    volumes:
#      - ${JAVA_SSL_HOST_FOLDER}:/certs
#    environment:
#      - JDK_JAVA_OPTIONS=${JAVA_SSL_OPTIONS}
#  gateway:
#    volumes:
#      - ${JAVA_SSL_HOST_FOLDER}:/certs
#    environment:
#      - JDK_JAVA_OPTIONS=${JAVA_SSL_OPTIONS}
  console:
    volumes:
      - ${JAVA_SSL_HOST_FOLDER}:/certs
    environment:
      - JDK_JAVA_OPTIONS=${JAVA_SSL_OPTIONS}

Enable only the services that need the certificate. In this example auth-service and gateway are commented out because a Nexus repository is reached by control-panel and console. For a certificate used elsewhere (for example a self-signed certificate in AIP SSO), uncomment auth-service and gateway as required.

Restart the components so the change is taken into account:

$ cd /opt/cast/installation/imaging-services   # navigate to the installation folder
$ sudo docker compose down                     # stop the containers
$ sudo docker compose up -d                    # start the containers in detached mode
$ sudo docker ps                               # check the containers are running

Step 4 - Mount the trust store for the Analysis Node

The procedure is the same as for Imaging Services - only the folder changes.

Edit /opt/cast/installation/imaging-node/.env and add the same two variables:

# Path to the folder containing the new_trust_store (or the volume name)
JAVA_SSL_HOST_FOLDER=/path/to/folder
# Java options to customize the trust store used by the JVM
JAVA_SSL_OPTIONS="-Djavax.net.ssl.trustStore=/certs/new_trust_store.p12 -Djavax.net.ssl.trustStorePassword=********** -Djavax.net.ssl.trustStoreType=pkcs12"

Then create (or edit) /opt/cast/installation/imaging-node/docker-compose.override.yml:

services:
  analysis-node:
    volumes:
      - ${JAVA_SSL_HOST_FOLDER}:/certs
    environment:
      - JDK_JAVA_OPTIONS=${JAVA_SSL_OPTIONS}

Restart the node with the same docker compose down / docker compose up -d sequence shown above, run from /opt/cast/installation/imaging-node.

Verify

Start the components and confirm that the target connection now works - for example that the Nexus repository is reachable from CAST Imaging - and that no TLS or PKIX path building failed errors appear in the logs of the affected services.