Skip to content

feat: generate TLS certificates using cert-manager - #820

Closed
luiscosta18 wants to merge 7 commits into
temporalio:mainfrom
luiscosta18:certs
Closed

feat: generate TLS certificates using cert-manager#820
luiscosta18 wants to merge 7 commits into
temporalio:mainfrom
luiscosta18:certs

Conversation

@luiscosta18

@luiscosta18 luiscosta18 commented Dec 30, 2025

Copy link
Copy Markdown

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

@luiscosta18
luiscosta18 requested a review from a team as a code owner December 30, 2025 21:13
@CLAassistant

CLAassistant commented Dec 30, 2025

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@CLAassistant

Copy link
Copy Markdown

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

@luiscosta18 luiscosta18 changed the title feat: generate TLS certificates using cer t-manager feat: generate TLS certificates using cert-manager Dec 30, 2025
@luiscosta18

Copy link
Copy Markdown
Author

Hello @robholland @tomwheeler @PhillypHenning

Please review this PR. Thanks.

@robholland robholland self-assigned this Jan 16, 2026
@luiscosta18

luiscosta18 commented Mar 30, 2026

Copy link
Copy Markdown
Author

Hello @robholland @tomwheeler @PhillypHenning

Please review this PR. Thanks.

Hello @robholland @tomwheeler @PhillypHenning
Looking forward to have your feedback on this 🙂

@@ -0,0 +1,90 @@
server:
additionalVolumeMounts:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these basically placeholders that cert-manager updates?

tls.key: |
-----BEGIN EC PRIVATE KEY-----
-----END EC PRIVATE KEY-----
certificates:

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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?

Comment thread charts/temporal/templates/secret.yaml Outdated
@robholland robholland mentioned this pull request Jul 22, 2026
@robholland

Copy link
Copy Markdown
Contributor

Closing in favour of #954, inspired by your work. Thanks for the time you spent on this!

@robholland robholland closed this Jul 27, 2026
robholland added a commit that referenced this pull request Jul 28, 2026
* 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants