轻松使用 Amazon EKS 工作负载中的 Amazon Secrets Manager 密钥

利用密钥存储,无需复杂的代码修改。
发布时间:2023 年 10 月 30 日
EKS 集群设置
EKS
Kubernetes
教程
亚马逊云科技
Olawale Olaleye
亚马逊云科技使用经验
200 - 中级
完成所需时间
30 分钟
前提条件

注册 / 登录 亚马逊云科技账户

上次更新时间
2023 年 10 月 30 日

在大规模运行安全且动态的容器化应用程序时,密钥管理是难度较大却至关重要的一个方面。密钥需要安全地分发到正在运行的应用程序,Kubernetes 提供了原生功能来满足这一需求,将密钥以 Kubernetes 密钥的形式进行管理。但是,许多客户选择使用外部密钥存储服务(如 Amazon Secrets Manager)来集中管理其 Kubernetes 集群之外的密钥,旨在改善其密钥使用的安全性、管理能力和可审计性。

使用外部密钥存储服务中的密钥通常需要修改应用程序代码,这样才能支持密钥存储服务特定的 API 调用,从而允许在应用程序运行时检索密钥。这可能会增加应用程序代码库的复杂性,并且可能降低容器化应用程序在环境之间移动,甚至利用不同的密钥存储服务时的可移植性。但是,在 Amazon EKS 上运行应用程序时,您有一个更简洁的替代方案,可以大幅减少代码更改。具体而言,您可以利用 Amazon Secrets and Configuration Provider (ASCP) 和 Kubernetes Secrets Store CSI Driver。ASCP 充当 Amazon Secrets Manager 和 Kubernetes 环境之间的桥梁,将您的应用程序密钥作为挂载存储卷中的文件直接挂载到 Pod 中。此方法可简化管理并增强工作负载的可移植性,并且无需对应用程序级代码进行大量修改即可访问密钥。

本教程以本系列第 1 部分中的 Amazon EKS 集群为基础,详细介绍如何为 Kubernetes Secrets Store CSI Driver 设置 Amazon Secrets and Configuration Provider (ASCP)。上次教程的集群配置中包括 OpenID Connect (OIDC) 端点,供 ASCP 服务账户的 IAM 角色 (IRSA) 使用。如需本系列的第 1 部分,请参阅 构建为运行高流量微服务预配置的 Amazon EKS 集群。或者,若要使用本教程所需的组件设置现有集群,请遵循 EKS 官方文档中创建 IAM OpenID Connect (OIDC) 端点部分的说明。

在本教程中,您将学习如何为 Amazon EKS 集群上的 Kubernetes Secrets Store CSI Driver 设置 Amazon Secrets and Configuration Provider (ASCP),以及如何设置 Amazon Secrets Manager 来存储应用程序密钥。您将利用 ASCP 向在 EKS 上运行的应用程序公开密钥,从而提高工作负载的安全性和可移植性。

前提条件

  • 安装最新版本的 kubectl。若要检查版本,请运行: kubectl version --short
  • 已安装最新版本的 eksctl。若要检查版本,请运行: eksctl info
  • 安装最新版本的 Helm。若要检查版本,请运行: helm version
  • 已安装最新版本的 Amazon CLI (v2)。若要检查版本,请运行: aws --version
  • 已获取在现有 EKS 集群上配置的 IAM OIDC 提供商

概览

本教程是使用 Amazon EKS 管理高流量微服务平台系列的一部分,专门介绍如何使用 Kubernetes Secrets Store CSI Driver 的 Amazon Secrets and Configuration Provider (ASCP) 管理应用程序密钥。本教程不仅会展示如何使用 EKS 工作负载中的外部密钥,还会展示如何在 Amazon Secrets Manager 中创建密钥。本教程包括以下部分:

 
请注意, Amazon Secrets Manager 包括 30 天免费试用期,从您存储第一个密钥时开始计算。如果您已存储密钥并超过 30 天,则系统将根据您的使用情况进行收费。
 

步骤 1:设置环境变量

在使用 Helm 或其他命令行工具与 Amazon EKS 集群进行交互之前,请务必定义好封装集群详细信息的特定环境变量。这些变量将在后续命令中使用,确保它们指向正确的集群和资源。

  • 首先,请确认您是在正确的集群上下文中进行操作。这样可确保任何后续命令可以发送到预期的 Kubernetes 集群。您可以执行以下命令来验证当前上下文:
kubectl config current-context
  • 为 EKS 集群定义 CLUSTER_NAME 环境变量。替换集群 region 的示例值。如果您使用的是自己的现有 EKS 集群,请替换 name 的示例值。
