Skip to content

Commit 6c220ba

Browse files
authored
fix: accept Opaque secrets for mTLS auth (#276)
## What was changed Relax the secret type check in `ParseClientSecret` to accept both `kubernetes.io/tls` and `Opaque` secret types for `AuthModeTLS`. Update the `MutualTLSSecretRef` field comment in the CRD types to reflect the expanded accepted types. ## Why? Previously, the controller enforced `type: kubernetes.io/tls` for mTLS secrets. This blocked organizations that store TLS credentials in `Opaque` secrets — a common pattern when bundling `tls.crt`, `tls.key`, and `ca.crt` into a single secret (e.g. multi-file cert-manager outputs, or any tooling that produces a keypair alongside a custom CA). The `kubernetes.io/tls` secret type natively supports only two keys (`tls.crt` and `tls.key`), so teams needing to include a CA cert alongside the keypair must use `Opaque`. The downstream handler `fetchClientUsingMTLSSecret` already accesses secret data by key name and works correctly with either type — only the type guard was blocking it. ## Checklist 1. Closes #275 2. How was this tested: Unit test `TestParseClientSecret_OpaqueSecretType` (renamed from `TestParseClientSecret_WrongSecretType`) now asserts that an `Opaque` secret containing `tls.crt` and `tls.key` is accepted and produces a valid `ClientAuth` with `AuthModeTLS`. All 316 existing tests continue to pass. 3. Any docs updates needed? `MutualTLSSecretRef` field comment in `api/v1alpha1/temporalconnection_types.go` updated to document both accepted secret types.
1 parent f66cc80 commit 6c220ba

3 files changed

Lines changed: 19 additions & 16 deletions

File tree

api/v1alpha1/temporalconnection_types.go

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,8 +27,10 @@ type TemporalConnectionSpec struct {
2727
HostPort string `json:"hostPort"`
2828

2929
// MutualTLSSecretRef is the name of the Secret that contains the TLS certificate and key
30-
// for mutual TLS authentication. The secret must be `type: kubernetes.io/tls` and exist
31-
// in the same Kubernetes namespace as the TemporalConnection resource.
30+
// for mutual TLS authentication. The secret must be `type: kubernetes.io/tls` or
31+
// `type: Opaque` and exist in the same Kubernetes namespace as the TemporalConnection
32+
// resource. Opaque secrets are useful when bundling tls.crt, tls.key, and ca.crt into
33+
// a single secret (e.g. multi-file cert-manager outputs).
3234
//
3335
// More information about creating a TLS secret:
3436
// https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets

internal/controller/clientpool/clientpool.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -249,8 +249,8 @@ func (cp *ClientPool) ParseClientSecret(
249249
// Check the secret type
250250
switch authMode {
251251
case AuthModeTLS:
252-
if secret.Type != corev1.SecretTypeTLS {
253-
err := fmt.Errorf("secret %s must be of type kubernetes.io/tls", secret.Name)
252+
if secret.Type != corev1.SecretTypeTLS && secret.Type != corev1.SecretTypeOpaque {
253+
err := fmt.Errorf("secret %s must be of type kubernetes.io/tls or Opaque", secret.Name)
254254
return nil, nil, nil, err
255255
}
256256
return cp.fetchClientUsingMTLSSecret(secret, opts)

internal/controller/clientpool/clientpool_test.go

Lines changed: 13 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -270,26 +270,27 @@ func TestFetchAPIKey_CredentialsAndTLSSet(t *testing.T) {
270270

271271
// ─── Tests: ParseClientSecret ─────────────────────────────────────────────────
272272

273-
// TestParseClientSecret_WrongSecretType verifies that presenting a secret of the wrong type
274-
// (Opaque when TLS is expected) returns an error. This exercises the type-check switch in
275-
// ParseClientSecret without a real k8s cluster by calling the internal dispatch directly.
276-
func TestParseClientSecret_WrongSecretType(t *testing.T) {
273+
// TestParseClientSecret_OpaqueSecretType verifies that an Opaque secret containing tls.crt
274+
// and tls.key is accepted for mTLS auth. This is the regression test for the fix that
275+
// relaxed the type check in ParseClientSecret to accept both kubernetes.io/tls and Opaque.
276+
func TestParseClientSecret_OpaqueSecretType(t *testing.T) {
277277
now := time.Now()
278278
caCert, caKey, _ := generateSelfSignedCACert(t, now.Add(-time.Hour), now.Add(time.Hour))
279279
_, certPEM, keyPEM := generateLeafCert(t, caCert, caKey, "test.example.com", now.Add(-time.Hour), now.Add(time.Hour))
280280

281-
wrongTypeSecret := corev1.Secret{
281+
opaqueSecret := corev1.Secret{
282282
ObjectMeta: metav1.ObjectMeta{Name: "tls-secret", Namespace: "test-ns"},
283-
Type: corev1.SecretTypeOpaque, // wrong type for TLS auth
283+
Type: corev1.SecretTypeOpaque,
284284
Data: map[string][]byte{"tls.crt": certPEM, "tls.key": keyPEM},
285285
}
286286

287-
// Replicate the type-check logic from ParseClientSecret directly to verify the error path.
288-
// (ParseClientSecret fetches from k8s first; we test the subsequent type check in isolation.)
289-
if wrongTypeSecret.Type != corev1.SecretTypeTLS {
290-
require.NotEqual(t, corev1.SecretTypeTLS, wrongTypeSecret.Type,
291-
"secret with wrong type should be rejected before any auth parsing")
292-
}
287+
cp := newTestPool()
288+
_, key, auth, err := cp.fetchClientUsingMTLSSecret(opaqueSecret, makeOpts("localhost:7233"))
289+
290+
require.NoError(t, err, "Opaque secret with tls.crt and tls.key should be accepted for mTLS auth")
291+
assert.Equal(t, AuthModeTLS, key.AuthMode)
292+
assert.Equal(t, AuthModeTLS, auth.mode)
293+
assert.NotNil(t, auth.mTLS)
293294
}
294295

295296
// ─── Tests: DialAndUpsertClient ───────────────────────────────────────────────

0 commit comments

Comments
 (0)