Custom CA certificates for Java workloads¶
For shared corporate or private CA roots, build the certificates into a
platform-owned JDK source image and select that JDK distribution explicitly.
This works with today's JavaApplication API, preserves JAR-only application
images, and uses Brewlet's existing digest-pinned JDK provisioning workflow.
This guide configures the default Java TLS trust used for outbound connections, such as HTTPS. It does not configure server certificates, mutual-TLS private keys, containerd registry trust, or the Brewlet admission webhook's certificates. Libraries that create their own TLS context may need separate configuration.
Related: JDK management · Deploying workloads · Security.
Build a JDK image containing the approved CA roots¶
Obtain the CA certificate through your organization's trusted distribution channel and verify its SHA-256 fingerprint out of band before importing it. Import only approved trust anchors, not a server's leaf certificate as a shortcut around TLS verification.
The following Dockerfile extends Temurin 21's existing cacerts, retaining its
public roots. Replace the base digest placeholder with a reviewed digest:
FROM docker.io/library/eclipse-temurin@sha256:<reviewed-temurin-21-digest>
COPY corporate-root-ca.pem /tmp/corporate-root-ca.pem
RUN "$JAVA_HOME/bin/keytool" -importcert -noprompt \
-cacerts -storepass changeit \
-alias corporate-root-ca \
-file /tmp/corporate-root-ca.pem \
&& "$JAVA_HOME/bin/keytool" -list -cacerts -storepass changeit \
-alias corporate-root-ca \
&& rm /tmp/corporate-root-ca.pem
Use a unique alias and import each approved root separately. changeit is the
upstream example truststore's integrity password, not an application credential;
adapt it if your base uses another password. This image must not contain private
keys or application secrets.
Build and publish this as a JDK source image, not a Brewlet application image. For example, replacing the registry destination with your own:
docker buildx build --platform linux/amd64,linux/arm64 \
-t registry.example.com/platform/temurin-corporate:21 --push .
docker buildx imagetools inspect registry.example.com/platform/temurin-corporate:21
Publish only the architectures you operate and confirm that the base supports them. Review the resulting image/index digest and use that digest below.
Perform certificate installation at build time. Brewlet copies the JDK source image's complete userland and launches Java directly; it does not run the image's normal entrypoint. Entrypoint-based CA import or OS trust-update scripts will not run. Updating the OS PEM bundle alone also does not guarantee that Java's default truststore changes.
Register and select the JDK¶
Add the derived image to the existing profile that owns your node pool. For a
Helm-managed profile, merge this entry into provisioner.jdks, retaining the
other JDKs your workloads need:
provisioner:
jdks:
- distribution: temurin-corporate
feature: 21
source:
image: registry.example.com/platform/temurin-corporate@sha256:<reviewed-image-digest>
javaHome: /opt/java/openjdk
For a directly managed NodeProfile, the same entry goes in spec.jdks.
Follow the existing JDK provisioning workflow;
do not create an overlapping profile or edit provisioned files on the host.
Once the selected nodes advertise the new JDK as ready, select it in your application descriptor:
apiVersion: apps.brewlet.sh/v1alpha1
kind: JavaApplication
metadata:
name: orders
spec:
artifact:
image: registry.example.com/demo/orders@sha256:<application-image-digest>
jvm:
version: 21
distribution: temurin-corporate
For a raw Pod or Deployment, use the Pod annotation
brewlet.sh/jdk: "temurin-corporate-21" instead.
No javax.net.ssl.trustStore flags are needed: Java uses this JDK's default
truststore, provided the application has not selected another one. Check for
existing truststore overrides, a jssecacerts file (which takes precedence over
cacerts), or framework-specific TLS configuration.
Pin both version and distribution. A bare version: 21 may select a different
JDK; adding a distribution can also change selection for other unpinned
workloads. See JDK selection.
Verify and rotate¶
Before rollout, inspect the imported aliases/fingerprints and exercise an actual TLS connection from the application to the intended private endpoint. Confirm that required public endpoints still work and that an endpoint signed by an untrusted CA fails. Listing certificates alone does not establish that the application's HTTP client uses that truststore.
Rotate roots like a JDK patch: rebuild from the current approved JDK base, publish a new digest, update the profile, wait for node readiness, and restart the affected workloads. Existing Pods retain their old JDK root; a source-image update does not change their running truststore. Default Java TLS contexts should not be assumed to reload trust automatically.
For a planned CA migration, first distribute both old and new roots, restart clients, then switch servers. Remove the old root in a subsequent image and workload rollout after migration. A compromised CA may require immediate removal instead, following your incident-response policy.
When trust must be application-specific¶
Today's JavaApplication CRD exposes spec.jvm.args but not volumes,
volume mounts, or a truststore field. Do not add those unsupported fields or
patch the operator-owned Deployment as a durable configuration mechanism.
Use a separately managed raw Pod/Deployment if you need a per-application
truststore now: mount a prebuilt JKS or PKCS12 file from a same-namespace Secret
or ConfigMap, read-only at a dedicated path such as /etc/java-trust, and pass
javax.net.ssl.trustStore, javax.net.ssl.trustStoreType, and, when required,
javax.net.ssl.trustStorePassword through the brewlet.sh/jvm-args annotation.
Build the store outside the Pod; the current handler does not support an
ordinary-image init container that runs keytool.
An explicit truststore replaces, rather than augments, Java's default
truststore. Include public roots yourself if required, and maintain them as the
JDK's defaults evolve. Never put private-key passwords in JVM annotations or
JAVA_TOOL_OPTIONS; those surfaces can expose values through manifests, process
arguments, or logs.
Proposal 0008 describes a possible first-class per-application truststore API. It is not implemented.