export CLUSTER_NAME=$(aws eks describe-cluster --region us-east-2 --name managednodes-quickstart --query "cluster.name" --output text)
  • 为 EKS 集群定义 CLUSTER_REGION 环境变量。替换集群 region 的示例值。
export CLUSTER_REGION=$(aws eks describe-cluster --name ${CLUSTER_NAME} --region us-east-2 --query "cluster.arn" --output text | cut -d: -f4)

若要验证变量是否已设置正确,请运行以下命令。验证输出是否与特定输入相匹配。

echo $CLUSTER_REGION
echo $CLUSTER_NAME

步骤 2:在 Amazon Secrets Manager 中创建密钥

在 Amazon Secrets Manager 中创建密钥是安全管理应用程序敏感信息的首要步骤。您将使用 Amazon CLI 存储一个示例密钥,稍后 Kubernetes 集群会访问该密钥。这样就无需在应用程序中对敏感信息进行硬编码,从而增强了安全性。

SECRET_ARN=$(aws secretsmanager create-secret --name eksSecret --secret-string '{"username":"eksdemo", "password":"eksRocks!"}' --region "$CLUSTER_REGION" --query ARN) 

上述命令会将密钥的 ARN 存储在变量中,以供后续使用。若要验证密钥是否已创建成功,请运行以下命令输出变量:

echo $SECRET_ARN

预期的输出应如下所示:

"arn:aws:secretsmanager:us-east-2:0123456789:secret:eksSecret-JeuuzY"

步骤 3:创建用于在 Amazon Secrets Manager 中访问密钥的 IAM 策略

在这一步中,您将使用 Amazon CLI 创建一个 IAM 策略,该策略会授予特定权限来访问存储在 Amazon Secrets Manager 中的密钥。通过使用上一步中的 $SECRET_ARN 变量,您将指定 IAM 策略要应用于哪个密钥。此方法可确保 Kubernetes 集群中获得授权的实体只能访问指定的密钥。在下一步中,我们会将此 IAM 策略关联到 Kubernetes 服务账户。

POLICY_ARN=$(aws --region "$CLUSTER_REGION" --query Policy.Arn --output text iam create-policy --policy-name eksdemo-secretsmanager-policy --policy-document '{
 "Version": "2012-10-17",
 "Statement": [ {
 "Effect": "Allow",
 "Action": ["secretsmanager:GetSecretValue", "secretsmanager:DescribeSecret"],
 "Resource": ['$SECRET_ARN']
 } ]
}')

上述命令会将该策略的 ARN 存储在变量中,以供后续使用。若要验证策略是否已创建成功,请运行以下命令输出变量:

echo $POLICY_ARN

预期的输出应如下所示:

`arn:aws:iam::0123456789:policy/eksdemo-secretsmanager-policy`

步骤 4:创建 IAM 角色并与 Kubernetes 服务账户关联

在这一步中,您将使用服务账户的 IAM 角色 (IRSA) 将 Kubernetes 服务账户映射到 Amazon IAM 角色,从而为在 EKS 上运行的应用程序启用精细化的权限管理。您将使用 eksctl 创建一个 Amazon IAM 角色,并将其与 EKS 集群中的特定 Kubernetes 服务账户相关联。您还将使用 Secret Store CSI Driver 在应用程序 Pod 级别(而非 CSI 驱动程序 Pod 级别)应用 IAM 权限。这样可以确保只有利用 IRSA 关联的 Kubernetes 服务账户的特定应用程序 Pod 才有权访问存储在 Amazon Secrets Manager 中的密钥。我们会将在上一步中创建的 IAM 策略关联到新创建的 IAM 角色。请注意,在运行这些命令之前,您必须具有与集群相关联的 OpenID Connect (OIDC) 端点

eksctl create iamserviceaccount --name eksdemo-secretmanager-sa --region="$CLUSTER_REGION" --cluster "$CLUSTER_NAME" --attach-policy-arn "$POLICY_ARN" --approve --override-existing-serviceaccounts
完成后,您应当会看到以下输出结果:
[2023-08-07 15](tel:2023080715):45:32 [ℹ] created serviceaccount "default/eksdemo-secretmanager-sa"
确保在集群的“default”命名空间中正确设置了“eksdemo-secretmanager-sa”服务账户。
kubectl get sa eksdemo-secretmanager-sa -o yaml

预期的输出应如下所示:

