feat: generate TLS certificates using cert-manager - #820
Conversation
|
|
|
Hello @robholland @tomwheeler @PhillypHenning Please review this PR. Thanks. |
Hello @robholland @tomwheeler @PhillypHenning |
| @@ -0,0 +1,90 @@ | |||
| server: | |||
| additionalVolumeMounts: | |||
There was a problem hiding this comment.
Can we automate these volumes/volumeMounts via helpers so that the user doesn't need to include them in their values? They are all boiler plate as the variable names and locations are all determined by Temporal itself. We can use a server.tls or similar values structure that mixes in the relevant volumes/mounts alongside any additional* the user has set. Likewise web.tls.
| secret: | ||
| secretName: temporal-tls-certs | ||
| config: | ||
| tls: |
There was a problem hiding this comment.
We can build config.tls automatically based on interpreting a more concise server.tls stanza also. Most of this is also boiler plate, just not sure about requireClientAuth and serverName for example. I defer to your knowledge of what should be customisable there.
| className: "" | ||
| hosts: | ||
| - "" | ||
| additionalSecrets: |
There was a problem hiding this comment.
Are these basically placeholders that cert-manager updates?
| tls.key: | | ||
| -----BEGIN EC PRIVATE KEY----- | ||
| -----END EC PRIVATE KEY----- | ||
| certificates: |
There was a problem hiding this comment.
Ah, maybe we add the volumes/mounts based on this block? Not sure if need to have server. and web. variants though, would it be valid to want cert manager for one but not the other?
|
Closing in favour of #954, inspired by your work. Thanks for the time you spent on this! |
* feat(server,web): add server.tls/web.tls wiring for TLS certificates
Adds concise `server.tls` (internode/frontend) and `web.tls` stanzas that,
given an existing kubernetes.io/tls secret, automatically:
* mount the secret into the server/web pods (volumes + volumeMounts), and
* generate the matching `server.config.tls` block and Web UI TEMPORAL_TLS_*
environment variables.
Users no longer hand-write the volume/mount/config boilerplate that TLS
previously required. Anything set under `server.config.tls` is deep-merged on
top of the generated config, so individual fields stay overridable and existing
config.tls-only setups keep working unchanged.
Certificate issuance is intentionally left out of the chart: it is cluster- and
CA-policy specific and cert-manager already models it well. The new
values/values.tls.yaml example shows the recommended end-to-end setup, creating
the cert-manager Issuer/Certificate resources via the existing `extraObjects`
escape hatch and wiring the resulting secrets in with `server.tls`/`web.tls`.
Any cert source that produces a secret (external-secrets, Vault, manual) works
the same way.
This is a simpler alternative to #820, which templated cert-manager CRDs and a
TLS secret directly in the chart.
* test(ci): exercise a cert-manager TLS setup in CI
Adds an end-to-end CI case for the server.tls/web.tls wiring:
* .github/workflows/ci.yml installs cert-manager (helm, --wait) into the kind
cluster before `ct install`, so the Issuer/Certificate resources can be
admitted.
* ci/postgres-tls-values.yaml is a new `ct install` case: postgres backend +
cert-manager issuance (via extraObjects) + internode/frontend/web TLS. Its
serverName values are self-consistent SANs, so it works under ct's generated
release names. `ct install` installs it, then `helm test` runs the bundled
cluster-health check over TLS.
For that health check (and the namespace-setup job) to talk to a TLS frontend,
the chart's own `temporal` CLI pods now speak TLS too: a shared
`temporal.frontendClient.tls.*` helper mounts the frontend secret and sets the
CLI's TEMPORAL_TLS_* env, wired into test.yaml and server-namespace-job.yaml
(the latter only when it targets the in-cluster frontend, not internal-frontend
or an ingress host). Without this, enabling frontend TLS silently broke the
namespace job and the health test.
Verified end-to-end against a real cluster: cert-manager issued the chain
(leaf certs carry the expected SAN and server+client EKUs), the cluster formed
over mutual internode TLS, the namespace job registered a namespace over
frontend TLS, and `helm test` reported SERVING.
* feat(tls): require serverName when host verification is in effect
Enabling server.tls.internode or server.tls.frontend now requires a
serverName, and web.tls requires one when enableHostVerification is
true. Host verification is always on for these paths, so an empty
serverName either silently downgraded the CLI clients to no host
verification or left the server's own client config verifying against an
empty name.
Drop the implicit "no serverName -> TEMPORAL_TLS_DISABLE_HOST_VERIFICATION"
fallback from the frontend-client wiring; a missing serverName is now a
clear template error instead of a silent, inconsistent downgrade.
* style(ci): add trailing newline to ci.yml
* feat(admintools): wire admin CLI pods for TLS with internal-frontend default and external toggle
The admin tools Deployment and the namespace-setup Job are `temporal` CLI
clients. Both default to the internal-frontend when it is enabled — a
one-off/administrative path that grants admin without an external
Authorizer — and use the external frontend otherwise. Two toggles route
them through the external frontend instead:
* admintools.useExternalFrontend
* server.config.namespaces.useExternalFrontend
Client TLS for both, and for the cluster-health test, is wired by a shared
temporal.adminClient.tls.* helper. The internal-frontend terminates TLS
with the internode config and the external frontend with the frontend
config, so the helper mounts the matching secret (server.tls.internode vs
server.tls.frontend), sets serverName, and presents a client certificate
when that section requires client auth (internode defaults to mTLS). Certs
mount at a fixed /etc/temporal/tls/client. The admin tools Deployment was
not previously wired for TLS at all.
TLS wiring is skipped when a custom admintools.temporalAddress is set, or
when the Job targets an external ingress host, since the chart cannot know
the certificate in those cases. A CI case exercises the internal-frontend
setup end to end.
* fix(tls): present client cert and clientCaFiles for mutual TLS
The frontend/admin-client TLS wiring keyed the client certificate and the
server's clientCaFiles off server.tls.<section>.requireClientAuth only.
Enabling mutual TLS through the documented server.config.tls override left
the frontend requiring client auth while the chart's own CLI pods presented
no certificate and the server had no CA to verify clients against.
The admin CLI pods now always present their client certificate (the secret
is already mounted, and an unrequested cert is never sent), and clientCaFiles
is emitted whenever requireClientAuth is effective through either surface.
Exercise frontend mutual TLS end to end in CI via the postgres-tls case, and
add unit coverage for the override path.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
What was changed
Add certificates.yaml + secret.yaml to templates
Why?
generate certificates using cert-manager
How was this tested
Deployed cert-manager helm-chart
Deployed temporal helm chart, 0.57.0, using temporal/charts/temporal/tests/certificates.yaml as values.yaml, with my own tls.crt + tls.key
Cert-manager will:
Use the temporal-issuer (which refers to the CA).
Ask the CA (from the tls-certs secret) to sign a new certificate.
Create the temporal-tls-certs secret in the same namespace — this secret will contain:
tls.crt: the signed certificate
tls.key: the private key
Optionally, ca.crt: the CA certificate (if configured)
➜ ~ kubectl get secret -n temporal
NAME TYPE DATA AGE
temporal-tls-certs kubernetes.io/tls 3 3h38m
tls-certs Opaque 2 153m
➜ ~ kubectl get certificate -n temporal
NAME READY SECRET AGE
temporal-cert True temporal-tls-certs 5h35m
➜ ~ kubectl get certificaterequests -n temporal-data
NAME APPROVED DENIED READY ISSUER REQUESTER AGE
temporal-cert-1 True True temporal-issuer system:serviceaccount:cert-manager:test-cert-manager 5h