TLS and custom CAs
Use TLS for public HTTP and gRPC endpoints and for connections to external dependencies. Certificates must be valid for the DNS names actually used by clients and Koldan pods.
Prerequisites
Prepare the public endpoint names, certificate chain, unencrypted PEM private key where the chart must terminate TLS, issuing CA bundle, renewal owner, and an overlap plan for CA rotation. Confirm whether TLS terminates at an Ingress controller, an OpenShift Route, or the Koldan gRPC service before changing values.
Public HTTP TLS
For Kubernetes Ingress, create a TLS Secret through the cluster's certificate controller or your approved secret process, then reference it from web.ingress.tls:
web:
ingress:
enabled: true
hosts:
- host: api.example.net
paths:
- path: /
pathType: Prefix
tls:
- secretName: koldan-web-tls
hosts:
- api.example.net
The referenced Secret must be in the Koldan namespace. Renewing that Secret is normally the responsibility of the certificate controller or operator that owns it.
For OpenShift, configure web.route.tls. Route TLS fields can contain certificate material directly and therefore become part of Helm release data. Prefer a platform-managed certificate when your Route configuration and organizational controls allow it.
Public gRPC TLS
When Koldan terminates gRPC TLS, enable the chart-managed certificate:
The chart creates a Kubernetes Secret and configures the gRPC service to use the PEM files. Both populated values also remain in Helm release data. Protect the source values and release objects as secrets. When an OpenShift Route terminates gRPC TLS instead, configure grpc.route.tls consistently with the selected edge, re-encrypt, or passthrough mode.
The application-property reference lists the supported koldan.api-grpc.ssl.* PEM and PKCS12 settings for deployments that provide their own mounted certificate files. Do not set both chart-managed PEM values and a separate application TLS configuration unless the resulting file paths and termination model have been deliberately reconciled.
Trust a private CA
Add PEM-encoded issuing certificates under customCA.data when PostgreSQL, Temporal, S3, OIDC, an LLM provider, or another required service uses a private CA:
customCA:
enabled: true
data:
organization-root.pem: |
<PEM CA certificate>
organization-intermediate.pem: |
<PEM intermediate CA certificate>
The chart stores these files in a Kubernetes Secret and mounts them at /mnt/trust-certs in supported Koldan workloads. Include only CA certificates needed to build the serving chain. Never place a private key in customCA.data.
customCA supplies outbound trust; it does not configure an Ingress, Route, or gRPC serving certificate. It also does not alter third-party dependency pods installed by their own subcharts. Configure trust for those dependencies through their supported interfaces.
Trust a private PostgreSQL CA from Temporal
When using self-managed Temporal from Koldan helm chart, it does not use Koldan's CA truststore. When the bundled Temporal deployment connects to PostgreSQL through TLS, mount the chart-managed custom-CA Secret into both the Temporal server and admin-tools workloads, then reference the mounted CA explicitly from every SQL datastore.
customCA:
enabled: true
data:
postgresql-ca.pem: |
<PEM PostgreSQL issuing CA chain>
temporal:
install: true
server:
additionalVolumes:
- name: koldan-custom-ca
secret:
# For a release named "koldan". Use the rendered
# <Koldan fullname>-custom-ca-certs name for another release.
secretName: koldan-custom-ca-certs
additionalVolumeMounts:
- name: koldan-custom-ca
mountPath: /mnt/trust-certs
readOnly: true
config:
persistence:
datastores:
default:
sql:
tls:
enabled: true
caFile: /mnt/trust-certs/postgresql-ca.pem
serverName: postgresql.example.internal
enableHostVerification: true
visibility:
sql:
tls:
enabled: true
caFile: /mnt/trust-certs/postgresql-ca.pem
serverName: postgresql.example.internal
enableHostVerification: true
admintools:
additionalVolumes:
- name: koldan-custom-ca
secret:
secretName: koldan-custom-ca-certs
additionalVolumeMounts:
- name: koldan-custom-ca
mountPath: /mnt/trust-certs
readOnly: true
Set serverName to a DNS SAN in the PostgreSQL serving certificate and keep enableHostVerification: true.
Verify
Before rollout, verify that the certificate matches its key and includes every required SAN. From a network location equivalent to the relevant client or pod, inspect each endpoint without printing private material:
openssl s_client -connect api.example.net:443 -servername api.example.net -verify_return_error </dev/null
openssl s_client -connect grpc.example.net:443 -servername grpc.example.net -alpn h2 -verify_return_error </dev/null
After the Helm upgrade:
- Confirm the public HTTP certificate, chain, hostname, and expiry.
- Confirm the gRPC path negotiates HTTP/2 and presents the intended certificate.
- Test OIDC discovery and login, PostgreSQL, Temporal, S3, and enabled provider connections from the Koldan namespace.
- Confirm affected pods restarted and became Ready. Updating a mounted Secret alone does not guarantee that an application has reloaded trust material.
Rotate certificates and CAs
- Add the new CA certificate while retaining the old CA.
- Apply the values and restart every workload that makes connections through that trust path.
- Verify that both old and new serving chains are accepted.
- Rotate serving certificates and confirm HTTP, gRPC, OIDC, PostgreSQL, Temporal, S3, and provider operations.
- Remove the old CA only after every server and client has moved, then restart and verify again.
For an emergency rollback, restore the prior serving certificate and key as a matched pair and retain both trust anchors until connectivity is stable.
| Symptom | Likely cause and recovery |
|---|---|
| Hostname verification fails | The connected DNS name is absent from the SAN; issue a corrected certificate rather than disabling verification |
| Unknown issuer or path-building error | Missing root/intermediate certificate, wrong CA bundle, or workload not restarted after the bundle changed |
| Private key does not match certificate | Restore the matched pair and repeat the rotation |
| Browser works but gRPC fails | gRPC endpoint, HTTP/2/ALPN, Route termination mode, or gRPC certificate is configured differently from HTTP |
| Only a bundled dependency fails | That subchart does not consume Koldan's customCA; configure its trust separately |