diff --git a/apis/core/v1alpha1/secret.go b/apis/core/v1alpha1/secret.go index 75fdb44..f4c6959 100644 --- a/apis/core/v1alpha1/secret.go +++ b/apis/core/v1alpha1/secret.go @@ -26,3 +26,12 @@ type SecretKeyReference struct { // Key is the key within the secret Key string `json:"key"` } + +// TlsSecretReference identifies a kubernetes.io/tls Secret without selecting +// a specific data key. The consumer owns the key convention (tls.crt and +// tls.key). +type TlsSecretReference struct { + // Empty JSON tag with "inline" attribute is required to properly inline the + // field in JSON output due to k8s apimachinery constraints. + k8scorev1.SecretReference `json:",inline"` +} diff --git a/apis/core/v1alpha1/secret_test.go b/apis/core/v1alpha1/secret_test.go new file mode 100644 index 0000000..7906713 --- /dev/null +++ b/apis/core/v1alpha1/secret_test.go @@ -0,0 +1,33 @@ +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +package v1alpha1 + +import ( + "encoding/json" + "strings" + "testing" +) + +func TestTlsSecretReferenceDoesNotContainKey(t *testing.T) { + ref := TlsSecretReference{} + ref.Name = "tls-secret" + + data, err := json.Marshal(ref) + if err != nil { + t.Fatal(err) + } + if strings.Contains(string(data), `"key"`) { + t.Fatalf("secret reference must not expose a key: %s", data) + } +} diff --git a/apis/core/v1alpha1/zz_generated.deepcopy.go b/apis/core/v1alpha1/zz_generated.deepcopy.go index c21775e..b11c8be 100644 --- a/apis/core/v1alpha1/zz_generated.deepcopy.go +++ b/apis/core/v1alpha1/zz_generated.deepcopy.go @@ -1,5 +1,20 @@ //go:build !ignore_autogenerated +// Copyright Amazon.com Inc. or its affiliates. All Rights Reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"). You may +// not use this file except in compliance with the License. A copy of the +// License is located at +// +// http://aws.amazon.com/apache2.0/ +// +// or in the "license" file accompanying this file. This file is distributed +// on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either +// express or implied. See the License for the specific language governing +// permissions and limitations under the License. + +// Code generated by ack-generate. DO NOT EDIT. + // Code generated by controller-gen. DO NOT EDIT. package v1alpha1 @@ -500,6 +515,11 @@ func (in *ResourceMetadata) DeepCopyInto(out *ResourceMetadata) { *out = new(AWSRegion) **out = **in } + if in.Partition != nil { + in, out := &in.Partition, &out.Partition + *out = new(AWSPartition) + **out = **in + } } // DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ResourceMetadata. @@ -548,3 +568,19 @@ func (in *SecretKeyReference) DeepCopy() *SecretKeyReference { in.DeepCopyInto(out) return out } + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *TlsSecretReference) DeepCopyInto(out *TlsSecretReference) { + *out = *in + out.SecretReference = in.SecretReference +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new TlsSecretReference. +func (in *TlsSecretReference) DeepCopy() *TlsSecretReference { + if in == nil { + return nil + } + out := new(TlsSecretReference) + in.DeepCopyInto(out) + return out +} diff --git a/pkg/runtime/reconciler.go b/pkg/runtime/reconciler.go index 625776f..1e5d590 100644 --- a/pkg/runtime/reconciler.go +++ b/pkg/runtime/reconciler.go @@ -213,8 +213,10 @@ func (r *reconciler) SecretValueFromReference( return "", ackerr.SecretNotFound } - // Currently we have only Opaque secrets in scope. - if secret.Type != corev1.SecretTypeOpaque { + // ACK secret references support generic Opaque secrets and the standard + // kubernetes.io/tls Secret type. Callers remain responsible for selecting + // an appropriate data key (for example, tls.crt or tls.key). + if secret.Type != corev1.SecretTypeOpaque && secret.Type != corev1.SecretTypeTLS { return "", ackerr.SecretTypeNotSupported } diff --git a/pkg/runtime/reconciler_test.go b/pkg/runtime/reconciler_test.go index b401ba1..acaa309 100644 --- a/pkg/runtime/reconciler_test.go +++ b/pkg/runtime/reconciler_test.go @@ -2524,11 +2524,12 @@ func secretReconciler( return r, apiReader } -// expectSecretGet wires the mocked apiReader to return an Opaque secret with -// the supplied key/value for a Get against the given namespace/name. -func expectSecretGet( +// expectSecretGet wires the mocked apiReader to return a secret with the +// supplied type and key/value for a Get against the given namespace/name. +func expectSecretGetOfType( apiReader *ctrlrtclientmock.Reader, namespace, name, key, value string, + secretType corev1.SecretType, ) { apiReader.On( "Get", mock.Anything, @@ -2536,11 +2537,22 @@ func expectSecretGet( mock.AnythingOfType("*v1.Secret"), ).Run(func(args mock.Arguments) { secret := args.Get(2).(*corev1.Secret) - secret.Type = corev1.SecretTypeOpaque + secret.Type = secretType secret.Data = map[string][]byte{key: []byte(value)} }).Return(nil) } +func expectSecretGet( + apiReader *ctrlrtclientmock.Reader, + namespace, name, key, value string, +) { + expectSecretGetOfType( + apiReader, + namespace, name, key, value, + corev1.SecretTypeOpaque, + ) +} + func ctxWithNamespace(ns string) context.Context { return context.WithValue(context.Background(), "resourceNamespace", ns) } @@ -2591,6 +2603,24 @@ func TestSecretValueFromReference_ExplicitSameNamespace(t *testing.T) { assert.Equal(t, "value", val) } +func TestSecretValueFromReference_TLSSecret(t *testing.T) { + r, apiReader := secretReconciler(false) + ctx := ctxWithNamespace("ns-a") + expectSecretGetOfType( + apiReader, + "ns-a", "sec", corev1.TLSCertKey, "certificate", + corev1.SecretTypeTLS, + ) + + val, err := r.SecretValueFromReference( + ctx, + newSecretRef("", "sec", corev1.TLSCertKey), + ) + + require.NoError(t, err) + assert.Equal(t, "certificate", val) +} + func TestSecretValueFromReference_CrossNamespace_FlagDisabled(t *testing.T) { r, _ := secretReconciler(false) ctx := ctxWithNamespace("ns-a")