Vault 凭证注入
> 本指南改编自 Vault on Minikube 和 Vault Kubernetes > Sidecar 指南。
大多数 crossplane 提供商至少支持提供以下来源的证书:
- Kubernetes secret
- 环境变量
- 文件系统
提供程序可以选择性地支持其他凭证源,但常用的凭证源涵盖了各种各样的用例。 在使用 Vault 进行secret管理的组织中,有一种特定用例很受欢迎,那就是使用侧卡将凭证注入文件系统。本指南将演示如何使用 Vault Kubernetes Sidecar 为 provider-gcp 和 provider-aws 提供凭证。
> 注: 在本指南中,我们将把 GCP 凭据和 AWS 访问密钥 > 复制到 Vault 的 KV secret引擎中。 这是一种使用 Vault > 管理secret的简单通用方法,但不如使用 Vault 的 > AWS、Azure 和 GCP 专用云提供商secret引擎那么强大。
设置
> 注意: 本指南将介绍如何设置 Vault 与 > Crossplane 在同一集群中运行。 您也可以选择使用现有的 Vault 实例,该实例在集群外运行,但已启用 Kubernetes 验证。
在开始之前,您必须确保已经安装了 crossplane 和 Vault,并且它们正在集群中运行。
1.安装 crossplane
1kubectl create namespace crossplane-system
2
3helm repo add crossplane-stable https://charts.crossplane.io/stable
4helm repo update
5
6helm install crossplane --namespace crossplane-system crossplane-stable/crossplane
2.安装 Vault Helm 图表
3.解封 Vault 实例
为了让 Vault 从物理存储中访问加密数据,必须对其进行 解封。
1kubectl exec vault-0 -- vault operator init -key-shares=1 -key-threshold=1 -format=json > cluster-keys.json
2VAULT_UNSEAL_KEY=$(cat cluster-keys.json | jq -r ".unseal_keys_b64[]")
3kubectl exec vault-0 -- vault operator unseal $VAULT_UNSEAL_KEY
4.启用 Kubernetes 验证方法
为了让Vault能够根据Kubernetes服务账户验证请求,必须启用Kubernetes身份验证后端。这需要登录Vault并配置服务账户令牌、API服务器地址和证书。由于我们是在Kubernetes中运行Vault,这些值已经可以通过容器文件系统和环境变量获得。
1cat cluster-keys.json | jq -r ".root_token" # get root token
2
3kubectl exec -it vault-0 -- /bin/sh
4vault login # use root token from above
5vault auth enable kubernetes
6
7vault write auth/kubernetes/config \
8 token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \
9 kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \
10 kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt
5.出口 Vault 集装箱
接下来的步骤将在本地环境中执行。
1exit
创建 GCP 服务账户
为了在 GCP 上配置基础设施,您需要创建一个具有适当权限的服务账户。 在本指南中,我们将只配置一个 CloudSQL 实例,因此服务账户将绑定到 “cloudsql.admin “角色。 以下步骤将设置一个 GCP 服务账户,赋予它必要的权限,以便 crossplane 能够管理 CloudSQL 实例,并在 JSON 文件中发出服务账户凭据。
1# replace this with your own gcp project id and the name of the service account
2# that will be created.
3PROJECT_ID=my-project
4NEW_SA_NAME=test-service-account-name
5
6# create service account
7SA="${NEW_SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com"
8gcloud iam service-accounts create $NEW_SA_NAME --project $PROJECT_ID
9
10# enable cloud API
11SERVICE="sqladmin.googleapis.com"
12gcloud services enable $SERVICE --project $PROJECT_ID
13
14# grant access to cloud API
15ROLE="roles/cloudsql.admin"
16gcloud projects add-iam-policy-binding --role="$ROLE" $PROJECT_ID --member "serviceAccount:$SA"
17
18# create service account keyfile
19gcloud iam service-accounts keys create creds.json --project $PROJECT_ID --iam-account $SA
现在,您应该在 creds.json
中获得有效的服务帐户凭据。
将凭据存储在 Vault 中
设置 Vault 后,您需要在 kv secrets engine 中存储凭证。
> 注意: 以下步骤涉及将凭证复制到容器 > 文件系统,然后再存储到 Vault 中。 您也可以选择将容器端口转发到本地环境 >(kubectl port-forward vault-0 8200:8200
),从而使用 Vault 的 > HTTP API 或用户界面。
1.将凭证文件复制到 Vault 容器中
将凭据复制到容器文件系统中,以便存储在 Vault 中。
1kubectl cp creds.json vault-0:/tmp/creds.json
2.启用 KV secret引擎
secret引擎必须启用后才能被引用。 在 secret
路径下启用 kv-v2
secret引擎。
3.在 KV 引擎中存储 GCP 凭据
将secret注入到 provider-gcp
控制器 Pod
时,您的 GCP 凭据的路径将被引用。
1vault kv put secret/provider-creds/gcp-default @tmp/creds.json
4.清理证书文件
您不再需要容器文件系统中的 GCP 凭据文件,所以请继续清理它。
1rm tmp/creds.json
创建 AWS IAM 用户
为了在 AWS 上调配基础设施,您需要使用现有的或创建具有适当权限的新 IAM 用户。 以下步骤将创建一个 AWS IAM 用户,并赋予其必要的权限。
> 注意: 如果您已有一个具有适当权限的 IAM 用户,则可以跳过此步骤,但仍需 > Provider ACCESS_KEY_ID
和 AWS_SECRET_ACCESS_KEY
环境变量的值。
1# create a new IAM user
2IAM_USER=test-user
3aws iam create-user --user-name $IAM_USER
4
5# grant the IAM user the necessary permissions
6aws iam attach-user-policy --user-name $IAM_USER --policy-arn arn:aws:iam::aws:policy/AmazonS3FullAccess
7
8# create a new IAM access key for the user
9aws iam create-access-key --user-name $IAM_USER > creds.json
10# assign the access key values to environment variables
11ACCESS_KEY_ID=$(jq -r .AccessKey.AccessKeyId creds.json)
12AWS_SECRET_ACCESS_KEY=$(jq -r .AccessKey.SecretAccessKey creds.json)
将凭据存储在 Vault 中
设置 Vault 后,您需要在 kv secrets engine 中存储凭证。
1.启用 KV secret引擎
secret引擎必须启用后才能被引用。 在 secret
路径下启用 kv-v2
secret引擎。
1kubectl exec -it vault-0 -- env \
2 ACCESS_KEY_ID=${ACCESS_KEY_ID} \
3 AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \
4 /bin/sh
5
6vault secrets enable -path=secret kv-v2
2.在 KV 引擎中存储 AWS 凭据
在将secret注入到 provider-aws
控制器 Pod
时,您的 AWS 凭据的路径将被引用。
vault kv put secret/provider-creds/aws-default access_key="$ACCESS_KEY_ID" secret_key="$AWS_SECRET_ACCESS_KEY"
为读取 Provider 凭据创建 Vault 策略
为了让我们的控制器能让 Vault sidecar 将凭证注入其文件系统,您必须将 Pod
与 policy 关联。该策略将允许在 kv-v2
secrets 引擎中读取和列出 provider-creds
路径上的所有 secrets。
1vault policy write provider-creds - <<EOF
2path "secret/data/provider-creds/*" {
3 capabilities = ["read", "list"]
4}
5EOF
为 Crossplane Provider Pods 创建角色
1.创建角色
最后一步是创建一个与你创建的策略绑定的角色,并将其与一组 Kubernetes 服务账户关联。 该角色可由 crossplane-system
名称空间中的任何 (*
) 服务账户承担。
1vault write auth/kubernetes/role/crossplane-providers \
2 bound_service_account_names="*" \
3 bound_service_account_namespaces=crossplane-system \
4 policies=provider-creds \
5 ttl=24h
2.出口 Vault 集装箱
接下来的步骤将在本地环境中执行。
1exit
安装 Provider-gcp
现在您已准备好安装 provider-gcp
。 Crossplane 提供了一种 ControllerConfig
类型,允许您自定义提供程序控制器 Pod
的部署。 ControllerConfig
可由任意数量的希望使用其配置的 Provider
对象创建和引用。 在下面的示例中,Pod
注释向 Vault mutating webhook 表示,我们希望将存储在 secret/provider-creds/gcp-default
的secret以 crossplane-providers
角色注入容器文件系统。 此外,还添加了模板格式,以确保secret数据以 provider-gcp
期望的形式呈现。
{% raw %}
1echo "apiVersion: pkg.crossplane.io/v1alpha1
2kind: ControllerConfig
3metadata:
4 name: vault-config
5spec:
6 metadata:
7 annotations:
8 vault.hashicorp.com/agent-inject: \"true\"
9 vault.hashicorp.com/role: "crossplane-providers"
10 vault.hashicorp.com/agent-inject-secret-creds.txt: "secret/provider-creds/gcp-default"
11 vault.hashicorp.com/agent-inject-template-creds.txt: |
12 {{- with secret \"secret/provider-creds/gcp-default\" -}}
13 {{ .Data.data | toJSON }}
14 {{- end -}}
15---
16apiVersion: pkg.crossplane.io/v1
17kind: Provider
18metadata:
19 name: provider-gcp
20spec:
21 package: xpkg.upbound.io/crossplane-contrib/provider-gcp:v0.22.0
22 controllerConfigRef:
23 name: vault-config" | kubectl apply -f -
{% endraw %}
配置 Provider-gcp
安装并运行 provider-gcp
后,您需要创建一个 ProviderConfig
来指定文件系统中的凭据,这些凭据应被用于调配引用此 ProviderConfig
的托管资源。 由于此 ProviderConfig
的名称是 default
,它将被任何未明确引用 ProviderConfig
的托管资源所使用。
> 注意: 请确保之前定义的 PROJECT_ID
环境变量 > 设置正确。
1echo "apiVersion: gcp.crossplane.io/v1beta1
2kind: ProviderConfig
3metadata:
4 name: default
5spec:
6 projectID: ${PROJECT_ID}
7 credentials:
8 source: Filesystem
9 fs:
10 path: /vault/secrets/creds.txt" | kubectl apply -f -
要验证 GCP 凭据是否已注入容器,请运行以下命令:
1PROVIDER_CONTROLLER_POD=$(kubectl -n crossplane-system get pod -l pkg.crossplane.io/provider=provider-gcp -o name --no-headers=true)
2kubectl -n crossplane-system exec -it $PROVIDER_CONTROLLER_POD -c provider-gcp -- cat /vault/secrets/creds.txt
提供基础设施
最后一步是实际配置一个 “CloudSQLInstance”。 创建以下对象将在 GCP 上创建一个云 SQL Postgres 数据库。
1echo "apiVersion: database.gcp.crossplane.io/v1beta1
2kind: CloudSQLInstance
3metadata:
4 name: postgres-vault-demo
5spec:
6 forProvider:
7 databaseVersion: POSTGRES_12
8 region: us-central1
9 settings:
10 tier: db-custom-1-3840
11 dataDiskType: PD_SSD
12 dataDiskSizeGb: 10
13 writeConnectionSecretToRef:
14 namespace: crossplane-system
15 name: cloudsqlpostgresql-conn" | kubectl apply -f -
您可以使用以下命令监控数据库配置的进度:
1kubectl get cloudsqlinstance -w
安装 Provider-aws
现在您已准备好安装 provider-aws
。 Crossplane 提供了一种 ControllerConfig
类型,允许您自定义提供程序控制器 Pod
的部署。 ControllerConfig
可由任意数量希望使用其配置的 Provider
对象创建和引用。 在下面的示例中, Pod
注解向 Vault mutating webhook 表示,我们希望将存储在 secret/provider-creds/aws-default
中的secret通过担任 crossplane-providers
角色注入容器文件系统。 还添加了一些模板格式,以确保secret数据以 provider-aws
期望的形式呈现。
{% raw %}
1echo "apiVersion: pkg.crossplane.io/v1alpha1
2kind: ControllerConfig
3metadata:
4 name: aws-vault-config
5spec:
6 args:
7 - --debug
8 metadata:
9 annotations:
10 vault.hashicorp.com/agent-inject: \"true\"
11 vault.hashicorp.com/role: \"crossplane-providers\"
12 vault.hashicorp.com/agent-inject-secret-creds.txt: \"secret/provider-creds/aws-default\"
13 vault.hashicorp.com/agent-inject-template-creds.txt: |
14 {{- with secret \"secret/provider-creds/aws-default\" -}}
15 [default]
16 aws_access_key_id="{{ .Data.data.access_key }}"
17 aws_secret_access_key="{{ .Data.data.secret_key }}"
18 {{- end -}}
19---
20apiVersion: pkg.crossplane.io/v1
21kind: Provider
22metadata:
23 name: provider-aws
24spec:
25 package: xpkg.upbound.io/crossplane-contrib/provider-aws:v0.33.0
26 controllerConfigRef:
27 name: aws-vault-config" | kubectl apply -f -
{% endraw %}
配置 Provider-aws
安装并运行 “provider-aws “后,您需要创建一个 “ProviderConfig”,指定文件系统中的凭据,用于调配引用该 “ProviderConfig “的托管资源。 由于该 “ProviderConfig “的名称是 “default”,因此将被任何未明确引用 “ProviderConfig “的托管资源所使用。
1echo "apiVersion: aws.crossplane.io/v1beta1
2kind: ProviderConfig
3metadata:
4 name: default
5spec:
6 credentials:
7 source: Filesystem
8 fs:
9 path: /vault/secrets/creds.txt" | kubectl apply -f -
要验证 AWS 凭据是否已注入容器,请运行以下命令:
1PROVIDER_CONTROLLER_POD=$(kubectl -n crossplane-system get pod -l pkg.crossplane.io/provider=provider-aws -o name --no-headers=true)
2kubectl -n crossplane-system exec -it $PROVIDER_CONTROLLER_POD -c provider-aws -- cat /vault/secrets/creds.txt
提供基础设施
最后一步是实际配置一个 “桶”。 创建以下对象将在 AWS 上创建一个 S3 桶。
1echo "apiVersion: s3.aws.crossplane.io/v1beta1
2kind: Bucket
3metadata:
4 name: s3-vault-demo
5spec:
6 forProvider:
7 acl: private
8 locationConstraint: us-east-1
9 publicAccessBlockConfiguration:
10 blockPublicPolicy: true
11 tagging:
12 tagSet:
13 - key: Name
14 value: s3-vault-demo
15 providerConfigRef:
16 name: default" | kubectl apply -f -
您可以使用以下命令监控水桶调配的进度:
1kubectl get bucket -w