diff --git a/e2e/deploy/vault/vault.yaml b/e2e/deploy/vault/vault.yaml index 972b028..ea1164f 100644 --- a/e2e/deploy/vault/vault.yaml +++ b/e2e/deploy/vault/vault.yaml @@ -146,6 +146,11 @@ spec: data: DOCKER_REPO_USER: dockerrepouser DOCKER_REPO_PASSWORD: dockerrepopassword + DOCKER_REPO_JSON_KEY: | + _json_key: { + "type": "service_account", + "project_id": "test" + } - type: kv path: secret/data/mysql data: diff --git a/e2e/test/secret-docker-json-key-vault.yaml b/e2e/test/secret-docker-json-key-vault.yaml new file mode 100644 index 0000000..22234c3 --- /dev/null +++ b/e2e/test/secret-docker-json-key-vault.yaml @@ -0,0 +1,21 @@ +apiVersion: v1 +kind: Secret +metadata: + name: test-secret-docker-json-key-vault + annotations: + secrets-webhook.security.bank-vaults.io/provider: "vault" + secrets-webhook.security.bank-vaults.io/vault-addr: "https://vault.default.svc.cluster.local:8200" + secrets-webhook.security.bank-vaults.io/vault-role: "default" + secrets-webhook.security.bank-vaults.io/vault-tls-secret: vault-tls + # secrets-webhook.security.bank-vaults.io/vault-skip-verify: "true" + secrets-webhook.security.bank-vaults.io/vault-path: "kubernetes" +type: kubernetes.io/dockerconfigjson +stringData: + .dockerconfigjson: | + { + "auths": { + "https://index.docker.io/v1/": { + "auth": "dmF1bHQ6c2VjcmV0L2RhdGEvZG9ja2VycmVwbyNET0NLRVJfUkVQT19KU09OX0tFWQ==" + } + } + } diff --git a/e2e/webhook_test.go b/e2e/webhook_test.go index 4a0389f..28f101f 100644 --- a/e2e/webhook_test.go +++ b/e2e/webhook_test.go @@ -39,6 +39,19 @@ import ( ) func TestSecretValueInjection(t *testing.T) { + type dockerAuth struct { + Username string `json:"username"` + Password string `json:"password"` + Auth string `json:"auth"` + } + + type auths struct { + DockerAuth dockerAuth `json:"https://index.docker.io/v1/"` + } + + type dockerconfig struct { + Auths auths `json:"auths"` + } secretVault := applyResource(features.New("secret-vault"), "secret-vault.yaml"). Assess("object created", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { secrets := &v1.SecretList{ @@ -61,28 +74,50 @@ func TestSecretValueInjection(t *testing.T) { err := cfg.Client().Resources(cfg.Namespace()).Get(ctx, "test-secret-vault", cfg.Namespace(), &secret) require.NoError(t, err) - type v1 struct { - Username string `json:"username"` - Password string `json:"password"` - Auth string `json:"auth"` - } + var dockerconfigjson dockerconfig - type auths struct { - V1 v1 `json:"https://index.docker.io/v1/"` - } + err = json.Unmarshal(secret.Data[".dockerconfigjson"], &dockerconfigjson) + require.NoError(t, err) + + dockerrepoauth := base64.StdEncoding.EncodeToString([]byte("dockerrepouser:dockerrepopassword")) + assert.Equal(t, "dockerrepouser", dockerconfigjson.Auths.DockerAuth.Username) + assert.Equal(t, "dockerrepopassword", dockerconfigjson.Auths.DockerAuth.Password) + assert.Equal(t, dockerrepoauth, dockerconfigjson.Auths.DockerAuth.Auth) + assert.Equal(t, "Inline: secretId AWS_ACCESS_KEY_ID", string(secret.Data["inline"])) - type dockerconfig struct { - Auths auths `json:"auths"` + return ctx + }). + Feature() + + secretDockerJsonKey := applyResource(features.New("secret-docker-json-key-vault"), "secret-docker-json-key-vault.yaml"). + Assess("object created", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { + secrets := &v1.SecretList{ + Items: []v1.Secret{ + { + ObjectMeta: metav1.ObjectMeta{Name: "test-secret-docker-json-key-vault", Namespace: cfg.Namespace()}, + }, + }, } + // wait for the secret to become available + err := wait.For(conditions.New(cfg.Client().Resources()).ResourcesFound(secrets), wait.WithTimeout(defaultTimeout)) + require.NoError(t, err) + + return ctx + }). + Assess("secret values are injected", func(ctx context.Context, t *testing.T, cfg *envconf.Config) context.Context { + var secret v1.Secret + + err := cfg.Client().Resources(cfg.Namespace()).Get(ctx, "test-secret-docker-json-key-vault", cfg.Namespace(), &secret) + require.NoError(t, err) + var dockerconfigjson dockerconfig err = json.Unmarshal(secret.Data[".dockerconfigjson"], &dockerconfigjson) require.NoError(t, err) - assert.Equal(t, "dockerrepouser", dockerconfigjson.Auths.V1.Username) - assert.Equal(t, "dockerrepopassword", dockerconfigjson.Auths.V1.Password) - assert.Equal(t, "Inline: secretId AWS_ACCESS_KEY_ID", string(secret.Data["inline"])) + dockerrepoauth := base64.StdEncoding.EncodeToString([]byte("_json_key: {\n \"type\": \"service_account\",\n \"project_id\": \"test\"\n}\n")) + assert.Equal(t, dockerrepoauth, dockerconfigjson.Auths.DockerAuth.Auth) return ctx }). @@ -119,7 +154,7 @@ func TestSecretValueInjection(t *testing.T) { }). Feature() - testenv.Test(t, secretVault, configMapVault) + testenv.Test(t, secretVault, secretDockerJsonKey, configMapVault) } func TestPodMutation(t *testing.T) { diff --git a/pkg/provider/bao/secret.go b/pkg/provider/bao/secret.go index 9aab08a..5b1dacd 100644 --- a/pkg/provider/bao/secret.go +++ b/pkg/provider/bao/secret.go @@ -99,7 +99,7 @@ func mutateDockerCreds(secret *corev1.Secret, dc *common.DockerCredentials, inje return errors.Wrap(err, "retrieving data from bao failed") } - assembled.Auths[key] = common.AssembleDockerAuthConfig(dcCreds, creds) + assembled.Auths[key] = common.AssembleDockerAuthConfig(dcCreds) } } diff --git a/pkg/provider/common/secret.go b/pkg/provider/common/secret.go index ad618f5..39f0b65 100644 --- a/pkg/provider/common/secret.go +++ b/pkg/provider/common/secret.go @@ -48,55 +48,38 @@ type DockerAuthConfig struct { func AssembleCredentialData(authCreds map[string]string) (map[string]string, error) { if username, ok := authCreds["username"]; ok { if password, ok := authCreds["password"]; ok { - credentialData := map[string]string{ + return map[string]string{ "username": username, "password": password, - } - - return credentialData, nil + }, nil } } if auth, ok := authCreds["auth"]; ok { - credentialData := map[string]string{ + return map[string]string{ "auth": auth, - } - - return credentialData, nil + }, nil } return nil, fmt.Errorf("no valid credentials found") } // assembleDockerAuthConfig assembles the DockerAuthConfig from the retrieved data from Vault -func AssembleDockerAuthConfig(dcCreds map[string]string, creds DockerAuthConfig) DockerAuthConfig { +func AssembleDockerAuthConfig(dcCreds map[string]string) DockerAuthConfig { if username, ok := dcCreds["username"]; ok { if password, ok := dcCreds["password"]; ok { - auth := fmt.Sprintf("%s:%s", username, password) - - dockerAuth := DockerAuthConfig{ - Auth: base64.StdEncoding.EncodeToString([]byte(auth)), + return DockerAuthConfig{ + Username: username, + Password: password, + Auth: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s:%s", username, password))), } - - if creds.Username != "" && creds.Password != "" { - dockerAuth.Username = dcCreds["username"] - dockerAuth.Password = dcCreds["password"] - } - - return dockerAuth } } if auth, ok := dcCreds["auth"]; ok { - dockerAuth := DockerAuthConfig{ + return DockerAuthConfig{ Auth: base64.StdEncoding.EncodeToString([]byte(auth)), } - - if creds.Auth != "" { - dockerAuth.Auth = auth - } - - return dockerAuth } return DockerAuthConfig{} diff --git a/pkg/provider/vault/secret.go b/pkg/provider/vault/secret.go index eb5fce8..441e31a 100644 --- a/pkg/provider/vault/secret.go +++ b/pkg/provider/vault/secret.go @@ -99,7 +99,7 @@ func mutateDockerCreds(secret *corev1.Secret, dc *common.DockerCredentials, inje return errors.Wrap(err, "retrieving data from vault failed") } - assembled.Auths[key] = common.AssembleDockerAuthConfig(dcCreds, creds) + assembled.Auths[key] = common.AssembleDockerAuthConfig(dcCreds) } }