From 64589cddda0d43e9964b368fefbd4bb62235fb5e Mon Sep 17 00:00:00 2001 From: Moritz Johner Date: Wed, 26 Jan 2022 22:10:15 +0100 Subject: [PATCH] chore: implement aws parameterstore e2e tests Signed-off-by: Moritz Johner --- e2e/suite/aws/common.go | 97 ++++++++++ .../aws/parameterstore/parameterstore.go | 45 +++++ .../parameterstore/parameterstore_managed.go | 85 +++++++++ e2e/suite/aws/parameterstore/provider.go | 165 ++++++++++++++++++ .../aws/{ => secretsmanager}/provider.go | 90 ++-------- .../{ => secretsmanager}/secretsmanager.go | 0 .../secretsmanager/secretsmanager_managed.go | 85 +++++++++ e2e/suite/aws/secretsmanager_managed.go | 102 ----------- e2e/suite/import.go | 3 +- terraform/aws/modules/cluster/irsa.tf | 19 ++ 10 files changed, 512 insertions(+), 179 deletions(-) create mode 100644 e2e/suite/aws/common.go create mode 100644 e2e/suite/aws/parameterstore/parameterstore.go create mode 100644 e2e/suite/aws/parameterstore/parameterstore_managed.go create mode 100644 e2e/suite/aws/parameterstore/provider.go rename e2e/suite/aws/{ => secretsmanager}/provider.go (67%) rename e2e/suite/aws/{ => secretsmanager}/secretsmanager.go (100%) create mode 100644 e2e/suite/aws/secretsmanager/secretsmanager_managed.go delete mode 100644 e2e/suite/aws/secretsmanager_managed.go diff --git a/e2e/suite/aws/common.go b/e2e/suite/aws/common.go new file mode 100644 index 000000000..b725b74a7 --- /dev/null +++ b/e2e/suite/aws/common.go @@ -0,0 +1,97 @@ +/* +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License 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 common + +import ( + "context" + + // nolint + . "github.com/onsi/gomega" + corev1 "k8s.io/api/core/v1" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + + esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1" + esmetav1 "github.com/external-secrets/external-secrets/apis/meta/v1" + "github.com/external-secrets/external-secrets/e2e/framework" +) + +const ( + WithReferencedIRSA = "with referenced IRSA" + WithMountedIRSA = "with mounted IRSA" + StaticCredentialsSecretName = "provider-secret" +) + +func ReferencedIRSAStoreName(f *framework.Framework) string { + return "irsa-ref-" + f.Namespace.Name +} + +func MountedIRSAStoreName(f *framework.Framework) string { + return "irsa-mounted-" + f.Namespace.Name +} + +func UseClusterSecretStore(tc *framework.TestCase) { + tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.ClusterSecretStoreKind + tc.ExternalSecret.Spec.SecretStoreRef.Name = ReferencedIRSAStoreName(tc.Framework) +} + +func UseMountedIRSAStore(tc *framework.TestCase) { + tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.SecretStoreKind + tc.ExternalSecret.Spec.SecretStoreRef.Name = MountedIRSAStoreName(tc.Framework) +} + +// StaticStore is namespaced and references +// static credentials from a secret. +func SetupStaticStore(f *framework.Framework, kid, sak, region string, serviceType esv1alpha1.AWSServiceType) { + awsCreds := &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{ + Name: StaticCredentialsSecretName, + Namespace: f.Namespace.Name, + }, + StringData: map[string]string{ + "kid": kid, + "sak": sak, + }, + } + err := f.CRClient.Create(context.Background(), awsCreds) + Expect(err).ToNot(HaveOccurred()) + + secretStore := &esv1alpha1.SecretStore{ + ObjectMeta: metav1.ObjectMeta{ + Name: f.Namespace.Name, + Namespace: f.Namespace.Name, + }, + Spec: esv1alpha1.SecretStoreSpec{ + Provider: &esv1alpha1.SecretStoreProvider{ + AWS: &esv1alpha1.AWSProvider{ + Service: serviceType, + Region: region, + Auth: esv1alpha1.AWSAuth{ + SecretRef: &esv1alpha1.AWSAuthSecretRef{ + AccessKeyID: esmetav1.SecretKeySelector{ + Name: StaticCredentialsSecretName, + Key: "kid", + }, + SecretAccessKey: esmetav1.SecretKeySelector{ + Name: StaticCredentialsSecretName, + Key: "sak", + }, + }, + }, + }, + }, + }, + } + err = f.CRClient.Create(context.Background(), secretStore) + Expect(err).ToNot(HaveOccurred()) +} diff --git a/e2e/suite/aws/parameterstore/parameterstore.go b/e2e/suite/aws/parameterstore/parameterstore.go new file mode 100644 index 000000000..3337bf460 --- /dev/null +++ b/e2e/suite/aws/parameterstore/parameterstore.go @@ -0,0 +1,45 @@ +/* +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License 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 aws + +import ( + + // nolint + . "github.com/onsi/ginkgo/v2" + + "github.com/external-secrets/external-secrets/e2e/framework" + "github.com/external-secrets/external-secrets/e2e/suite/common" +) + +var _ = Describe("[aws] ", Label("aws", "parameterstore"), func() { + f := framework.New("eso-aws-ps") + prov := NewFromEnv(f) + + DescribeTable("sync secrets", + framework.TableFunc(f, + prov), + Entry(common.SimpleDataSync(f)), + Entry(common.NestedJSONWithGJSON(f)), + Entry(common.JSONDataFromSync(f)), + Entry(common.JSONDataWithProperty(f)), + Entry(common.JSONDataWithTemplate(f)), + Entry(common.DockerJSONConfig(f)), + Entry(common.DataPropertyDockerconfigJSON(f)), + Entry(common.SSHKeySync(f)), + Entry(common.SSHKeySyncDataProperty(f)), + Entry(common.SyncWithoutTargetName(f)), + Entry(common.JSONDataWithoutTargetName(f)), + ) +}) diff --git a/e2e/suite/aws/parameterstore/parameterstore_managed.go b/e2e/suite/aws/parameterstore/parameterstore_managed.go new file mode 100644 index 000000000..5b611cd65 --- /dev/null +++ b/e2e/suite/aws/parameterstore/parameterstore_managed.go @@ -0,0 +1,85 @@ +/* +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License 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 aws + +import ( + + // nolint + . "github.com/onsi/ginkgo/v2" + + "github.com/external-secrets/external-secrets/e2e/framework" + "github.com/external-secrets/external-secrets/e2e/framework/addon" + awscommon "github.com/external-secrets/external-secrets/e2e/suite/aws" + "github.com/external-secrets/external-secrets/e2e/suite/common" +) + +// here we use the global eso instance +// that uses the service account in the default namespace +// which was created by terraform. +var _ = Describe("[awsmanaged] IRSA via referenced service account", Label("aws", "parameterstore", "managed"), func() { + f := framework.New("eso-aws-ps-managed") + prov := NewFromEnv(f) + + // nolint + DescribeTable("sync secrets", + framework.TableFunc(f, + prov), + framework.Compose(awscommon.WithReferencedIRSA, f, common.SimpleDataSync, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.NestedJSONWithGJSON, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataFromSync, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithProperty, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithTemplate, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.DockerJSONConfig, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.DataPropertyDockerconfigJSON, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.SSHKeySync, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.SSHKeySyncDataProperty, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.SyncWithoutTargetName, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithoutTargetName, awscommon.UseClusterSecretStore), + ) +}) + +// here we create a central eso instance in the default namespace +// that mounts the service account which was created by terraform. +var _ = Describe("[awsmanaged] with mounted IRSA", Label("aws", "parameterstore", "managed"), func() { + f := framework.New("eso-aws-ps-irsa-managed") + prov := NewFromEnv(f) + + // each test case gets its own ESO instance + BeforeEach(func() { + f.Install(addon.NewESO( + addon.WithControllerClass(f.BaseName), + addon.WithServiceAccount(prov.ServiceAccountName), + addon.WithReleaseName(f.Namespace.Name), + addon.WithNamespace("default"), + )) + }) + + // nolint + DescribeTable("sync secrets", + framework.TableFunc(f, + prov), + framework.Compose(awscommon.WithMountedIRSA, f, common.SimpleDataSync, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.NestedJSONWithGJSON, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataFromSync, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithProperty, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithTemplate, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.DockerJSONConfig, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.DataPropertyDockerconfigJSON, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.SSHKeySync, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.SSHKeySyncDataProperty, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.SyncWithoutTargetName, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithoutTargetName, awscommon.UseMountedIRSAStore), + ) +}) diff --git a/e2e/suite/aws/parameterstore/provider.go b/e2e/suite/aws/parameterstore/provider.go new file mode 100644 index 000000000..040309af3 --- /dev/null +++ b/e2e/suite/aws/parameterstore/provider.go @@ -0,0 +1,165 @@ +/* +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License 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 aws + +import ( + "context" + "os" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/credentials" + "github.com/aws/aws-sdk-go/aws/session" + "github.com/aws/aws-sdk-go/service/ssm" + + //nolint + . "github.com/onsi/ginkgo/v2" + + // nolint + . "github.com/onsi/gomega" + metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" + + esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1" + esmetav1 "github.com/external-secrets/external-secrets/apis/meta/v1" + "github.com/external-secrets/external-secrets/e2e/framework" + "github.com/external-secrets/external-secrets/e2e/framework/log" + common "github.com/external-secrets/external-secrets/e2e/suite/aws" +) + +type Provider struct { + ServiceAccountName string + ServiceAccountNamespace string + + region string + client *ssm.SSM + framework *framework.Framework +} + +func NewProvider(f *framework.Framework, kid, sak, region, saName, saNamespace string) *Provider { + sess, err := session.NewSessionWithOptions(session.Options{ + Config: aws.Config{ + Credentials: credentials.NewStaticCredentials(kid, sak, ""), + Region: aws.String(region), + }, + }) + if err != nil { + Fail(err.Error()) + } + sm := ssm.New(sess) + prov := &Provider{ + ServiceAccountName: saName, + ServiceAccountNamespace: saNamespace, + region: region, + client: sm, + framework: f, + } + + BeforeEach(func() { + common.SetupStaticStore(f, kid, sak, region, esv1alpha1.AWSServiceParameterStore) + prov.SetupReferencedIRSAStore() + prov.SetupMountedIRSAStore() + }) + + AfterEach(func() { + // Cleanup ClusterSecretStore + err := prov.framework.CRClient.Delete(context.Background(), &esv1alpha1.ClusterSecretStore{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ReferencedIRSAStoreName(f), + }, + }) + Expect(err).ToNot(HaveOccurred()) + }) + + return prov +} + +func NewFromEnv(f *framework.Framework) *Provider { + kid := os.Getenv("AWS_ACCESS_KEY_ID") + sak := os.Getenv("AWS_SECRET_ACCESS_KEY") + region := "eu-west-1" + saName := os.Getenv("AWS_SA_NAME") + saNamespace := os.Getenv("AWS_SA_NAMESPACE") + return NewProvider(f, kid, sak, region, saName, saNamespace) +} + +// CreateSecret creates a secret at the provider. +func (s *Provider) CreateSecret(key, val string) { + _, err := s.client.PutParameter(&ssm.PutParameterInput{ + Name: aws.String(key), + Value: aws.String(val), + DataType: aws.String("text"), + Type: aws.String("String"), + }) + Expect(err).ToNot(HaveOccurred()) +} + +// DeleteSecret deletes a secret at the provider. +func (s *Provider) DeleteSecret(key string) { + _, err := s.client.DeleteParameter(&ssm.DeleteParameterInput{ + Name: aws.String(key), + }) + Expect(err).ToNot(HaveOccurred()) +} + +// MountedIRSAStore is a SecretStore without auth config +// ESO relies on the pod-mounted ServiceAccount when using this store. +func (s *Provider) SetupMountedIRSAStore() { + secretStore := &esv1alpha1.SecretStore{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.MountedIRSAStoreName(s.framework), + Namespace: s.framework.Namespace.Name, + }, + Spec: esv1alpha1.SecretStoreSpec{ + Provider: &esv1alpha1.SecretStoreProvider{ + AWS: &esv1alpha1.AWSProvider{ + Service: esv1alpha1.AWSServiceParameterStore, + Region: s.region, + Auth: esv1alpha1.AWSAuth{}, + }, + }, + }, + } + err := s.framework.CRClient.Create(context.Background(), secretStore) + Expect(err).ToNot(HaveOccurred()) +} + +// ReferncedIRSAStore is a ClusterStore +// that references a (IRSA-) ServiceAccount in the default namespace. +func (s *Provider) SetupReferencedIRSAStore() { + log.Logf("creating IRSA ClusterSecretStore %s", s.framework.Namespace.Name) + secretStore := &esv1alpha1.ClusterSecretStore{ + ObjectMeta: metav1.ObjectMeta{ + Name: common.ReferencedIRSAStoreName(s.framework), + }, + } + _, err := controllerutil.CreateOrUpdate(context.Background(), s.framework.CRClient, secretStore, func() error { + secretStore.Spec.Provider = &esv1alpha1.SecretStoreProvider{ + AWS: &esv1alpha1.AWSProvider{ + Service: esv1alpha1.AWSServiceParameterStore, + Region: s.region, + Auth: esv1alpha1.AWSAuth{ + JWTAuth: &esv1alpha1.AWSJWTAuth{ + ServiceAccountRef: &esmetav1.ServiceAccountSelector{ + Name: s.ServiceAccountName, + Namespace: &s.ServiceAccountNamespace, + }, + }, + }, + }, + } + return nil + }) + Expect(err).ToNot(HaveOccurred()) +} diff --git a/e2e/suite/aws/provider.go b/e2e/suite/aws/secretsmanager/provider.go similarity index 67% rename from e2e/suite/aws/provider.go rename to e2e/suite/aws/secretsmanager/provider.go index 3e1bc0185..61ef9c1e8 100644 --- a/e2e/suite/aws/provider.go +++ b/e2e/suite/aws/secretsmanager/provider.go @@ -29,7 +29,6 @@ import ( // nolint . "github.com/onsi/gomega" - v1 "k8s.io/api/core/v1" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "sigs.k8s.io/controller-runtime/pkg/controller/controllerutil" @@ -37,24 +36,19 @@ import ( esmetav1 "github.com/external-secrets/external-secrets/apis/meta/v1" "github.com/external-secrets/external-secrets/e2e/framework" "github.com/external-secrets/external-secrets/e2e/framework/log" + common "github.com/external-secrets/external-secrets/e2e/suite/aws" ) -type SMProvider struct { +type Provider struct { ServiceAccountName string ServiceAccountNamespace string - kid string - sak string region string client *secretsmanager.SecretsManager framework *framework.Framework } -const ( - staticCredentialsSecretName = "provider-secret" -) - -func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace string) *SMProvider { +func NewProvider(f *framework.Framework, kid, sak, region, saName, saNamespace string) *Provider { sess, err := session.NewSessionWithOptions(session.Options{ Config: aws.Config{ Credentials: credentials.NewStaticCredentials(kid, sak, ""), @@ -65,18 +59,16 @@ func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace Fail(err.Error()) } sm := secretsmanager.New(sess) - prov := &SMProvider{ + prov := &Provider{ ServiceAccountName: saName, ServiceAccountNamespace: saNamespace, - kid: kid, - sak: sak, region: region, client: sm, framework: f, } BeforeEach(func() { - prov.SetupStaticStore() + common.SetupStaticStore(f, kid, sak, region, esv1alpha1.AWSServiceSecretsManager) prov.SetupReferencedIRSAStore() prov.SetupMountedIRSAStore() }) @@ -85,7 +77,7 @@ func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace // Cleanup ClusterSecretStore err := prov.framework.CRClient.Delete(context.Background(), &esv1alpha1.ClusterSecretStore{ ObjectMeta: metav1.ObjectMeta{ - Name: prov.ReferencedIRSAStoreName(), + Name: common.ReferencedIRSAStoreName(f), }, }) Expect(err).ToNot(HaveOccurred()) @@ -94,17 +86,17 @@ func NewSMProvider(f *framework.Framework, kid, sak, region, saName, saNamespace return prov } -func NewFromEnv(f *framework.Framework) *SMProvider { +func NewFromEnv(f *framework.Framework) *Provider { kid := os.Getenv("AWS_ACCESS_KEY_ID") sak := os.Getenv("AWS_SECRET_ACCESS_KEY") region := "eu-west-1" saName := os.Getenv("AWS_SA_NAME") saNamespace := os.Getenv("AWS_SA_NAMESPACE") - return NewSMProvider(f, kid, sak, region, saName, saNamespace) + return NewProvider(f, kid, sak, region, saName, saNamespace) } // CreateSecret creates a secret at the provider. -func (s *SMProvider) CreateSecret(key, val string) { +func (s *Provider) CreateSecret(key, val string) { // we re-use some secret names throughout our test suite // due to the fact that there is a short delay before the secret is actually deleted // we have to retry creating the secret @@ -129,7 +121,7 @@ func (s *SMProvider) CreateSecret(key, val string) { // DeleteSecret deletes a secret at the provider. // There may be a short delay between calling this function // and the removal of the secret on the provider side. -func (s *SMProvider) DeleteSecret(key string) { +func (s *Provider) DeleteSecret(key string) { log.Logf("deleting secret %s", key) _, err := s.client.DeleteSecret(&secretsmanager.DeleteSecretInput{ SecretId: aws.String(key), @@ -140,10 +132,10 @@ func (s *SMProvider) DeleteSecret(key string) { // MountedIRSAStore is a SecretStore without auth config // ESO relies on the pod-mounted ServiceAccount when using this store. -func (s *SMProvider) SetupMountedIRSAStore() { +func (s *Provider) SetupMountedIRSAStore() { secretStore := &esv1alpha1.SecretStore{ ObjectMeta: metav1.ObjectMeta{ - Name: s.MountedIRSAStoreName(), + Name: common.MountedIRSAStoreName(s.framework), Namespace: s.framework.Namespace.Name, }, Spec: esv1alpha1.SecretStoreSpec{ @@ -160,17 +152,13 @@ func (s *SMProvider) SetupMountedIRSAStore() { Expect(err).ToNot(HaveOccurred()) } -func (s *SMProvider) MountedIRSAStoreName() string { - return "irsa-mounted-" + s.framework.Namespace.Name -} - // ReferncedIRSAStore is a ClusterStore // that references a (IRSA-) ServiceAccount in the default namespace. -func (s *SMProvider) SetupReferencedIRSAStore() { +func (s *Provider) SetupReferencedIRSAStore() { log.Logf("creating IRSA ClusterSecretStore %s", s.framework.Namespace.Name) secretStore := &esv1alpha1.ClusterSecretStore{ ObjectMeta: metav1.ObjectMeta{ - Name: s.ReferencedIRSAStoreName(), + Name: common.ReferencedIRSAStoreName(s.framework), }, } _, err := controllerutil.CreateOrUpdate(context.Background(), s.framework.CRClient, secretStore, func() error { @@ -192,53 +180,3 @@ func (s *SMProvider) SetupReferencedIRSAStore() { }) Expect(err).ToNot(HaveOccurred()) } - -func (s *SMProvider) ReferencedIRSAStoreName() string { - return "irsa-ref-" + s.framework.Namespace.Name -} - -// StaticStore is namespaced and references -// static credentials from a secret. -func (s *SMProvider) SetupStaticStore() { - awsCreds := &v1.Secret{ - ObjectMeta: metav1.ObjectMeta{ - Name: staticCredentialsSecretName, - Namespace: s.framework.Namespace.Name, - }, - StringData: map[string]string{ - "kid": s.kid, - "sak": s.sak, - }, - } - err := s.framework.CRClient.Create(context.Background(), awsCreds) - Expect(err).ToNot(HaveOccurred()) - - secretStore := &esv1alpha1.SecretStore{ - ObjectMeta: metav1.ObjectMeta{ - Name: s.framework.Namespace.Name, - Namespace: s.framework.Namespace.Name, - }, - Spec: esv1alpha1.SecretStoreSpec{ - Provider: &esv1alpha1.SecretStoreProvider{ - AWS: &esv1alpha1.AWSProvider{ - Service: esv1alpha1.AWSServiceSecretsManager, - Region: s.region, - Auth: esv1alpha1.AWSAuth{ - SecretRef: &esv1alpha1.AWSAuthSecretRef{ - AccessKeyID: esmetav1.SecretKeySelector{ - Name: staticCredentialsSecretName, - Key: "kid", - }, - SecretAccessKey: esmetav1.SecretKeySelector{ - Name: staticCredentialsSecretName, - Key: "sak", - }, - }, - }, - }, - }, - }, - } - err = s.framework.CRClient.Create(context.Background(), secretStore) - Expect(err).ToNot(HaveOccurred()) -} diff --git a/e2e/suite/aws/secretsmanager.go b/e2e/suite/aws/secretsmanager/secretsmanager.go similarity index 100% rename from e2e/suite/aws/secretsmanager.go rename to e2e/suite/aws/secretsmanager/secretsmanager.go diff --git a/e2e/suite/aws/secretsmanager/secretsmanager_managed.go b/e2e/suite/aws/secretsmanager/secretsmanager_managed.go new file mode 100644 index 000000000..84f2e9509 --- /dev/null +++ b/e2e/suite/aws/secretsmanager/secretsmanager_managed.go @@ -0,0 +1,85 @@ +/* +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License 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 aws + +import ( + + // nolint + . "github.com/onsi/ginkgo/v2" + + "github.com/external-secrets/external-secrets/e2e/framework" + "github.com/external-secrets/external-secrets/e2e/framework/addon" + awscommon "github.com/external-secrets/external-secrets/e2e/suite/aws" + "github.com/external-secrets/external-secrets/e2e/suite/common" +) + +// here we use the global eso instance +// that uses the service account in the default namespace +// which was created by terraform. +var _ = Describe("[awsmanaged] IRSA via referenced service account", Label("aws", "secretsmanager", "managed"), func() { + f := framework.New("eso-aws-managed") + prov := NewFromEnv(f) + + // nolint + DescribeTable("sync secretsmanager secrets", + framework.TableFunc(f, + prov), + framework.Compose(awscommon.WithReferencedIRSA, f, common.SimpleDataSync, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.NestedJSONWithGJSON, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataFromSync, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithProperty, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithTemplate, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.DockerJSONConfig, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.DataPropertyDockerconfigJSON, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.SSHKeySync, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.SSHKeySyncDataProperty, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.SyncWithoutTargetName, awscommon.UseClusterSecretStore), + framework.Compose(awscommon.WithReferencedIRSA, f, common.JSONDataWithoutTargetName, awscommon.UseClusterSecretStore), + ) +}) + +// here we create a central eso instance in the default namespace +// that mounts the service account which was created by terraform. +var _ = Describe("[awsmanaged] with mounted IRSA", Label("aws", "secretsmanager", "managed"), func() { + f := framework.New("eso-aws-managed") + prov := NewFromEnv(f) + + // each test case gets its own ESO instance + BeforeEach(func() { + f.Install(addon.NewESO( + addon.WithControllerClass(f.BaseName), + addon.WithServiceAccount(prov.ServiceAccountName), + addon.WithReleaseName(f.Namespace.Name), + addon.WithNamespace("default"), + )) + }) + + // nolint + DescribeTable("sync secretsmanager secrets", + framework.TableFunc(f, + prov), + framework.Compose(awscommon.WithMountedIRSA, f, common.SimpleDataSync, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.NestedJSONWithGJSON, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataFromSync, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithProperty, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithTemplate, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.DockerJSONConfig, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.DataPropertyDockerconfigJSON, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.SSHKeySync, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.SSHKeySyncDataProperty, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.SyncWithoutTargetName, awscommon.UseMountedIRSAStore), + framework.Compose(awscommon.WithMountedIRSA, f, common.JSONDataWithoutTargetName, awscommon.UseMountedIRSAStore), + ) +}) diff --git a/e2e/suite/aws/secretsmanager_managed.go b/e2e/suite/aws/secretsmanager_managed.go deleted file mode 100644 index 6d83d3d73..000000000 --- a/e2e/suite/aws/secretsmanager_managed.go +++ /dev/null @@ -1,102 +0,0 @@ -/* -Licensed under the Apache License, Version 2.0 (the "License"); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License 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 aws - -import ( - - // nolint - . "github.com/onsi/ginkgo/v2" - - esv1alpha1 "github.com/external-secrets/external-secrets/apis/externalsecrets/v1alpha1" - "github.com/external-secrets/external-secrets/e2e/framework" - "github.com/external-secrets/external-secrets/e2e/framework/addon" - "github.com/external-secrets/external-secrets/e2e/suite/common" -) - -const ( - withReferencedIRSA = "with referenced IRSA" - withMountedIRSA = "with mounted IRSA" -) - -// here we use the global eso instance -// that uses the service account in the default namespace -// which was created by terraform. -var _ = Describe("[awsmanaged] IRSA via referenced service account", Label("aws", "secretsmanager", "managed"), func() { - f := framework.New("eso-aws-managed") - prov := NewFromEnv(f) - - DescribeTable("sync secrets", - framework.TableFunc(f, - prov), - framework.Compose(withReferencedIRSA, f, common.SimpleDataSync, useClusterSecretStore(prov)), - framework.Compose(withReferencedIRSA, f, common.NestedJSONWithGJSON, useClusterSecretStore(prov)), - framework.Compose(withReferencedIRSA, f, common.JSONDataFromSync, useClusterSecretStore(prov)), - framework.Compose(withReferencedIRSA, f, common.JSONDataWithProperty, useClusterSecretStore(prov)), - framework.Compose(withReferencedIRSA, f, common.JSONDataWithTemplate, useClusterSecretStore(prov)), - framework.Compose(withReferencedIRSA, f, common.DockerJSONConfig, useClusterSecretStore(prov)), - framework.Compose(withReferencedIRSA, f, common.DataPropertyDockerconfigJSON, useClusterSecretStore(prov)), - framework.Compose(withReferencedIRSA, f, common.SSHKeySync, useClusterSecretStore(prov)), - framework.Compose(withReferencedIRSA, f, common.SSHKeySyncDataProperty, useClusterSecretStore(prov)), - framework.Compose(withReferencedIRSA, f, common.SyncWithoutTargetName, useClusterSecretStore(prov)), - framework.Compose(withReferencedIRSA, f, common.JSONDataWithoutTargetName, useClusterSecretStore(prov)), - ) -}) - -// here we create a central eso instance in the default namespace -// that mounts the service account which was created by terraform. -var _ = Describe("[awsmanaged] with mounted IRSA", Label("aws", "secretsmanager", "managed"), func() { - f := framework.New("eso-aws-managed") - prov := NewFromEnv(f) - - // each test case gets its own ESO instance - BeforeEach(func() { - f.Install(addon.NewESO( - addon.WithControllerClass(f.BaseName), - addon.WithServiceAccount(prov.ServiceAccountName), - addon.WithReleaseName(f.Namespace.Name), - addon.WithNamespace("default"), - )) - }) - - DescribeTable("sync secrets", - framework.TableFunc(f, - prov), - framework.Compose(withMountedIRSA, f, common.SimpleDataSync, useMountedIRSAStore(prov)), - framework.Compose(withMountedIRSA, f, common.NestedJSONWithGJSON, useMountedIRSAStore(prov)), - framework.Compose(withMountedIRSA, f, common.JSONDataFromSync, useMountedIRSAStore(prov)), - framework.Compose(withMountedIRSA, f, common.JSONDataWithProperty, useMountedIRSAStore(prov)), - framework.Compose(withMountedIRSA, f, common.JSONDataWithTemplate, useMountedIRSAStore(prov)), - framework.Compose(withMountedIRSA, f, common.DockerJSONConfig, useMountedIRSAStore(prov)), - framework.Compose(withMountedIRSA, f, common.DataPropertyDockerconfigJSON, useMountedIRSAStore(prov)), - framework.Compose(withMountedIRSA, f, common.SSHKeySync, useMountedIRSAStore(prov)), - framework.Compose(withMountedIRSA, f, common.SSHKeySyncDataProperty, useMountedIRSAStore(prov)), - framework.Compose(withMountedIRSA, f, common.SyncWithoutTargetName, useMountedIRSAStore(prov)), - framework.Compose(withMountedIRSA, f, common.JSONDataWithoutTargetName, useMountedIRSAStore(prov)), - ) -}) - -func useClusterSecretStore(prov *SMProvider) func(*framework.TestCase) { - return func(tc *framework.TestCase) { - tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.ClusterSecretStoreKind - tc.ExternalSecret.Spec.SecretStoreRef.Name = prov.ReferencedIRSAStoreName() - } -} - -func useMountedIRSAStore(prov *SMProvider) func(*framework.TestCase) { - return func(tc *framework.TestCase) { - tc.ExternalSecret.Spec.SecretStoreRef.Kind = esv1alpha1.SecretStoreKind - tc.ExternalSecret.Spec.SecretStoreRef.Name = prov.MountedIRSAStoreName() - } -} diff --git a/e2e/suite/import.go b/e2e/suite/import.go index fd9c332f8..6e5d5fdb6 100644 --- a/e2e/suite/import.go +++ b/e2e/suite/import.go @@ -16,7 +16,8 @@ package suite import ( // import different e2e test suites. - _ "github.com/external-secrets/external-secrets/e2e/suite/aws" + _ "github.com/external-secrets/external-secrets/e2e/suite/aws/parameterstore" + _ "github.com/external-secrets/external-secrets/e2e/suite/aws/secretsmanager" _ "github.com/external-secrets/external-secrets/e2e/suite/azure" _ "github.com/external-secrets/external-secrets/e2e/suite/gcp" _ "github.com/external-secrets/external-secrets/e2e/suite/vault" diff --git a/terraform/aws/modules/cluster/irsa.tf b/terraform/aws/modules/cluster/irsa.tf index ba4a256a3..a4783f523 100644 --- a/terraform/aws/modules/cluster/irsa.tf +++ b/terraform/aws/modules/cluster/irsa.tf @@ -37,6 +37,25 @@ resource "aws_iam_role" "eso-e2e-irsa" { "arn:aws:iam::aws:policy/SecretsManagerReadWrite" ] + inline_policy { + name = "aws_ssm_parameterstore" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = [ + "ssm:GetParameter", + "ssm:PutParameter", + ] + Effect = "Allow" + Resource = "*" + }, + ] + }) + } + + } resource "null_resource" "apply_sa" {