apiVersion: v1
kind: ServiceAccount
metadata:
 annotations:
 eks.amazonaws.com/role-arn: arn:aws:iam::01234567890:role/eksctl-managednodes-quickstart-addon-iamserv-Role1-WRJJQSRMC4LK
 creationTimestamp: "2023-09-12T18:32:23Z"
 labels:
 app.kubernetes.io/managed-by: eksctl
 name: eksdemo-secretmanager-sa
 namespace: default
 resourceVersion: "4456"
 uid: 5c7989b7-2cdb-42f6-a9ee-db20a7e484d9

步骤 5:安装 ASCP 和 Secrets Store CSI Driver

在这一步中,您将使用 Helm 安装 Amazon Secrets and Configuration Provider (ASCP) 和 Secrets Store CSI Driver,二者会在 Amazon Secrets Manager 和 Kubernetes 集群之间建立安全的桥梁。这样,您的集群就能够访问存储在 Amazon Secrets Manager 中的密钥,并且无需对应用程序代码进行复杂的更改。ASCP 和 Secrets Store CSI Driver 将分别作为 DaemonSet 进行安装,确保驱动程序和提供程序的副本可以在集群中的每个节点上运行。

以下命令会将 Secrets Store CSI Driver Helm 图表存储库添加到本地 Helm 索引以允许安装:

helm repo add secrets-store-csi-driver https://kubernetes-sigs.github.io/secrets-store-csi-driver/charts

预期的输出应如下所示:

"secrets-store-csi-driver" has been added to your repositories

以下命令会将 Amazon Secrets and Configuration Provider (ASCP) Helm 图表存储库添加到本地 Helm 索引以允许安装:

helm repo add aws-secrets-manager https://aws.github.io/secrets-store-csi-driver-provider-aws

预期的输出应如下所示:

"aws-secrets-manager" has been added to your repositories

若要安装 Secrets Store CSI Driver,请运行以下 Helm 命令:

helm install -n kube-system csi-secrets-store secrets-store-csi-driver/secrets-store-csi-driver

预期的输出应如下所示:

NAME: csi-secrets-store
LAST DEPLOYED: Fri Sep 29 17:30:00 2023
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
The Secrets Store CSI Driver is getting deployed to your cluster.

To verify that Secrets Store CSI Driver has started, run:

kubectl --namespace=kube-system get pods -l "app=secrets-store-csi-driver"

Now you can follow these steps https://secrets-store-csi-driver.sigs.k8s.io/getting-started/usage.html
to create a SecretProviderClass resource, and a deployment using the SecretProviderClass.

如输出内容所述,若要验证 Secrets Store CSI Driver 是否已启动,请运行以下命令:

kubectl --namespace=kube-system get pods -l "app=secrets-store-csi-driver"

您应当会看到以下输出结果。确保所有 Pod 的 STATUS 均为 Running:

NAME READY STATUS RESTARTS AGE
csi-secrets-store-secrets-store-csi-driver-5l4sr 3/3 Running 0 2m31s
csi-secrets-store-secrets-store-csi-driver-jhbnf 3/3 Running 0 2m31s
csi-secrets-store-secrets-store-csi-driver-qsdm6 3/3 Running 0 2m31s

若要安装 Amazon Secrets and Configuration Provider(ASCP),请运行以下 Helm 命令:

helm install -n kube-system secrets-provider-aws aws-secrets-manager/secrets-store-csi-driver-provider-aws

预期的输出应如下所示:

NAME: secrets-provider-aws
LAST DEPLOYED: Tue Sep 12 18:33:45 2023
NAMESPACE: kube-system
STATUS: deployed
REVISION: 1
TEST SUITE: None

您还可以运行以下 Helm 命令来验证安装是否已完成:

`helm list -n kube-system` 

您会看到如下输出结果:

NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
csi-secrets-store kube-system [1 2023-08-07 15](tel:12023080715):39:24.856932796 +0000 UTC deployed secrets-store-csi-driver-1.3.4 1.3.4
secrets-provider-aws kube-system [1 2023-08-07 15](tel:12023080715):39:55.851595668 +0000 UTC deployed secrets-store-csi-driver-provider-aws-0.3.4

步骤 6:创建 ASCP SecretProviderClass 资源

在这一步中,您将定义 SecretProviderClass Kubernetes 对象,该对象为 Kubernetes 工作负载中的无缝密钥管理奠定了基础。这个资源充当 Amazon Secrets and Configuration Provider (ASCP) 的一组指令,指定哪些密钥可以从 Amazon Secrets Manager 中获取以及如何将这些密钥挂载到 Pod 中。请注意,SecretProviderClass 必须部署在与引用它的工作负载相同的命名空间中。若要了解详细信息,请参阅 SecretProviderClass 文档

