mirror of
https://github.com/external-secrets/external-secrets.git
synced 2024-12-14 11:57:59 +00:00
chore: implement aws parameterstore e2e tests
Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
This commit is contained in:
parent
5a8df8cb18
commit
64589cddda
10 changed files with 512 additions and 179 deletions
97
e2e/suite/aws/common.go
Normal file
97
e2e/suite/aws/common.go
Normal file
|
@ -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())
|
||||
}
|
45
e2e/suite/aws/parameterstore/parameterstore.go
Normal file
45
e2e/suite/aws/parameterstore/parameterstore.go
Normal file
|
@ -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)),
|
||||
)
|
||||
})
|
85
e2e/suite/aws/parameterstore/parameterstore_managed.go
Normal file
85
e2e/suite/aws/parameterstore/parameterstore_managed.go
Normal file
|
@ -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),
|
||||
)
|
||||
})
|
165
e2e/suite/aws/parameterstore/provider.go
Normal file
165
e2e/suite/aws/parameterstore/provider.go
Normal file
|
@ -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())
|
||||
}
|
|
@ -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())
|
||||
}
|
85
e2e/suite/aws/secretsmanager/secretsmanager_managed.go
Normal file
85
e2e/suite/aws/secretsmanager/secretsmanager_managed.go
Normal file
|
@ -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),
|
||||
)
|
||||
})
|
|
@ -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()
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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" {
|
||||
|
|
Loading…
Reference in a new issue