# Custom CA Certificates (Java)

LLMS index: [llms.txt](https://hummingbird-project.io/llms.txt) | Full content: [llms-full.txt](https://hummingbird-project.io/llms-full.txt)

---

## Overview

You can configure Java-based container images (openjdk, etc.) to trust custom Certificate Authority (CA) certificates for TLS connections. Java uses its own truststore format (PKCS12) rather than PEM files.

Java keystores require a password for integrity checking. The system truststore uses the standard password `changeit`, which is a well-known default used for tamper detection rather than confidentiality.

## Volume Mount Approach

Create a custom truststore using the `keytool` command. You can either trust only your specific CAs (for internal-only applications) or merge with the default public CAs (typical for applications connecting to both internal and external services).

```bash
CERTDIR=$(mktemp -d)  # or use a persistent directory for repeated runs
chmod 777 "$CERTDIR"  # to work with non-privileged containers

# OPTIONAL: Copy the default Java truststore to merge with public CAs
# Skip this step to trust ONLY your custom CAs
podman run --rm -v "${CERTDIR}:/work:Z" \
  registry.access.redhat.com/hi/openjdk:latest \
  cp /etc/pki/ca-trust/extracted/java/cacerts /work/cacerts

# Import your custom CA
podman run --rm -v "${CERTDIR}:/work:Z" \
  registry.access.redhat.com/hi/openjdk:latest \
  keytool -import -noprompt -trustcacerts -alias my-custom-ca \
    -file /work/my-ca.crt \
    -keystore /work/cacerts \
    -storepass changeit -storetype PKCS12 \
    -J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE
```

The `-storetype PKCS12` and `-J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE` flags
are required for compatibility with FIPS images. The system truststore is PKCS12 format
with unencrypted certificate entries (generated by `p11-kit`). Without these flags,
`keytool` defaults to PBE-encrypted certificate bags that the FIPS security provider
cannot decrypt.

### Podman Example

Mount the custom truststore to the system location:

```bash
podman run --rm \
  -v "${CERTDIR}/cacerts:/etc/pki/ca-trust/extracted/java/cacerts:ro,Z" \
  registry.access.redhat.com/hi/openjdk:latest \
  java -jar myapp.jar
```

### Kubernetes Example

In Kubernetes, use an init container to create the truststore, then share it via an emptyDir volume:

```yaml
apiVersion: v1
kind: ConfigMap
metadata:
  name: custom-ca
data:
  ca.crt: |
    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE-----
---
apiVersion: v1
kind: Pod
spec:
  initContainers:
  - name: prepare-truststore
    image: registry.access.redhat.com/hi/openjdk:latest
    command: ["sh", "-c"]
    args:
    - |
      # OPTIONAL: Copy the default truststore to merge with public CAs
      # Skip this line to trust ONLY your custom CAs
      cp /etc/pki/ca-trust/extracted/java/cacerts /truststore/cacerts
      chmod 666 /truststore/cacerts
      keytool -import -noprompt -trustcacerts -alias custom-ca \
        -file /ca/ca.crt -keystore /truststore/cacerts \
        -storepass changeit -storetype PKCS12 \
        -J-Dkeystore.pkcs12.certProtectionAlgorithm=NONE
    volumeMounts:
    - name: custom-ca
      mountPath: /ca
    - name: truststore
      mountPath: /truststore
  containers:
  - name: app
    image: registry.access.redhat.com/hi/openjdk:latest
    volumeMounts:
    - name: truststore
      mountPath: /etc/pki/ca-trust/extracted/java
      readOnly: true
  volumes:
  - name: custom-ca
    configMap:
      name: custom-ca
  - name: truststore
    emptyDir: {}
```

For the trust-only-specific-CAs approach, omit the `cp` command and create the keystore directly with `keytool -import`.

## Derived Image Approach

Use this approach when it's more practical to bake the certificates into the image instead of generating the truststore on each container startup. This creates a new image with a merged trust store with the `trust anchor` command.

Create a multi-stage Containerfile with your `ca.crt` in the build context. This example derives from the `openjdk` image:

```dockerfile
FROM registry.access.redhat.com/hi/openjdk:latest-builder AS builder

USER root
COPY ca.crt /tmp/
RUN trust anchor /tmp/ca.crt

FROM registry.access.redhat.com/hi/openjdk:latest
COPY --from=builder /etc/pki /etc/pki
```

Build and use your custom image:

```bash
podman build -t my-openjdk-with-ca .
podman run --rm my-openjdk-with-ca java -jar myapp.jar
```
