Просмотр исходного кода

Harden classic provider e2e env setup

Signed-off-by: Moritz Johner <beller.moritz@googlemail.com>
Moritz Johner 2 месяцев назад
Родитель
Сommit
bbfc06f71b

+ 46 - 9
e2e/suites/provider/cases/azure/provider.go

@@ -50,31 +50,68 @@ type azureProvider struct {
 	framework    *framework.Framework
 }
 
+type azureStaticEnvConfig struct {
+	VaultURL     string
+	TenantID     string
+	ClientID     string
+	ClientSecret string
+}
+
+func loadAzureStaticEnvConfig() azureStaticEnvConfig {
+	return azureStaticEnvConfig{
+		VaultURL:     os.Getenv("TFC_VAULT_URL"),
+		TenantID:     os.Getenv("TFC_AZURE_TENANT_ID"),
+		ClientID:     os.Getenv("TFC_AZURE_CLIENT_ID"),
+		ClientSecret: os.Getenv("TFC_AZURE_CLIENT_SECRET"),
+	}
+}
+
+func (c azureStaticEnvConfig) missingStaticEnv() []string {
+	var missing []string
+	if c.VaultURL == "" {
+		missing = append(missing, "TFC_VAULT_URL")
+	}
+	if c.TenantID == "" {
+		missing = append(missing, "TFC_AZURE_TENANT_ID")
+	}
+	if c.ClientID == "" {
+		missing = append(missing, "TFC_AZURE_CLIENT_ID")
+	}
+	if c.ClientSecret == "" {
+		missing = append(missing, "TFC_AZURE_CLIENT_SECRET")
+	}
+	return missing
+}
+
+func skipIfAzureStaticEnvMissing(cfg azureStaticEnvConfig) {
+	if missing := cfg.missingStaticEnv(); len(missing) > 0 {
+		Skip("missing Azure e2e environment: " + strings.Join(missing, ", "))
+	}
+}
+
 // newFromEnv creates a new Azure KeyVault e2e test provider
 // which uses client credentials flow to authenticate with azure.
 func newFromEnv(f *framework.Framework) *azureProvider {
-	vaultURL := os.Getenv("TFC_VAULT_URL")
-	tenantID := os.Getenv("TFC_AZURE_TENANT_ID")
-	clientID := os.Getenv("TFC_AZURE_CLIENT_ID")
-	clientSecret := os.Getenv("TFC_AZURE_CLIENT_SECRET")
+	cfg := loadAzureStaticEnvConfig()
 
 	basicClient := keyvault.New()
 	prov := &azureProvider{
 		framework:    f,
-		clientID:     clientID,
-		tenantID:     tenantID,
-		vaultURL:     vaultURL,
+		clientID:     cfg.ClientID,
+		tenantID:     cfg.TenantID,
+		vaultURL:     cfg.VaultURL,
 		client:       &basicClient,
-		clientSecret: clientSecret,
+		clientSecret: cfg.ClientSecret,
 	}
 
 	o := &sync.Once{}
 	BeforeEach(func() {
+		skipIfAzureStaticEnvMissing(cfg)
 		// run authorizor only if this spec is called
 		// this allows us to run OTHER providers using GINKGO_LABELS without bailing out
 		o.Do(func() {
 			defer GinkgoRecover()
-			clientCredentialsConfig := kvauth.NewClientCredentialsConfig(clientID, clientSecret, tenantID)
+			clientCredentialsConfig := kvauth.NewClientCredentialsConfig(cfg.ClientID, cfg.ClientSecret, cfg.TenantID)
 			clientCredentialsConfig.Resource = "https://vault.azure.net"
 			authorizer, err := clientCredentialsConfig.Authorizer()
 			if err != nil {

+ 37 - 0
e2e/suites/provider/cases/azure/provider_support_test.go

@@ -0,0 +1,37 @@
+package azure
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestAzureStaticEnvConfigMissingEnv(t *testing.T) {
+	t.Parallel()
+
+	cfg := azureStaticEnvConfig{}
+	want := []string{
+		"TFC_VAULT_URL",
+		"TFC_AZURE_TENANT_ID",
+		"TFC_AZURE_CLIENT_ID",
+		"TFC_AZURE_CLIENT_SECRET",
+	}
+
+	if got := cfg.missingStaticEnv(); !reflect.DeepEqual(got, want) {
+		t.Fatalf("missingStaticEnv() = %v, want %v", got, want)
+	}
+}
+
+func TestAzureStaticEnvConfigMissingEnvComplete(t *testing.T) {
+	t.Parallel()
+
+	cfg := azureStaticEnvConfig{
+		VaultURL:     "https://example.vault.azure.net/",
+		TenantID:     "tenant",
+		ClientID:     "client",
+		ClientSecret: "secret",
+	}
+
+	if got := cfg.missingStaticEnv(); len(got) != 0 {
+		t.Fatalf("missingStaticEnv() = %v, want none", got)
+	}
+}

+ 14 - 0
e2e/suites/provider/cases/delinea/config.go

@@ -29,6 +29,20 @@ type config struct {
 	clientSecret string
 }
 
+func missingRequiredEnvFromConfig(cfg config) []string {
+	var missing []string
+	if cfg.tenant == "" {
+		missing = append(missing, "DELINEA_TENANT")
+	}
+	if cfg.clientID == "" {
+		missing = append(missing, "DELINEA_CLIENT_ID")
+	}
+	if cfg.clientSecret == "" {
+		missing = append(missing, "DELINEA_CLIENT_SECRET")
+	}
+	return missing
+}
+
 func loadConfigFromEnv() (*config, error) {
 	var cfg config
 	var err error

+ 35 - 0
e2e/suites/provider/cases/delinea/config_test.go

@@ -0,0 +1,35 @@
+package delinea
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestMissingRequiredEnvFromConfig(t *testing.T) {
+	t.Parallel()
+
+	cfg := config{}
+	want := []string{
+		"DELINEA_TENANT",
+		"DELINEA_CLIENT_ID",
+		"DELINEA_CLIENT_SECRET",
+	}
+
+	if got := missingRequiredEnvFromConfig(cfg); !reflect.DeepEqual(got, want) {
+		t.Fatalf("missingRequiredEnvFromConfig() = %v, want %v", got, want)
+	}
+}
+
+func TestMissingRequiredEnvFromConfigComplete(t *testing.T) {
+	t.Parallel()
+
+	cfg := config{
+		tenant:       "tenant",
+		clientID:     "client",
+		clientSecret: "secret",
+	}
+
+	if got := missingRequiredEnvFromConfig(cfg); len(got) != 0 {
+		t.Fatalf("missingRequiredEnvFromConfig() = %v, want none", got)
+	}
+}

+ 9 - 0
e2e/suites/provider/cases/delinea/delinea.go

@@ -18,6 +18,8 @@ package delinea
 
 import (
 	"context"
+	"os"
+	"strings"
 
 	"github.com/external-secrets/external-secrets-e2e/framework"
 	"github.com/external-secrets/external-secrets-e2e/suites/provider/cases/common"
@@ -37,6 +39,13 @@ var _ = Describe("[delinea]", Label("delinea"), func() {
 	provider := &secretStoreProvider{}
 
 	BeforeEach(func() {
+		if missing := missingRequiredEnvFromConfig(config{
+			tenant:       os.Getenv("DELINEA_TENANT"),
+			clientID:     os.Getenv("DELINEA_CLIENT_ID"),
+			clientSecret: os.Getenv("DELINEA_CLIENT_SECRET"),
+		}); len(missing) > 0 {
+			Skip("missing Delinea e2e environment: " + strings.Join(missing, ", "))
+		}
 
 		cfg, err := loadConfigFromEnv()
 		gomega.Expect(err).ToNot(gomega.HaveOccurred())

+ 8 - 0
e2e/suites/provider/cases/gcp/gcp_managed.go

@@ -42,6 +42,7 @@ var _ = Describe("[gcpmanaged] with pod identity", Label("gcp", "secretsmanager"
 
 	// each test case gets its own ESO instance
 	BeforeEach(func() {
+		skipIfGCPManagedEnvMissing(prov.access)
 		f.Install(addon.NewESO(
 			addon.WithControllerClass(f.BaseName),
 			addon.WithServiceAccount(prov.ServiceAccountName),
@@ -50,6 +51,7 @@ var _ = Describe("[gcpmanaged] with pod identity", Label("gcp", "secretsmanager"
 			addon.WithoutWebhook(),
 			addon.WithoutCertController(),
 		))
+		prov.CreatePodIDStore()
 	})
 
 	DescribeTable("sync secrets",
@@ -79,6 +81,7 @@ var _ = Describe("[gcpmanaged] with service account", Label("gcp", "secretsmanag
 	prov := NewFromEnv(f, f.BaseName)
 
 	BeforeEach(func() {
+		skipIfGCPManagedEnvMissing(prov.access)
 		f.Install(addon.NewESO(
 			addon.WithControllerClass(f.BaseName),
 			addon.WithReleaseName(f.Namespace.Name),
@@ -86,6 +89,11 @@ var _ = Describe("[gcpmanaged] with service account", Label("gcp", "secretsmanag
 			addon.WithoutWebhook(),
 			addon.WithoutCertController(),
 		))
+		prov.CreateSpecifcSASecretStore()
+	})
+
+	AfterEach(func() {
+		prov.DeleteSpecifcSASecretStore()
 	})
 
 	DescribeTable("sync secrets",

+ 72 - 12
e2e/suites/provider/cases/gcp/provider.go

@@ -19,6 +19,7 @@ import (
 	"context"
 	"fmt"
 	"os"
+	"strings"
 
 	secretmanager "cloud.google.com/go/secretmanager/apiv1"
 
@@ -32,6 +33,7 @@ import (
 	"golang.org/x/oauth2/jwt"
 	"google.golang.org/api/option"
 	v1 "k8s.io/api/core/v1"
+	apierrors "k8s.io/apimachinery/pkg/api/errors"
 	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
 	utilpointer "k8s.io/utils/pointer"
 	"sigs.k8s.io/controller-runtime/pkg/controller/controllerutil"
@@ -53,10 +55,73 @@ type GcpProvider struct {
 	clusterLocation string
 	clusterName     string
 	controllerClass string
+	access          gcpAccessConfig
+}
+
+type gcpAccessConfig struct {
+	Credentials        string
+	ProjectID          string
+	ServiceAccountName string
+	ClusterLocation    string
+	ClusterName        string
+}
+
+func newGCPAccessConfigFromEnv() gcpAccessConfig {
+	return gcpAccessConfig{
+		Credentials:        os.Getenv("GCP_SERVICE_ACCOUNT_KEY"),
+		ProjectID:          os.Getenv("GCP_FED_PROJECT_ID"),
+		ServiceAccountName: os.Getenv("GCP_KSA_NAME"),
+		ClusterLocation:    os.Getenv("GCP_FED_REGION"),
+		ClusterName:        os.Getenv("GCP_GKE_CLUSTER"),
+	}
+}
+
+func (c gcpAccessConfig) missingStaticEnv() []string {
+	var missing []string
+	if c.Credentials == "" {
+		missing = append(missing, "GCP_SERVICE_ACCOUNT_KEY")
+	}
+	if c.ProjectID == "" {
+		missing = append(missing, "GCP_FED_PROJECT_ID")
+	}
+	return missing
+}
+
+func (c gcpAccessConfig) missingManagedEnv() []string {
+	var missing []string
+	if c.ServiceAccountName == "" {
+		missing = append(missing, "GCP_KSA_NAME")
+	}
+	if c.ClusterLocation == "" {
+		missing = append(missing, "GCP_FED_REGION")
+	}
+	if c.ClusterName == "" {
+		missing = append(missing, "GCP_GKE_CLUSTER")
+	}
+	return missing
+}
+
+func skipIfGCPStaticEnvMissing(access gcpAccessConfig) {
+	if missing := access.missingStaticEnv(); len(missing) > 0 {
+		Skip("missing GCP e2e environment: " + strings.Join(missing, ", "))
+	}
+}
+
+func skipIfGCPManagedEnvMissing(access gcpAccessConfig) {
+	if missing := access.missingManagedEnv(); len(missing) > 0 {
+		Skip("missing GCP managed identity environment: " + strings.Join(missing, ", "))
+	}
 }
 
 func NewGCPProvider(f *framework.Framework, credentials, projectID string,
 	clusterLocation string, clusterName string, serviceAccountName string, serviceAccountNamespace string, controllerClass string) *GcpProvider {
+	access := gcpAccessConfig{
+		Credentials:        credentials,
+		ProjectID:          projectID,
+		ServiceAccountName: serviceAccountName,
+		ClusterLocation:    clusterLocation,
+		ClusterName:        clusterName,
+	}
 	prov := &GcpProvider{
 		credentials:             credentials,
 		projectID:               projectID,
@@ -66,30 +131,22 @@ func NewGCPProvider(f *framework.Framework, credentials, projectID string,
 		ServiceAccountName:      serviceAccountName,
 		ServiceAccountNamespace: serviceAccountNamespace,
 		controllerClass:         controllerClass,
+		access:                  access,
 	}
 
 	BeforeEach(func() {
+		skipIfGCPStaticEnvMissing(prov.access)
 		prov.CreateSAKeyStore()
 		prov.CreateReferentSAKeyStore()
-		prov.CreateSpecifcSASecretStore()
-		prov.CreatePodIDStore()
-	})
-
-	AfterEach(func() {
-		prov.DeleteSpecifcSASecretStore()
 	})
 
 	return prov
 }
 
 func NewFromEnv(f *framework.Framework, controllerClass string) *GcpProvider {
-	projectID := os.Getenv("GCP_FED_PROJECT_ID")
-	credentials := os.Getenv("GCP_SERVICE_ACCOUNT_KEY")
-	serviceAccountName := os.Getenv("GCP_KSA_NAME")
+	access := newGCPAccessConfigFromEnv()
 	serviceAccountNamespace := "default"
-	clusterLocation := os.Getenv("GCP_FED_REGION")
-	clusterName := os.Getenv("GCP_GKE_CLUSTER")
-	return NewGCPProvider(f, credentials, projectID, clusterLocation, clusterName, serviceAccountName, serviceAccountNamespace, controllerClass)
+	return NewGCPProvider(f, access.Credentials, access.ProjectID, access.ClusterLocation, access.ClusterName, access.ServiceAccountName, serviceAccountNamespace, controllerClass)
 }
 
 func (s *GcpProvider) getClient(ctx context.Context) (client *secretmanager.Client, err error) {
@@ -286,5 +343,8 @@ func (s *GcpProvider) DeleteSpecifcSASecretStore() {
 			Name: s.SAClusterSecretStoreName(),
 		},
 	})
+	if apierrors.IsNotFound(err) {
+		return
+	}
 	Expect(err).ToNot(HaveOccurred())
 }

+ 54 - 0
e2e/suites/provider/cases/gcp/provider_support_test.go

@@ -0,0 +1,54 @@
+package gcp
+
+import (
+	"reflect"
+	"testing"
+)
+
+func TestGCPAccessConfigMissingStaticEnv(t *testing.T) {
+	t.Parallel()
+
+	cfg := gcpAccessConfig{}
+	want := []string{
+		"GCP_SERVICE_ACCOUNT_KEY",
+		"GCP_FED_PROJECT_ID",
+	}
+
+	if got := cfg.missingStaticEnv(); !reflect.DeepEqual(got, want) {
+		t.Fatalf("missingStaticEnv() = %v, want %v", got, want)
+	}
+}
+
+func TestGCPAccessConfigMissingManagedEnv(t *testing.T) {
+	t.Parallel()
+
+	cfg := gcpAccessConfig{}
+	want := []string{
+		"GCP_KSA_NAME",
+		"GCP_FED_REGION",
+		"GCP_GKE_CLUSTER",
+	}
+
+	if got := cfg.missingManagedEnv(); !reflect.DeepEqual(got, want) {
+		t.Fatalf("missingManagedEnv() = %v, want %v", got, want)
+	}
+}
+
+func TestGCPAccessConfigMissingEnvComplete(t *testing.T) {
+	t.Parallel()
+
+	cfg := gcpAccessConfig{
+		Credentials:        "creds",
+		ProjectID:          "project",
+		ServiceAccountName: "ksa",
+		ClusterLocation:    "region",
+		ClusterName:        "cluster",
+	}
+
+	if got := cfg.missingStaticEnv(); len(got) != 0 {
+		t.Fatalf("missingStaticEnv() = %v, want none", got)
+	}
+	if got := cfg.missingManagedEnv(); len(got) != 0 {
+		t.Fatalf("missingManagedEnv() = %v, want none", got)
+	}
+}