在Amazon EKS中使用AWS Secrets Manager代理
AWS Secrets Manager是一项可用于管理、检索和轮换数据库凭据、应用程序凭据、API密钥和其他密钥在整个生命周期中的服务。您还可以使用Secrets Manager将应用程序源代码中的硬编码凭据替换为运行时调用,以便在需要时动态检索凭据。
在Amazon Elastic Kubernetes Service(Amazon EKS)环境中管理密钥会带来三个主要挑战:对特定语言AWS SDK的依赖、直接API调用带来的网络依赖以及跨多个Pod的复杂密钥轮换。
AWS Secrets Manager代理通过提供在计算环境中本地运行的语言无关HTTP接口来解决这些挑战。在本文中,我们将向您展示如何在Amazon EKS中将Secrets Manager代理部署为边车容器,以通过HTTP调用检索密钥。
新方法:Secrets Manager代理
Secrets Manager代理是一个客户端代理,您可以使用它在AWS计算环境中标准化从Secrets Manager使用密钥的方式。该代理在计算环境中拉取和缓存密钥,并允许您的应用程序通过本地HTTP端点(localhost:2773)直接从内存缓存中使用密钥。
您可以从本地代理获取密钥值,而不是向Secrets Manager进行网络调用,从而提高应用程序可用性,同时减少API调用。由于Secrets Manager代理是语言无关的,您可以在不同的编程语言中使用它,而无需依赖AWS SDK。
后量子密码学保护
Secrets Manager代理实现了ML-KEM(基于机器学习的密钥封装机制)密钥交换,为密钥检索操作提供了额外的密码学保护。此功能默认启用,无需额外配置。
身份验证和访问控制
此解决方案使用Amazon EKS Pod Identity进行到AWS服务的安全身份验证。Pod Identity提供了一种简化方法,将AWS Identity and Access Management(IAM)角色与Kubernetes服务账户关联,避免了OpenID Connect(OIDC)提供程序配置的需要。IAM主体需要GetSecretValue和DescribeSecret权限才能通过代理检索密钥。
Secrets Manager代理提供针对服务器端请求伪造(SSRF)的保护。安装代理时,它会生成一个随机SSRF令牌并将其存储在/var/run/awssmatoken中。代理会主动阻止未在X-Aws-Parameters-Secrets-Token标头中包含此令牌的请求。
解决方案概述
在此解决方案中,您将Secrets Manager代理作为边车容器部署在Amazon EKS Pod中,与NGINX应用程序一起运行。边车模式有助于确保每个Pod都有自己的代理实例,提供隔离和细粒度的安全边界。
本文演示了Secrets Manager代理边车方法,补充了[宣布ASCP与Pod Identity集成]中涵盖的AWS Secrets and Configuration Provider(ASCP)指南。
Amazon EKS支持多种使用Secrets Manager密钥的模式。当您希望将密钥作为文件挂载并偏好Kubernetes原生密钥管理时,用于Kubernetes Secrets Store CSI驱动程序的ASCP效果很好。当您需要基于HTTP的密钥访问、希望在密钥轮换期间避免Pod重启或需要通过refreshNow参数进行细粒度刷新控制时,请使用Secrets Manager代理。
在Secrets Manager代理和CSI驱动程序之间选择:
| 方法 |
访问方法 |
最适合 |
| Secrets Manager代理 |
到localhost:2773的HTTP API调用 |
需要运行时密钥访问、动态刷新和语言无关HTTP接口的应用程序 |
| ASCP和CSI驱动程序 |
作为文件挂载的密钥 |
Kubernetes原生密钥管理和基于文件的密钥使用 |
每种密钥管理方法对于不同的使用场景都有特定的优势。Secrets Manager代理适用于需要基于HTTP的访问和动态密钥更新的应用程序,而带有CSI驱动程序的ASCP适用于需要基于文件的密钥挂载的应用程序。在选择这些方法时,请考虑应用程序的具体要求、操作模式和安全性需求。
要部署此解决方案,您需要构建代理二进制文件,将其容器化,并使用Kubernetes清单和Amazon EKS Pod Identity将其部署到Amazon EKS,以实现对Secrets Manager的安全访问。
图1:解决方案工作流程
解决方案的工作流程如图1所示,包括以下步骤:
- 应用程序容器发送GET /secretsmanager/get(localhost:2773)以检索密钥
- Secrets Manager代理检查本地缓存以确定密钥是否已存储在内存中
- 如果未缓存,使用Pod Identity进行身份验证以建立到AWS Secrets Manager的安全访问
- 承担IAM角色以从AWS Secrets Manager检索密钥
- 将密钥返回到边车容器进行缓存
- 将密钥返回到应用程序容器以满足原始请求
先决条件
要构建本文中的解决方案,您必须满足以下条件:
- AWS账户
- 位于us-west-2 AWS区域的Amazon EKS集群(1.32)
- 请注意,AWS Secrets Manager代理支持自其初始发布以来可用的Amazon EKS和Kubernetes版本,为跨集群版本的密钥管理提供通用兼容性。
- 在集群上安装的Amazon EKS Pod Identity代理
- 基于Linux的虚拟机或Amazon Elastic Compute Cloud(Amazon EC2)实例以构建代理
- AWS命令行界面(AWS CLI)版本2
- 已安装和配置的kubectl
- 已安装的Docker
安装Secrets Manager代理
在本节中,您将安装Secrets Manager代理。安装代理后,您将创建Pod Identity关联、Secrets Manager二进制映像、将二进制映像推送到Amazon Elastic Container Registry(Amazon ECR),并在Secrets Manager中创建密钥。
验证Pod Identity代理安装:
1
|
kubectl get daemonset eks-pod-identity-agent -n kube-system
|
使用以下命令创建Pod Identity关联:
1
2
3
4
5
|
aws eks create-pod-identity-association \
--cluster-name <cluster> \
--namespace default \
--service-account secrets-manager-sa \
--role-arn arn:aws:iam::<ACCOUNT_ID>:role/eks-secrets-manager-role
|
创建一个名为install的文件并添加以下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
|
#!/bin/bash -e
PATH=/bin:/usr/bin:/sbin:/usr/sbin # Use a safe path
AGENTTARGETDIR=/opt/aws/secretsmanageragent
AGENTSOURCEDIR=/etc/aws_secretsmanager_agent/configuration
AGENTBIN=aws_secretsmanager_agent
TOKENGROUP=awssmatokenreader
AGENTUSER=awssmauser
TOKENSCRIPT=/etc/aws_secretsmanager_agent/configuration/awssmaseedtoken
AGENTSCRIPT=awssmastartup
if [ `id -u` -ne 0 ]; then
echo "This script must be run as root" >&2
exit 1
fi
if [ ! -r ${TOKENSCRIPT} ]; then
echo "Can not read ${TOKENSCRIPT}" >&2
exit 1
fi
if [ ! -r ${AGENTSOURCEDIR}/${AGENTBIN} ]; then
echo "Can not read ${AGENTBIN}" >&2
exit 1
fi
groupadd -f ${TOKENGROUP}
useradd -r -m -g ${TOKENGROUP} -d ${AGENTTARGETDIR} ${AGENTUSER} || true
chmod 755 ${AGENTTARGETDIR}
install -D -T -m 755
${AGENTSOURCEDIR}/${AGENTBIN} ${AGENTTARGETDIR}/bin/${AGENTBIN}
chown -R ${AGENTUSER} ${AGENTTARGETDIR}
exit 0
|
在基于Linux的实例上使用以下命令构建代理二进制文件:
1
2
3
4
5
6
7
8
9
10
|
#!/bin/bash -e
# Here we are building the Secrets Manager Agent Binary for Linux x86_64 architecture
sudo yum -y groupinstall "Development Tools"
sudo yum install -y git
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y
source $HOME/.cargo/env
git clone https://github.com/aws/aws-secretsmanager-agent
cd aws-secretsmanager-agent
mv ../install aws_secretsmanager_agent/configuration
cargo build --release --target x86_64-unknown-linux-gnu
|
创建一个名为startup.sh的文件作为入口点并添加以下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
#!/bin/bash
set -e
echo "Starting AWS Secrets Manager Agent initialization..."
# Step 1: Run the install script (equivalent to install-agent init container)
echo "Running agent installation..."
/etc/aws_secretsmanager_agent/configuration/install
# Step 2: Initialize the token (equivalent to token-init init container)
echo "Starting token initialization..."
chmod +x
/etc/aws_secretsmanager_agent/configuration/awssmaseedtoken /etc/aws_secretsmanager_agent/configuration/awssmaseedtoken start
# Step 3: Start the main secrets manager agent
echo "Starting secrets manager agent..."
exec
/etc/aws_secretsmanager_agent/configuration/aws_secretsmanager_agent
|
创建一个名为Docker-eks的文件并添加以下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
FROM public.ecr.aws/amazonlinux/amazonlinux:2023
# Install required dependencies
RUN yum install -y ca-certificates bash shadow-utils && yum clean all
RUN mkdir -p /opt/aws/secretsmanageragent /var/run
# Copy in the agent binary and configuration scripts
COPY aws_secretsmanager_agent/configuration/
/etc/aws_secretsmanager_agent/configuration
COPY target/x86_64-unknown-linux-
gnu/release/aws_secretsmanager_agent
/etc/aws_secretsmanager_agent/configuration
# Make binaries and scripts executable
RUN chmod -R +x /etc/aws_secretsmanager_agent/configuration
# Copy and setup startup script
COPY startup.sh /startup.sh
RUN chmod +x /startup.sh
WORKDIR /
# Use the startup script as entrypoint
ENTRYPOINT ["/startup.sh"]
|
使用以下命令构建和发布映像:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
#!/bin/bash -e
#Create the ECR Repo ( us-west-2 region)
aws ecr create-repository --repository-name secrets-manager-agent --image-tag-mutability MUTABLE
#Build the image
docker build -f Dockerfile-eks -t secrets-manager-agent:eks .
#Tag the image
docker tag secrets-manager-agent:eks <ACCOUNT_ID>.dkr.ecr.us-west-2.amazonaws.com/secrets-manager-agent:eks
# Login into ECR
aws ecr get-login-password --region us-west-2 | docker login --username AWS --password-stdin <ACCOUNT_ID>.dkr.ecr.us-west-2.amazonaws.com
#Push the image
docker push <ACCOUNT_ID>.dkr.ecr.us-west-2.amazonaws.com/secrets-manager-agent:eks
|
成功后,您的私有Amazon ECR仓库将显示已发布的映像。
创建密钥
映像成功发布后,您就可以创建密钥了。
使用AWS CLI在终端中输入以下命令,在Secrets Manager中创建一个密钥。
1
2
|
aws secretsmanager create-secret --name MySecret --description "My Secret" \
--secret-string "{\"user\": \"my_user\", \"password\": \"my-password\"}"
|
您应该看到类似以下的输出:
1
2
3
4
5
|
{
"ARN": "arn:aws:secretsmanager:us-west-
2:XXXXXXXXXXXX:secret:MySecret-LrBlpm",
"Name": "MySecret", "VersionId": "b5e73e9b-6ec5-4144-a176-3648304b2d60"
}
|
记录密钥Amazon Resource Name(ARN)以便在下一节中使用。
创建IAM角色
Amazon EKS应用程序需要一个IAM角色,该角色授予检索您刚创建的密钥的权限。
要创建IAM角色:
- 使用编辑器创建一个名为eks_iam_policy.json的文件,内容如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "pods.eks.amazonaws.com"
},
"Action": [
"sts:AssumeRole",
"sts:TagSession"
]
}
]
}
|
- 在终端中输入以下命令以创建IAM角色:
1
|
aws iam create-role --role-name eks-secrets-manager-role --assume-role-policy-document file://eks_iam_policy.json
|
- 创建一个名为iam_permission.json的文件,内容如下,将<SECRET_ARN>替换为您之前记录的密钥ARN:
1
2
3
4
5
6
7
8
9
10
11
12
13
|
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"secretsmanager:GetSecretValue",
"secretsmanager:DescribeSecret"
],
"Resource": "<SECRET_ARN>"
}
]
}
|
- 输入以下命令创建策略:
1
|
aws iam create-policy --policy-name get-secret-policy --policy-document file://iam_permission.json
|
- 记录策略ARN以便在下一步中使用。
- 输入以下命令将此策略添加到IAM角色,将<POLICY_ARN>替换为您刚才记录的值:
1
|
aws iam attach-role-policy --role-name eks-secrets-manager-role --policy-arn <POLICY_ARN>
|
配置应用程序并将Secrets Manager代理部署到Amazon EKS
以下是用于将Secrets Manager代理作为边车容器与应用程序容器一起安装的示例Kubernetes部署YAML。将<ACCOUNT_ID>替换为您的AWS账户号,并运行代码以将NGINX应用程序部署到Amazon EKS集群。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
# nginx-with-secrets-agent.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-with-secrets-simplified
labels:
app: nginx-with-secrets-simplified
spec:
replicas: 1
selector:
matchLabels:
app: nginx-with-secrets-simplified
template:
metadata:
labels:
app: nginx-with-secrets-simplified
spec:
serviceAccountName: secrets-manager-sa
containers:
- name: nginx
image: nginx:latest
ports:
- containerPort: 80
volumeMounts:
- name: token-volume
mountPath: /var/run
- name: secrets-manager-agent
image: <ACCOUNT_ID>.dkr.ecr.us-west-
2.amazonaws.com/secrets-manager-agent:eks
env:
- name: AWS_TOKEN
value: "file:///var/run/awssmatoken"
volumeMounts:
- name: token-volume
mountPath: /var/run
volumes:
- name: token-volume
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: nginx-service
spec:
selector:
app: nginx-with-secrets-simplified
ports:
- port: 80
targetPort: 80
type: ClusterIP
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: secrets-manager-sa
|
1
|
kubectl apply -f nginx-with-secrets-agent.yaml
|
如果成功,Pod将运行两个活动容器。
检索密钥
现在您可以运行以下命令来使用本地Web服务器检索代理。kubectl exec进入应用程序容器,通过REST API调用从Web服务器检索密钥。
1
2
|
kubectl exec -it nginx-with-secrets-c7945f8dc-7hrzr -c nginx -- sh
curl -v -H "X-Aws-Parameters-Secrets-Token: $(cat/var/run/awssmatoken)" 'http://localhost:2773/secretsmanager/get?secretId=<SecretID>'
|
如果IAM权限配置正确,您应该看到Success 200消息和密钥值。
清理
运行以下清理脚本以删除为解决方案创建的资源:
1
2
|
chmod +x cleanup.sh
./cleanup.sh
|
完成后,您可以检查repo中名为cleanup.sh的文件以验证清理是否成功:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
#!/bin/bash
set -e
echo "Cleaning up EKS resources..."
kubectl delete deployment nginx-with-secrets-simplified --ignore-not-found=true
kubectl delete service nginx-service --ignore-not-found=true
kubectl delete serviceaccount secrets-manager-sa --ignore-not-found=true
echo "Cleaning up Pod Identity association..."
# Replace with your actual cluster name
read -p "Enter your CLUSTER_NAME: " CLUSTER_NAME
if [ -n "$CLUSTER_NAME" ]; then
ASSOCIATION_ID=$(aws eks list-pod-identity-associations \
--cluster-name $CLUSTER_NAME \
--query 'associations[?serviceAccount==`secrets-manager-sa`].associationId' \
--output text)
if [ -n "$ASSOCIATION_ID" ] && [ "$ASSOCIATION_ID" !=
"None" ]; then
aws eks delete-pod-identity-association \
--cluster-name $CLUSTER_NAME \
--association-id $ASSOCIATION_ID || echo "Pod Identity
association already deleted"
echo "Pod Identity association deleted"
else
echo "No Pod Identity association found"
fi
fi
echo "Cleaning up IAM resources..."
# Replace with your actual policy ARN from the create-policy
output
read -p "Enter your POLICY_ARN: " POLICY_ARN
if [ -n "$POLICY_ARN" ]; then
aws iam detach-role-policy \
--role-name eks-secrets-manager-role \
--policy-arn $POLICY_ARN || echo "Policy already detached"
aws iam delete-policy --policy-arn $POLICY_ARN || echo
"Policy already deleted"
fi
aws iam delete-role --role-name eks-secrets-manager-role || echo
"Role already deleted"
echo "Cleaning up secret..."
aws secretsmanager delete-secret --secret-id MySecret || echo
"Secret already deleted"
echo "Cleaning up container image..."
aws ecr delete-repository \
--repository-name secrets-manager-agent \
--force || echo "Repository already deleted"
echo "Cleanup complete!"
|
结论
在本文中,我们向您展示了如何在Amazon EKS中将AWS Secrets Manager代理部署为边车容器。这种方法提供了一种语言无关的方式,通过HTTP调用检索密钥,减少了SDK依赖,同时通过SSRF保护和基于IAM的访问控制保持安全性。
Secrets Manager代理可以作为边车容器或DaemonSet部署。使用边车部署用于隔离密钥和细粒度安全边界,使用DaemonSet部署用于跨多个应用程序的共享密钥和优化的资源利用。
这种方法补充了现有的密钥管理模式,并为团队提供了基于HTTP的密钥访问、即时刷新控制以及跨AWS计算环境的一致接口。
要了解更多信息,请访问AWS Secrets Manager文档。