diff --git a/test/e2e/e2e_test.go b/test/e2e/e2e_test.go index 2a6a61fa3..c81cf10a0 100644 --- a/test/e2e/e2e_test.go +++ b/test/e2e/e2e_test.go @@ -227,4 +227,109 @@ var _ = Describe("External Secrets Operator End-to-End test scenarios", Ordered, }, time.Minute, 10*time.Second).Should(Succeed()) }) }) + + // TODO: Update vault.yaml + Context("Vault Secret Manager", Label("SecretProvider:Vault"), func() { + const ( + clusterSecretStoreFile = "testdata/vault/secret_store.yaml" + externalSecretFile = "testdata/vault/external_secret.yaml" + pushSecretFile = "testdata/vault/push_secret.yaml" + secretToPushFile = "testdata/vault/_push_secret.yaml" + secretNamePattern = "${SECRET_KEY_NAME}" + secretValuePattern = "${SECRET_VALUE}" + clusterSecretStoreNamePattern = "${CLUSTERSECRETSTORE_NAME}" + ) + + AfterAll(func() { + By("Deleting the Vault secret") + // TODO: make a similar method/approach that checks to see that the secret is deleted. + Expect(utils.DeleteVaultSecret(ctx, clientset, secretName, secretRegionName)). + NotTo(HaveOccurred(), "failed to delete Vault secret test/e2e") + }) + + It("should create secrets mentioned in ExternalSecret using the referenced ClusterSecretStore", func() { + var ( + // test bindata for Vault + vaultExternalSecretConfigFile = "testdata/vault/external_secret_config.yaml" + vaultClusterSecretStoreFile = "testdata/vault/cluster_secret_store.yaml" + vaultExternalSecretFile = "testdata/vault/external_secret.yaml" + vaultPushSecretFile = "testdata/vault/push_secret.yaml" + clusterSecretStoreResourceName = fmt.Sprintf("vault-secret-store-%s", utils.GetRandomString(5)) + pushSecretResourceName = "vault-push-secret" + externalSecretResourceName = "vault-external-secret" + secretResourceName = "vault-secret" + keyNameInSecret = "vault_secret_access_key" + ) + + defer func() { + // TODO: make a similar method/approach that checks to see that the secret is deleted. + Expect(utils.DeleteVaultSecret(ctx, clientset, secretName, secretRegionName)). + NotTo(HaveOccurred(), "failed to delete Vault secret test/e2e") + }() + + expectedSecretValue, err := utils.ReadExpectedSecretValue(expectedSecretValueFile) + Expect(err).To(Succeed()) + + By("Creating kubernetes secret to be used in PushSecret") + secretsAssetFunc := utils.ReplacePatternInAsset(secretValuePattern, base64.StdEncoding.EncodeToString(expectedSecretValue)) + loader.CreateFromFile(secretsAssetFunc, vaultPushSecretFile, testNamespace) + defer loader.DeleteFromFile(testassets.ReadFile, vaultPushSecretFile, testNamespace) + + By("Creating ClusterSecretStore") + cssAssetFunc := utils.ReplacePatternInAsset(clusterSecretStoreNamePattern, clusterSecretStoreResourceName) + loader.CreateFromFile(cssAssetFunc, vaultClusterSecretStoreFile, testNamespace) + defer loader.DeleteFromFile(cssAssetFunc, vaultClusterSecretStoreFile, testNamespace) + + By("Waiting for ClusterSecretStore to become Ready") + Expect(utils.WaitForESOResourceReady(ctx, dynamicClient, + schema.GroupVersionResource{ + Group: externalSecretsGroupName, + Version: v1APIVersion, + Resource: clusterSecretStoresKind, + }, + "", clusterSecretStoreResourceName, time.Minute, + )).To(Succeed()) + + By("Creating PushSecret") + assetFunc := utils.ReplacePatternInAsset(secretNamePattern, secretName, + clusterSecretStoreNamePattern, clusterSecretStoreResourceName) + loader.CreateFromFile(assetFunc, vaultPushSecretFile, testNamespace) + defer loader.DeleteFromFile(testassets.ReadFile, vaultPushSecretFile, testNamespace) + + By("Waiting for PushSecret to become Ready") + Expect(utils.WaitForESOResourceReady(ctx, dynamicClient, + schema.GroupVersionResource{ + Group: externalSecretsGroupName, + Version: v1alpha1APIVersion, + Resource: PushSecretsKind, + }, + testNamespace, pushSecretResourceName, time.Minute, + )).To(Succeed()) + + By("Creating ExternalSecret") + loader.CreateFromFile(assetFunc, vaultExternalSecretFile, testNamespace) + defer loader.DeleteFromFile(testassets.ReadFile, vaultExternalSecretFile, testNamespace) + + By("Waiting for ExternalSecret to become Ready") + Expect(utils.WaitForESOResourceReady(ctx, dynamicClient, + schema.GroupVersionResource{ + Group: externalSecretsGroupName, + Version: v1APIVersion, + Resource: externalSecretsKind, + }, + testNamespace, externalSecretResourceName, time.Minute, + )).To(Succeed()) + + By("Waiting for target secret to be created with expected data") + Eventually(func(g Gomega) { + secret, err := loader.KubeClient.CoreV1().Secrets(testNamespace).Get(ctx, secretResourceName, metav1.GetOptions{}) + g.Expect(err).NotTo(HaveOccurred(), "should get %s from namespace %s", secretResourceName, testNamespace) + + val, ok := secret.Data[keyNameInSecret] + g.Expect(ok).To(BeTrue(), "%s should be present in secret %s", keyNameInSecret, secret.Name) + + g.Expect(val).To(Equal(expectedSecretValue), "%s does not match expected value", keyNameInSecret) + }, time.Minute, 10*time.Second).Should(Succeed()) + }) + }) }) diff --git a/test/e2e/testdata/vault/cluster_secret_store.yaml b/test/e2e/testdata/vault/cluster_secret_store.yaml new file mode 100644 index 000000000..13b03754f --- /dev/null +++ b/test/e2e/testdata/vault/cluster_secret_store.yaml @@ -0,0 +1,19 @@ +apiVersion: external-secrets.io/v1 +kind: ClusterSecretStore +metadata: + name: vault-store + namespace: vault-test +spec: + provider: + vault: + server: http://vault.vault-test.svc.cluster.local:8200 + path: secret + version: v2 + auth: + kubernetes: + mountPath: kubernetes + role: eso-role + serverAccountRef: + name: external-secrets + namespace: external-secrets + timeout: 30s \ No newline at end of file diff --git a/test/e2e/testdata/vault/external_secret.yaml b/test/e2e/testdata/vault/external_secret.yaml new file mode 100644 index 000000000..c76063424 --- /dev/null +++ b/test/e2e/testdata/vault/external_secret.yaml @@ -0,0 +1,17 @@ +apiVersion: external-secrets.io/v1 +kind: ExternalSecret +metadata: + name: vault-e2e-test + namespace: vault-test +spec: + refreshInterval: 10s + secretStoreRef: + name: vault-store + kind: SecretStore + target: + name: vault-e2e-test + data: + - secretKey: username + remoteRef: + key: secret/data/e2e-test + property: username \ No newline at end of file diff --git a/test/e2e/testdata/vault/external_secret_config.yaml b/test/e2e/testdata/vault/external_secret_config.yaml new file mode 100644 index 000000000..0d6c7d78d --- /dev/null +++ b/test/e2e/testdata/vault/external_secret_config.yaml @@ -0,0 +1,30 @@ +apiVersion: operator.openshift.io/v1alpha1 +kind: ExternalSecretsConfig +metadata: + labels: + app.kubernetes.io/name: cluster + app.kubernetes.io/managed-by: external-secrets-operator-e2e + name: cluster +spec: + controllerConfig: + networkPolicies: + - name: allow-external-secrets-egress + componentName: ExternalSecretsCoreController + egress: + # Allow egress to Kubernetes API server, AWS endpoints, and DNS + - to: [] + ports: + - protocol: TCP + port: 6443 # Kubernetes API + - protocol: TCP + port: 443 # HTTPS + - protocol: TCP + port: 5353 # DNS + - protocol: UDP + port: 5353 # DNS + - protocol: UDP + port: 53 # DNS + - protocol: TCP + port: 443 + - protocol: TCP + port: 8200 diff --git a/test/e2e/testdata/vault/push_secret.yaml b/test/e2e/testdata/vault/push_secret.yaml new file mode 100644 index 000000000..dcb9840c0 --- /dev/null +++ b/test/e2e/testdata/vault/push_secret.yaml @@ -0,0 +1,11 @@ +apiVersion: v1 +kind: Secret +metadata: + labels: + app.kubernetes.io/name: vault-k8s-push-secret + app.kubernetes.io/managed-by: external-secrets-operator-e2e + name: vault-k8s-push-secret + namespace: external-secrets +data: + aws_secret_access_key: ${SECRET_VALUE} +type: Opaque diff --git a/test/e2e/testdata/vault/vault.yaml b/test/e2e/testdata/vault/vault.yaml new file mode 100644 index 000000000..e69de29bb diff --git a/test/utils/conditions.go b/test/utils/conditions.go index 54cb0463b..23811608a 100644 --- a/test/utils/conditions.go +++ b/test/utils/conditions.go @@ -202,3 +202,7 @@ func ReplacePatternInAsset(replacePatternString ...string) AssetFunc { return []byte(replacedFileContent), nil } } + +func DeleteVaultSecret(ctx context.Context, k8sClient *kubernetes.Clientset, secretName, region string) error { + return nil +}