Skip to content

Commit 3d0ecf2

Browse files
Shivs11claude
andauthored
fix: use CA certificate from mTLS secret for server verification (#212)
When connecting to a Temporal server via mTLS, the controller reads tls.crt and tls.key from the referenced Kubernetes secret but does not read ca.crt. This causes the controller to fall back to the system CA bundle for server certificate verification, which fails when the server's TLS certificate is signed by a private or internal CA (e.g. cert-manager in a self-hosted cluster). This change reads ca.crt from the mTLS secret (when present) and uses it as the trusted root CA pool for server certificate verification. This is fully backward compatible. Secrets created by cert-manager automatically include ca.crt. Temporal Cloud users are unaffected since their server certs are signed by public CAs already in the system bundle. <!--- Note to EXTERNAL Contributors --> <!-- Thanks for opening a PR! If it is a significant code change, please **make sure there is an open issue** for this. We work best with you when we have accepted the idea first before you code. --> <!--- For ALL Contributors 👇 --> ## What was changed <!-- Describe what has changed in this PR --> ## Why? <!-- Tell your future self why have you made these changes --> ## Checklist <!--- add/delete as needed ---> 1. Closes <!-- add issue number here --> Closes #158 3. How was this tested: <!--- Please describe how you tested your changes/how we can test them --> 4. Any docs updates needed? <!--- update README if applicable or point out where to update docs.temporal.io --> Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 31ccde6 commit 3d0ecf2

1 file changed

Lines changed: 14 additions & 1 deletion

File tree

internal/controller/clientpool/clientpool.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -130,9 +130,22 @@ func (cp *ClientPool) fetchClientUsingMTLSSecret(secret corev1.Secret, opts NewC
130130
if err != nil {
131131
return nil, err
132132
}
133-
clientOpts.ConnectionOptions.TLS = &tls.Config{
133+
tlsCfg := &tls.Config{
134134
Certificates: []tls.Certificate{cert},
135135
}
136+
// If the secret contains a CA certificate, use it as the trusted root for server
137+
// certificate verification. This enables connecting to Temporal servers whose TLS
138+
// certificates are signed by private or internal CAs (e.g. cert-manager in a test
139+
// cluster). When ca.crt is absent, Go falls back to the system CA bundle, which is
140+
// the correct behaviour for Temporal Cloud and other publicly-signed endpoints.
141+
if caCert, ok := secret.Data["ca.crt"]; ok && len(caCert) > 0 {
142+
rootCAs := x509.NewCertPool()
143+
if !rootCAs.AppendCertsFromPEM(caCert) {
144+
return nil, errors.New("failed to parse CA certificate from secret")
145+
}
146+
tlsCfg.RootCAs = rootCAs
147+
}
148+
clientOpts.ConnectionOptions.TLS = tlsCfg
136149
expiryTime = exp
137150

138151
c, err := sdkclient.Dial(clientOpts)

0 commit comments

Comments
 (0)