Skip to main content

mTLS Certificate Setup and Custom CA

This page covers the steps and configuration options that are common to all Witboost services that support mutual TLS (mTLS): the Provisioning Coordinator, the Computational Governance Platform (WCG), and the Knowledge Graph Manager (KGM).

Refer to the guide for your specific service for service-specific Helm values, application configuration, and any unique options:

warning

This guide is intended for platform engineers or administrators configuring secure integrations. It requires knowledge of certificates, secret managers, and Helm deployments.

What is mTLS?

Mutual TLS (mTLS) extends standard TLS by requiring both sides of a connection to authenticate with a certificate:

  • The client (e.g. the Coordinator, WCG, or KGM) presents a client certificate to prove its identity to the remote server.
  • The server presents its own certificate, and the client verifies it against a trusted Certificate Authority (CA).

This mutual authentication prevents both impersonation of the client and man-in-the-middle attacks on the server.

Create a Client Certificate

Certificate + private key — both are required

In mTLS, a "client certificate" is not just the certificate file. It is the combination of two pieces:

  • The X.509 certificate — a public document containing your identity and public key, signed by a Certificate Authority.
  • The private key — a secret that proves you own that certificate. Without it, the client cannot complete the TLS handshake, regardless of having the certificate.

When this guide refers to a "client certificate", it means both together. You will package them into a single PKCS#12 (.p12) file in the steps below.

All Witboost services that use mTLS require a client certificate with the following X.509 extensions:

ExtensionRequired ValueMeaning
Key UsageDigital SignatureThe key can be used to sign data
Extended Key UsageTLS Web Client AuthenticationThe certificate can be used by a client in a TLS session. Prevents misuse (e.g. using a server certificate as a client certificate)
Basic ConstraintsCA:FALSEThe certificate is an end-entity certificate, not a CA. Ensures it cannot issue other certificates or impersonate a CA

Verify your certificate

Run:

openssl x509 -in client.crt -text

Look for the X509v3 extensions section and confirm the above values are present.

Package as PKCS#12

All Witboost services expect a .p12 file containing certificate + private key:

openssl pkcs12 -export \
-in client.crt \
-inkey client.key \
-out client.p12 \
-name "witboost-client"
note

When you run this command, OpenSSL will prompt you to set an export password. This password protects the .p12 file itself. You will need to provide it later when configuring the service — store it securely.

Store the Certificate in your Secret Manager

Upload client.p12 (as binary content) to a secret in your organization's secret manager under the key client.p12.

tip

Refer to the Witboost Installation guide for details on secrets and the secret manager integration.

Note the name you give this secret — you will reference it in remoteSecretName in your service's Helm configuration.

Enable the Client Certificate in Helm

In the values.yaml provided to the Witboost Helm Chart, enable the client certificate and reference the secret that holds it:

<service-helm-key>:
useClientCertificate:
enabled: true
remoteSecretName: '<secret-name>' # CHANGE ME — name in your secret manager

Replace <service-helm-key> with the key for your service. When enabled: true and remoteSecretName is set, the umbrella chart's ExternalSecret fetches all keys from remoteSecretName and creates a Kubernetes Secret in the cluster. That secret is then mounted into the pod at /opt/docker/etc/tls/client.p12 (accessible as etc/tls/client.p12 from the application working directory).

ServiceHelm keyCreated Kubernetes Secret
Provisioning Coordinatorprovisioning-coordinatorwitboost-pc-cert-secret
WCGgovernance-platformwitboost-governance-cert-secret
KGMkgmwitboost-kgm-cert-secret

(Optional) Use an existing Kubernetes Secret instead

If the certificate already exists as a Kubernetes Secret (for example, created by cert-manager or managed separately), you can mount it directly without going through the ExternalSecret flow:

<service-helm-key>:
useClientCertificate:
enabled: true
tlsCertSecretName: '<k8s-secret>' # CHANGE ME — name of your existing K8s Secret

When tlsCertSecretName is set, remoteSecretName is not required and no ExternalSecret is created for the certificate. The deployment mounts tlsCertSecretName directly at /opt/docker/etc/tls/client.p12.

note

The referenced Kubernetes Secret must exist in the namespace and contain a key named client.p12.

Custom CA Configuration

Enable this only if the remote servers the service connects to use a private or internal Certificate Authority that is not trusted by the default JVM truststore.

Each service supports three ways of supplying the CA certificate. Exactly one must be set when customCA.enabled: true. Setting multiple options simultaneously or setting none will cause a Helm render error.

The table below shows the Helm key and the auto-created Kubernetes Secret name for each service:

ServiceHelm keyAuto-created Secret name (Options B & C)
Provisioning Coordinatorprovisioning-coordinatorcoordinator-ca-certificate
WCGgovernance-platformgovernance-ca-certificate
KGMkgmkgm-ca-certificate
UI backenduica-certificate

In the examples below, replace <service-helm-key> with the value for your service from the table above.

Option A — Use an existing Kubernetes Secret

<service-helm-key>:
customCA:
enabled: true
# Pre-existing Kubernetes Secret containing the CA certificate.
# The Secret must contain the key specified by secretKey (default: cacert.crt).
secretName: '<secret-name>' # CHANGE ME
# secretKey: 'cacert.crt' # OPTIONAL — change only if your Secret uses a different key name

When using Option A, the chart uses the Secret you reference directly without creating a new one.

Option B — Provide a base64-encoded certificate inline

<service-helm-key>:
customCA:
enabled: true
caCrtBase64: '<base64-of-cacert.crt>' # CHANGE ME

Option C — Provide a certificate file at Helm render time (Deprecated)

Deprecated

caCrtFilePath is deprecated and will be removed in a future major version. The certificate file must be placed inside the helm/files/ directory within the relevant sub-chart before running helm upgrade.

Migrate to Option A (existing Secret) or Option B (base64 inline) instead.

<service-helm-key>:
customCA:
enabled: true
caCrtFilePath: 'files/cacert.crt' # CHANGE ME — path relative to the sub-chart root

How the CA is applied

The mechanism differs by service type:

JVM-based services (Provisioning Coordinator, WCG, KGM): An init container runs before the service starts. It copies the JVM default truststore and imports the CA certificate using keytool, so the service can verify TLS certificates presented by downstream servers during the handshake.

UI backend (Node.js): The chart mounts the CA certificate at /ca/cacert.crt inside the container and sets CA_CERTIFICATE_PATH and USE_CUSTOM_CA environment variables. The Node.js backend reads the certificate directly from the filesystem when establishing HTTPS connections — no init container is needed.