创建名为 eksdemo-spc.yaml 的 Kubernetes 清单,并将以下内容粘贴到其中:

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
 name: eks-demo-aws-secrets
 namespace: default
spec:
 provider: aws
 parameters:
 objects: |
 - objectName: "eksSecret"
 objectType: "secretsmanager"

应用 YAML 清单。

`kubectl apply -f eksdemo-spc.yaml`

若要验证 SecretProviderClass 是否已创建成功,请运行以下命令:

kubectl describe secretproviderclass eks-demo-aws-secrets

预期的输出应如下所示:

Name: eks-demo-aws-secrets
Namespace: default
Labels: <none>
Annotations: <none>
API Version: secrets-store.csi.x-k8s.io/v1
Kind: SecretProviderClass
Metadata:
 Creation Timestamp: 2023-08-09T21:13:50Z
 Generation: 1
 Resource Version: 9853
 UID: d11bbadc-f3c8-4e70-8b1e-effe72b1518e
Spec:
 Parameters:
 Objects: - objectName: "eksSecret"
 objectType: "secretsmanager"

 Provider: aws
Events: <none>

步骤 7:部署示例工作负载以使用密钥

在这一步中,您将部署一个示例工作负载,以桥接您的应用程序和 Amazon Secrets Manager。通过将密钥作为文件挂载到工作负载的文件系统上,您将完成在 Kubernetes 环境中安全管理和访问密钥的端到端过程。在 Pod 模板中,您将指定 Secrets Store CSI 作为卷驱动程序,然后指定挂载密钥的路径,操作方式与挂载传统卷相同。在此示例中,我们将在 /mnt/secrets-store 位置挂载密钥。

创建名为 eksdemo-app.yaml 的 Kubernetes 清单,并将以下内容粘贴到其中:

apiVersion: v1
kind: Pod
metadata:
 name: busybox
 namespace: default
spec:
 serviceAccountName: eksdemo-secretmanager-sa
 volumes:
 - name: secrets-store-inline
 csi:
 driver: secrets-store.csi.k8s.io
 readOnly: true
 volumeAttributes:
 secretProviderClass: "eks-demo-aws-secrets"
 containers:
 - image: public.ecr.aws/docker/library/busybox:1.36
 command:
 - sleep
 - "3600"
 imagePullPolicy: IfNotPresent
 name: busybox
 volumeMounts:
 - name: secrets-store-inline
 mountPath: "/mnt/secrets-store"
 readOnly: true
 restartPolicy: Always

应用 YAML 清单。

`kubectl apply ``-``f eksdemo-app.yaml`

若要验证 Pod 是否已创建成功,请运行以下命令:

kubectl get pod busybox

您应当会看到以下输出结果。确保 Pod STATUS 为 Running:

NAME READY STATUS RESTARTS AGE
busybox 1/1 Running 0 11s

步骤 8:测试密钥

最后,我们将使用 kubectl 执行到我们刚刚部署的 Pod 中,看看我们是否可以读取挂载的密钥。

kubectl exec -it $(kubectl get pods | awk '/busybox/{print $1}' | head -1) -- cat /mnt/secrets-store/eksSecret; echo

此命令应输出我们之前创建的密钥:

`{"username":"eksdemo", "password":"eksRocks!"}`

清理资源

完成本教程后,为了更好地管理资源,您可能需要删除创建的特定资源。
# Delete the Sample Pod
kubectl delete pod busybox

# Delete the SecretProviderClass Resources
kubectl delete secretproviderclass eks-demo-aws-secrets

# Remove IAM Roles for Service Accounts (IRSA
`eksctl ``delete`` iamserviceaccount` --cluster="$CLUSTER_NAME" --name=eksdemo-secretmanager-sa --region="$CLUSTER_REGION"

# Delete AWS Secrets Manager Secret without recovery window
aws secretsmanager delete-secret --secret-id eksSecret --region "$CLUSTER_REGION" --force-delete-without-recovery

# Uninstall the AWS Secrets and Configuration Provider
helm uninstall -n kube-system csi-secrets-store
helm uninstall -n kube-system secrets-provider-aws

# Delete IAM Policy
aws iam delete-policy --policy-arn $POLICY_ARN

结论

完成本教程后,您就将 Amazon Secrets Manager 与 Amazon EKS 集群进行了集成。通过这样的集成,您无需进行复杂的代码修改即可集中管理应用程序密钥,同时可以在 EKS 上运行的工作负载中轻松使用这些密钥。密钥的安全性和治理能力以及应用程序的可移植性都得以改善,并且开销很低。对于工作负载可能需要的各种类型的密钥,例如数据库凭据、API 密钥等,您可以轻松沿用此示例方法。