From ada6b85cdedcc8b760e35644ee1b0f0eba843b25 Mon Sep 17 00:00:00 2001 From: Connor Graham Date: Tue, 14 Apr 2026 14:55:34 -0400 Subject: [PATCH 1/2] fix: accept Opaque secrets for mTLS auth in ParseClientSecret --- api/v1alpha1/temporalconnection_types.go | 6 ++++-- internal/controller/clientpool/clientpool.go | 4 ++-- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/api/v1alpha1/temporalconnection_types.go b/api/v1alpha1/temporalconnection_types.go index f085b07f..b5cc2a80 100644 --- a/api/v1alpha1/temporalconnection_types.go +++ b/api/v1alpha1/temporalconnection_types.go @@ -27,8 +27,10 @@ type TemporalConnectionSpec struct { HostPort string `json:"hostPort"` // MutualTLSSecretRef is the name of the Secret that contains the TLS certificate and key - // for mutual TLS authentication. The secret must be `type: kubernetes.io/tls` and exist - // in the same Kubernetes namespace as the TemporalConnection resource. + // for mutual TLS authentication. The secret must be `type: kubernetes.io/tls` or + // `type: Opaque` and exist in the same Kubernetes namespace as the TemporalConnection + // resource. Opaque secrets are useful when bundling tls.crt, tls.key, and ca.crt into + // a single secret (e.g. multi-file cert-manager outputs). // // More information about creating a TLS secret: // https://kubernetes.io/docs/concepts/configuration/secret/#tls-secrets diff --git a/internal/controller/clientpool/clientpool.go b/internal/controller/clientpool/clientpool.go index ac8e114c..b5b9976b 100644 --- a/internal/controller/clientpool/clientpool.go +++ b/internal/controller/clientpool/clientpool.go @@ -249,8 +249,8 @@ func (cp *ClientPool) ParseClientSecret( // Check the secret type switch authMode { case AuthModeTLS: - if secret.Type != corev1.SecretTypeTLS { - err := fmt.Errorf("secret %s must be of type kubernetes.io/tls", secret.Name) + if secret.Type != corev1.SecretTypeTLS && secret.Type != corev1.SecretTypeOpaque { + err := fmt.Errorf("secret %s must be of type kubernetes.io/tls or Opaque", secret.Name) return nil, nil, nil, err } return cp.fetchClientUsingMTLSSecret(secret, opts) From ca05ddbf4340d51c2da793b92e5b1253cc68b1af Mon Sep 17 00:00:00 2001 From: Connor Graham Date: Tue, 14 Apr 2026 14:56:19 -0400 Subject: [PATCH 2/2] test: rename WrongSecretType test to assert Opaque is accepted for mTLS --- .../controller/clientpool/clientpool_test.go | 25 ++++++++++--------- 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/internal/controller/clientpool/clientpool_test.go b/internal/controller/clientpool/clientpool_test.go index 067bd586..b00cf014 100644 --- a/internal/controller/clientpool/clientpool_test.go +++ b/internal/controller/clientpool/clientpool_test.go @@ -270,26 +270,27 @@ func TestFetchAPIKey_CredentialsAndTLSSet(t *testing.T) { // ─── Tests: ParseClientSecret ───────────────────────────────────────────────── -// TestParseClientSecret_WrongSecretType verifies that presenting a secret of the wrong type -// (Opaque when TLS is expected) returns an error. This exercises the type-check switch in -// ParseClientSecret without a real k8s cluster by calling the internal dispatch directly. -func TestParseClientSecret_WrongSecretType(t *testing.T) { +// TestParseClientSecret_OpaqueSecretType verifies that an Opaque secret containing tls.crt +// and tls.key is accepted for mTLS auth. This is the regression test for the fix that +// relaxed the type check in ParseClientSecret to accept both kubernetes.io/tls and Opaque. +func TestParseClientSecret_OpaqueSecretType(t *testing.T) { now := time.Now() caCert, caKey, _ := generateSelfSignedCACert(t, now.Add(-time.Hour), now.Add(time.Hour)) _, certPEM, keyPEM := generateLeafCert(t, caCert, caKey, "test.example.com", now.Add(-time.Hour), now.Add(time.Hour)) - wrongTypeSecret := corev1.Secret{ + opaqueSecret := corev1.Secret{ ObjectMeta: metav1.ObjectMeta{Name: "tls-secret", Namespace: "test-ns"}, - Type: corev1.SecretTypeOpaque, // wrong type for TLS auth + Type: corev1.SecretTypeOpaque, Data: map[string][]byte{"tls.crt": certPEM, "tls.key": keyPEM}, } - // Replicate the type-check logic from ParseClientSecret directly to verify the error path. - // (ParseClientSecret fetches from k8s first; we test the subsequent type check in isolation.) - if wrongTypeSecret.Type != corev1.SecretTypeTLS { - require.NotEqual(t, corev1.SecretTypeTLS, wrongTypeSecret.Type, - "secret with wrong type should be rejected before any auth parsing") - } + cp := newTestPool() + _, key, auth, err := cp.fetchClientUsingMTLSSecret(opaqueSecret, makeOpts("localhost:7233")) + + require.NoError(t, err, "Opaque secret with tls.crt and tls.key should be accepted for mTLS auth") + assert.Equal(t, AuthModeTLS, key.AuthMode) + assert.Equal(t, AuthModeTLS, auth.mode) + assert.NotNil(t, auth.mTLS) } // ─── Tests: DialAndUpsertClient ───────────────────────────────────────────────