From a47a68ba1c5a71bd001297e5d3d31d26f016a4ef Mon Sep 17 00:00:00 2001 From: Tom Proctor Date: Wed, 15 Jun 2022 00:11:42 +0100 Subject: [PATCH 1/7] Use token from CSI TokenRequests --- Makefile | 5 +++-- internal/config/config.go | 32 ++++++++++++++++++++++++++++---- internal/config/config_test.go | 34 ++++++++++++++++++---------------- internal/provider/provider.go | 17 +++++++++++------ main.go | 1 - test/bats/provider.bats | 5 +++++ 6 files changed, 65 insertions(+), 29 deletions(-) diff --git a/Makefile b/Makefile index fa0b4f3..c7fc6ac 100644 --- a/Makefile +++ b/Makefile @@ -17,7 +17,7 @@ LDFLAGS?="-X '$(PKG).BuildVersion=$(VERSION)' \ -X '$(PKG).BuildDate=$(BUILD_DATE)' \ -X '$(PKG).GoVersion=$(shell go version)'" K8S_VERSION?=v1.22.2 -CSI_DRIVER_VERSION=1.0.0 +CSI_DRIVER_VERSION=1.1.2 VAULT_HELM_VERSION=0.16.1 CI_TEST_ARGS?= @@ -68,7 +68,8 @@ e2e-setup: --wait --timeout=5m \ --namespace=csi \ --set linux.image.pullPolicy="IfNotPresent" \ - --set syncSecret.enabled=true + --set syncSecret.enabled=true \ + --set tokenRequests[0].audience="vault" helm install vault-bootstrap test/bats/configs/vault \ --namespace=csi helm install vault https://github.com/hashicorp/vault-helm/archive/v$(VAULT_HELM_VERSION).tar.gz \ diff --git a/internal/config/config.go b/internal/config/config.go index 5983254..6582451 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -74,10 +74,11 @@ type Parameters struct { } type PodInfo struct { - Name string - UID types.UID - Namespace string - ServiceAccountName string + Name string + UID types.UID + Namespace string + ServiceAccountName string + ServiceAccountToken string } type Secret struct { @@ -148,6 +149,29 @@ func parseParameters(parametersStr string) (Parameters, error) { return Parameters{}, err } + tokensJSON := params["csi.storage.k8s.io/serviceAccount.tokens"] + if tokensJSON != "" { + // The csi.storage.k8s.io/serviceAccount.tokens field is a JSON object + // marshalled into a string. The object keys are audience name (string) + // and the values are embedded objects with "token" and + // "expirationTimestamp" fields for the corresponding audience. + var tokens map[string]struct { + Token string `json:"token"` + ExpirationTimestamp string `json:"expirationTimestamp"` + } + if err := json.Unmarshal([]byte(tokensJSON), &tokens); err != nil { + return Parameters{}, fmt.Errorf("failed to unmarshal service account tokens: %w", err) + } + + audience := "vault" + if parameters.Audience != "" { + audience = parameters.Audience + } + if token, ok := tokens[audience]; ok { + parameters.PodInfo.ServiceAccountToken = token.Token + } + } + return parameters, nil } diff --git a/internal/config/config_test.go b/internal/config/config_test.go index 0a0806e..2b2c391 100644 --- a/internal/config/config_test.go +++ b/internal/config/config_test.go @@ -142,22 +142,23 @@ func TestParseConfig(t *testing.T) { name: "set all options", targetPath: targetPath, parameters: map[string]string{ - "roleName": "example-role", - "vaultSkipTLSVerify": "true", - "vaultAddress": "my-vault-address", - "vaultNamespace": "my-vault-namespace", - "vaultKubernetesMountPath": "my-mount-path", - "vaultCACertPath": "my-ca-cert-path", - "vaultCADirectory": "my-ca-directory", - "vaultTLSServerName": "mytls-server-name", - "vaultTLSClientCertPath": "my-tls-client-cert-path", - "vaultTLSClientKeyPath": "my-tls-client-key-path", - "csi.storage.k8s.io/pod.name": "my-pod-name", - "csi.storage.k8s.io/pod.uid": "my-pod-uid", - "csi.storage.k8s.io/pod.namespace": "my-pod-namespace", - "csi.storage.k8s.io/serviceAccount.name": "my-pod-sa-name", - "objects": objects, - "audience": "my-aud", + "roleName": "example-role", + "vaultSkipTLSVerify": "true", + "vaultAddress": "my-vault-address", + "vaultNamespace": "my-vault-namespace", + "vaultKubernetesMountPath": "my-mount-path", + "vaultCACertPath": "my-ca-cert-path", + "vaultCADirectory": "my-ca-directory", + "vaultTLSServerName": "mytls-server-name", + "vaultTLSClientCertPath": "my-tls-client-cert-path", + "vaultTLSClientKeyPath": "my-tls-client-key-path", + "csi.storage.k8s.io/pod.name": "my-pod-name", + "csi.storage.k8s.io/pod.uid": "my-pod-uid", + "csi.storage.k8s.io/pod.namespace": "my-pod-namespace", + "csi.storage.k8s.io/serviceAccount.name": "my-pod-sa-name", + "csi.storage.k8s.io/serviceAccount.tokens": `{"my-aud": {"token": "my-pod-sa-token", "expirationTimestamp": "bar"}, "other-aud": {"token": "unused-token"}}`, + "objects": objects, + "audience": "my-aud", }, expected: Config{ TargetPath: targetPath, @@ -183,6 +184,7 @@ func TestParseConfig(t *testing.T) { "my-pod-uid", "my-pod-namespace", "my-pod-sa-name", + "my-pod-sa-token", }, Audience: "my-aud", }, diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 6e5303f..966f58d 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -81,19 +81,24 @@ func (p *provider) createJWTToken(ctx context.Context, podInfo config.PodInfo, a func (p *provider) login(ctx context.Context, client *api.Client, params config.Parameters) error { p.logger.Debug("performing vault login") - jwt, err := p.createJWTToken(ctx, params.PodInfo, params.Audience) - if err != nil { - return err + jwt := params.PodInfo.ServiceAccountToken + if jwt == "" { + p.logger.Debug("no suitable token found in mount request, falling back to generating service account JWT") + var err error + jwt, err = p.createJWTToken(ctx, params.PodInfo, params.Audience) + if err != nil { + return err + } } req := client.NewRequest(http.MethodPost, "/v1/auth/"+params.VaultKubernetesMountPath+"/login") - err = req.SetJSONBody(map[string]string{ + if err := req.SetJSONBody(map[string]string{ "role": params.VaultRoleName, "jwt": jwt, - }) - if err != nil { + }); err != nil { return err } + secret, err := vaultclient.Do(ctx, client, req) if err != nil { return fmt.Errorf("failed to login: %w", err) diff --git a/main.go b/main.go index c7dd54b..b027c08 100644 --- a/main.go +++ b/main.go @@ -72,7 +72,6 @@ func realMain(logger hclog.Logger) error { grpc.UnaryInterceptor(func(ctx context.Context, req interface{}, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (interface{}, error) { startTime := time.Now() serverLogger.Info("Processing unary gRPC call", "grpc.method", info.FullMethod) - serverLogger.Debug("Request contents", "req", req) resp, err := handler(ctx, req) serverLogger.Info("Finished unary gRPC call", "grpc.method", info.FullMethod, "grpc.time", time.Since(startTime), "grpc.code", status.Code(err), "err", err) return resp, err diff --git a/test/bats/provider.bats b/test/bats/provider.bats index 8c8d955..c7f5b6c 100644 --- a/test/bats/provider.bats +++ b/test/bats/provider.bats @@ -43,11 +43,13 @@ setup(){ kubectl --namespace=csi exec vault-0 -- vault write auth/kubernetes/role/db-role \ bound_service_account_names=nginx-db \ bound_service_account_namespaces=test \ + audience=vault \ policies=db-policy \ ttl=20m kubectl --namespace=csi exec vault-0 -- vault write auth/kubernetes/role/kv-role \ bound_service_account_names=nginx-kv \ bound_service_account_namespaces=test \ + audience=vault \ policies=kv-policy \ ttl=20m kubectl --namespace=csi exec vault-0 -- vault write auth/kubernetes/role/kv-custom-audience-role \ @@ -59,16 +61,19 @@ setup(){ kubectl --namespace=csi exec vault-0 -- vault write -namespace=acceptance auth/kubernetes/role/kv-namespace-role \ bound_service_account_names=nginx-kv-namespace \ bound_service_account_namespaces=test \ + audience=vault \ policies=kv-namespace-policy \ ttl=20m kubectl --namespace=csi exec vault-0 -- vault write auth/kubernetes/role/pki-role \ bound_service_account_names=nginx-pki \ bound_service_account_namespaces=test \ + audience=vault \ policies=pki-policy \ ttl=20m kubectl --namespace=csi exec vault-0 -- vault write auth/kubernetes/role/all-role \ bound_service_account_names=nginx-all \ bound_service_account_namespaces=test \ + audience=vault \ policies=db-policy,kv-policy,pki-policy \ ttl=20m From 632e6c74d353b886d97069349c0187a9ef0b8088 Mon Sep 17 00:00:00 2001 From: Tom Proctor Date: Fri, 17 Jun 2022 14:29:31 +0100 Subject: [PATCH 2/7] Add changelog note and set 1.2.0 as the next version --- CHANGELOG.md | 7 +++++++ Makefile | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 58b0449..000e3c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,13 @@ CHANGES: * Duplicate object names now trigger an error instead of silently overwriting files. [[GH-148](https://github.com/hashicorp/vault-csi-provider/pull/148)] +* Vault CSI Provider will use service account tokens passed from the Secrets Store CSI Driver instead of generating one if an appropriate token is provided. [[GH-163](https://github.com/hashicorp/vault-csi-provider/pull/163)] + * **NOTE:** Generating service account tokens within the Vault CSI Provider will be deprecated in **1.4.0**. + The Secrets Store CSI driver will need to be configured to generate tokens for the "vault" audience, but you can + opt-in to use the new behavior before that release. To do so, use the + [`tokenRequests`](https://github.com/kubernetes-sigs/secrets-store-csi-driver/tree/main/charts/secrets-store-csi-driver#configuration) + option from the _driver_ helm chart via the flag `--set tokenRequests[0].audience="vault"`. See + [CSI TokenRequests documentation](https://kubernetes-csi.github.io/docs/token-requests.html) for further details. BUGS: diff --git a/Makefile b/Makefile index c7fc6ac..74760ad 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ REGISTRY_NAME?=docker.io/hashicorp IMAGE_NAME=vault-csi-provider # VERSION defines the next version to build/release -VERSION?=1.1.1 +VERSION?=1.2.0 IMAGE_TAG=$(REGISTRY_NAME)/$(IMAGE_NAME):$(VERSION) IMAGE_TAG_LATEST=$(REGISTRY_NAME)/$(IMAGE_NAME):latest # https://reproducible-builds.org/docs/source-date-epoch/ From 96fceceee762939e042a477bea6c29a3b48ca3f6 Mon Sep 17 00:00:00 2001 From: Tom Proctor Date: Fri, 17 Jun 2022 18:03:18 +0100 Subject: [PATCH 3/7] PR suggestion: Update changelog wording Co-authored-by: Christopher Swenson --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 000e3c9..f7c6632 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGES: * Duplicate object names now trigger an error instead of silently overwriting files. [[GH-148](https://github.com/hashicorp/vault-csi-provider/pull/148)] * Vault CSI Provider will use service account tokens passed from the Secrets Store CSI Driver instead of generating one if an appropriate token is provided. [[GH-163](https://github.com/hashicorp/vault-csi-provider/pull/163)] - * **NOTE:** Generating service account tokens within the Vault CSI Provider will be deprecated in **1.4.0**. + * **NOTE:** Generating service account tokens is deprecated within the Vault CSI Provider and will be removed in **1.4.0**. The Secrets Store CSI driver will need to be configured to generate tokens for the "vault" audience, but you can opt-in to use the new behavior before that release. To do so, use the [`tokenRequests`](https://github.com/kubernetes-sigs/secrets-store-csi-driver/tree/main/charts/secrets-store-csi-driver#configuration) From 7c6047d01ce72ed9ae850d2d2c8336ea855e9082 Mon Sep 17 00:00:00 2001 From: Tom Proctor Date: Fri, 17 Jun 2022 18:14:11 +0100 Subject: [PATCH 4/7] Breaking change slated for 2.0.0 instead --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f7c6632..695e0ac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGES: * Duplicate object names now trigger an error instead of silently overwriting files. [[GH-148](https://github.com/hashicorp/vault-csi-provider/pull/148)] * Vault CSI Provider will use service account tokens passed from the Secrets Store CSI Driver instead of generating one if an appropriate token is provided. [[GH-163](https://github.com/hashicorp/vault-csi-provider/pull/163)] - * **NOTE:** Generating service account tokens is deprecated within the Vault CSI Provider and will be removed in **1.4.0**. + * **NOTE:** Generating service account tokens is deprecated within the Vault CSI Provider and will be removed in **2.0.0**. The Secrets Store CSI driver will need to be configured to generate tokens for the "vault" audience, but you can opt-in to use the new behavior before that release. To do so, use the [`tokenRequests`](https://github.com/kubernetes-sigs/secrets-store-csi-driver/tree/main/charts/secrets-store-csi-driver#configuration) From 6d62f53986fa3d4eebd9bce38757a52f5436e46f Mon Sep 17 00:00:00 2001 From: Tom Proctor Date: Fri, 17 Jun 2022 18:14:41 +0100 Subject: [PATCH 5/7] Wording --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 695e0ac..b15a9e5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,7 +4,7 @@ CHANGES: * Duplicate object names now trigger an error instead of silently overwriting files. [[GH-148](https://github.com/hashicorp/vault-csi-provider/pull/148)] * Vault CSI Provider will use service account tokens passed from the Secrets Store CSI Driver instead of generating one if an appropriate token is provided. [[GH-163](https://github.com/hashicorp/vault-csi-provider/pull/163)] - * **NOTE:** Generating service account tokens is deprecated within the Vault CSI Provider and will be removed in **2.0.0**. + * **NOTE:** Generating service account tokens within the Vault CSI Provider is deprecated and will be removed in **2.0.0**. The Secrets Store CSI driver will need to be configured to generate tokens for the "vault" audience, but you can opt-in to use the new behavior before that release. To do so, use the [`tokenRequests`](https://github.com/kubernetes-sigs/secrets-store-csi-driver/tree/main/charts/secrets-store-csi-driver#configuration) From 57ade4161dc09a4d30b516dfeb895a6c856eb244 Mon Sep 17 00:00:00 2001 From: Tom Proctor Date: Mon, 20 Mar 2023 15:15:10 +0000 Subject: [PATCH 6/7] Don't commit to deprecating token requests from the provider --- CHANGELOG.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2b377f5..bde63c0 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -24,9 +24,9 @@ CHANGES: * Duplicate object names now trigger an error instead of silently overwriting files. [[GH-148](https://github.com/hashicorp/vault-csi-provider/pull/148)] * Vault CSI Provider will use service account tokens passed from the Secrets Store CSI Driver instead of generating one if an appropriate token is provided. [[GH-163](https://github.com/hashicorp/vault-csi-provider/pull/163)] - * **NOTE:** Generating service account tokens within the Vault CSI Provider is deprecated and will be removed in **2.0.0**. - The Secrets Store CSI driver will need to be configured to generate tokens for the "vault" audience, but you can - opt-in to use the new behavior before that release. To do so, use the + * The Secrets Store CSI driver needs to be configured to generate tokens with the correct audience for this feature. Vault CSI Provider + will look for a token with the audience specified in the SecretProviderClass, or otherwise "vault". To configure the driver to generate + a token with the correct audience, use the [`tokenRequests`](https://github.com/kubernetes-sigs/secrets-store-csi-driver/tree/main/charts/secrets-store-csi-driver#configuration) option from the _driver_ helm chart via the flag `--set tokenRequests[0].audience="vault"`. See [CSI TokenRequests documentation](https://kubernetes-csi.github.io/docs/token-requests.html) for further details. From d2268b363e9ec9139b2115f03681b7413aa92a49 Mon Sep 17 00:00:00 2001 From: Tom Proctor Date: Mon, 20 Mar 2023 16:30:07 +0000 Subject: [PATCH 7/7] Hopefully address flaky acceptance test due to slow image pull --- test/bats/_helpers.bash | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/test/bats/_helpers.bash b/test/bats/_helpers.bash index 5049f4a..c156b9d 100644 --- a/test/bats/_helpers.bash +++ b/test/bats/_helpers.bash @@ -14,13 +14,16 @@ wait_for_success() { } setup_postgres() { - # Setup postgres + # Setup postgres, pulling the image first to help avoid CI timeouts. + POSTGRES_IMAGE="$(awk '/image:/{print $NF}' $CONFIGS/postgres.yaml)" + docker pull "${POSTGRES_IMAGE}" + kind load docker-image "${POSTGRES_IMAGE}" POSTGRES_PASSWORD=$(openssl rand -base64 30) kubectl --namespace=test create secret generic postgres-root \ --from-literal=POSTGRES_USER="root" \ --from-literal=POSTGRES_PASSWORD="${POSTGRES_PASSWORD}" kubectl --namespace=test apply -f $CONFIGS/postgres.yaml - kubectl wait --namespace=test --for=condition=Ready --timeout=5m pod -l app=postgres + kubectl wait --namespace=test --for=condition=Ready --timeout=10m pod -l app=postgres # Configure vault to manage postgres kubectl --namespace=csi exec vault-0 -- vault secrets enable database