Vault EKS and Agent Integration
验证:未记录
- 适用版本
- 未记录
- 验证范围
- 尚未登记验证记录。
本文缩写(英文全称与中文含义)
| 缩写 | 英文全称/名称 | 中文含义 |
|---|---|---|
| API | Application Programming Interface | 应用程序编程接口 |
| AWS | Amazon Web Services | 亚马逊云服务 |
| CA | Certificate Authority | 证书颁发机构 |
| CLI | Command-Line Interface | 命令行接口 |
| CSI | Container Storage Interface | 容器存储接口 |
| EKS | Elastic Kubernetes Service | AWS 托管 Kubernetes 服务 |
| ESO | External Secrets Operator | 将外部秘密系统中的值同步到 Kubernetes 的控制器 |
| JWKS | JSON Web Key Set | JSON Web 密钥集,常用于验证令牌签名 |
| JWT | JSON Web Token | 一种携带声明的令牌格式 |
| OIDC | OpenID Connect | 基于 OAuth 2.0 的身份认证协议 |
| RBAC | Role-Based Access Control | 基于角色的访问控制 |
| SAN | Subject Alternative Name | 证书主题备用名称,用于声明域名或 IP |
| SDK | Software Development Kit | 软件开发工具包 |
| TTL | Time To Live | 存活时间;具体指缓存有效期或记录过期时间 |
1. 方案#
Vault 位于集群外,通过 EKS ServiceAccount 的短期 JWT 验证身份,Vault Agent 渲染数据库凭据到 Pod 内存卷。应用不取得 Vault token,也不把数据库密码同步成 Kubernetes Secret。
本例使用 JWT auth 校验 EKS issuer/JWKS,不是使用 TokenReview 的 Kubernetes auth。两种方式不要混配。JWT auth
前提:已完成 动态数据库,存在 orders-app policy、database/creds/orders-read;EKS 可访问 Vault,Vault 可访问 EKS OIDC discovery/JWKS,应用网络可访问数据库。
2. 绑定 EKS 身份#
先用 AWS CLI 确认实际集群:
export VAULT_EKS_NAME=production
export VAULT_EKS_REGION=ap-southeast-1
VAULT_EKS_ISSUER=$(aws eks describe-cluster --name "$VAULT_EKS_NAME" --region "$VAULT_EKS_REGION" --query 'cluster.identity.oidc.issuer' --output text)
vault auth enable -path=eks-jwt jwt
vault write auth/eks-jwt/config oidc_discovery_url="$VAULT_EKS_ISSUER" bound_issuer="$VAULT_EKS_ISSUER"保存 orders-jwt-role.json:
{
"role_type": "jwt",
"user_claim": "sub",
"bound_subject": "system:serviceaccount:orders:orders-api",
"bound_audiences": ["vault"],
"token_policies": ["orders-app"],
"token_ttl": "5m",
"token_max_ttl": "10m"
}vault write auth/eks-jwt/role/orders-api @orders-jwt-role.jsonissuer + subject + audience 一起约束身份;测试和生产集群分别建 auth mount。JWT auth 不实时检查 Pod 是否已删除,被盗 JWT 在过期前仍可能登录;短 token TTL 与紧急撤销需配套。若要求实时 TokenReview,改用 Kubernetes auth,并设计 reviewer token 的安全获取、权限与续期。
3. 准备 namespace、CA 和 Agent 配置#
kubectl create namespace orders
kubectl -n orders create serviceaccount orders-api
kubectl -n orders create configmap vault-ca --from-file=ca.crt=/secure/platform/vault-ca.crtCA 证书不是私钥。保存 agent.hcl,替换 vault.internal 为证书 SAN 覆盖的实际地址:
pid_file = "/tmp/vault-agent.pid"
vault {
address = "https://vault.internal:8200"
ca_cert = "/etc/vault-ca/ca.crt"
}
auto_auth {
method "jwt" {
mount_path = "auth/eks-jwt"
config = {
path = "/var/run/vault-jwt/token"
role = "orders-api"
remove_jwt_after_reading = false
}
}
}
template {
destination = "/vault/secrets/database.json"
perms = "0640"
error_on_missing_key = true
contents = <<EOT
{{- with secret "database/creds/orders-read" -}}
{"username": {{ .Data.username | toJSON }}, "password": {{ .Data.password | toJSON }}}
{{- end -}}
EOT
}kubectl -n orders create configmap orders-vault-agent --from-file=agent.hcl投射 JWT 由 kubelet 轮换,Agent 不删除它。Agent 负责重新认证、lease 生命周期和模板更新,但不会自动修改应用进程的环境变量。JWT auto-auth、Agent templates
4. 部署验证 Pod#
保存为 orders-vault-demo.yaml。consumer 仅验证受限文件可读,不输出凭据,也不是实际订单应用。
apiVersion: apps/v1
kind: Deployment
metadata:
name: orders-vault-demo
namespace: orders
spec:
replicas: 1
selector:
matchLabels:
app: orders-vault-demo
template:
metadata:
labels:
app: orders-vault-demo
spec:
serviceAccountName: orders-api
automountServiceAccountToken: false
securityContext:
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: vault-agent
image: hashicorp/vault:2.1.1
command: ["vault", "agent", "-config=/etc/vault-agent/agent.hcl"]
securityContext:
runAsNonRoot: true
runAsUser: 100
runAsGroup: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
resources:
requests: {cpu: 50m, memory: 64Mi}
limits: {cpu: 250m, memory: 256Mi}
volumeMounts:
- {name: config, mountPath: /etc/vault-agent, readOnly: true}
- {name: ca, mountPath: /etc/vault-ca, readOnly: true}
- {name: jwt, mountPath: /var/run/vault-jwt, readOnly: true}
- {name: secrets, mountPath: /vault/secrets}
- name: consumer
image: busybox:1.37.0
command: ["sh", "-c", "while true; do sleep 60; done"]
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
resources:
requests: {cpu: 10m, memory: 16Mi}
limits: {cpu: 100m, memory: 32Mi}
readinessProbe:
exec:
command: ["sh", "-c", "test -s /vault/secrets/database.json"]
periodSeconds: 5
volumeMounts:
- {name: secrets, mountPath: /vault/secrets, readOnly: true}
volumes:
- name: config
configMap:
name: orders-vault-agent
- name: ca
configMap:
name: vault-ca
- name: jwt
projected:
sources:
- serviceAccountToken:
path: token
audience: vault
expirationSeconds: 600
- name: secrets
emptyDir:
medium: Memory
sizeLimit: 8Mikubectl apply -f orders-vault-demo.yaml
kubectl -n orders rollout status deployment/orders-vault-demo
kubectl -n orders logs deployment/orders-vault-demo -c vault-agent --tail=50
kubectl -n orders exec deployment/orders-vault-demo -c consumer -- sh -c 'test -r /vault/secrets/database.json && echo credentials-file-ready'验收成功标志是文件生成且不暴露值;应用实际访问数据库仍需单独验证。文件存在不是凭据仍有效的证明,生产 readiness 应验证当前凭据和必要数据库访问。
5. 企业应用接入#
把 consumer 替换为订单服务镜像,使用固定 digest;实现“文件更新 → 解析新凭据 → 新连接池健康检查 → 排空旧连接池”。Agent 原子替换文件,文件监听要处理 rename/inode 变化;仅启动时读一次文件不够。
| 其他方式 | 适用场景 | 取舍 |
|---|---|---|
| Vault Agent Injector | 团队希望通过 Pod annotation 统一注入 | 需要管理 webhook、模板与失败策略 |
| Vault Secrets Operator / ESO | 应用只能读取 Kubernetes Secret | secret 会进入 Kubernetes API/etcd,配置加密和 RBAC |
| CSI provider | 文件挂载集成 | 核对凭据续期、刷新和应用重载能力 |
| 应用 SDK | 应用需要精确 lease 控制 | 自己处理认证、重试、续期与撤销 |
限制只有 Agent 能挂载身份 JWT,业务容器只读凭据文件;Pod 创建权限本身能影响 workload 身份,RBAC、准入策略和 NetworkPolicy 同样重要。
6. 故障与清理#
- 换成其他 namespace/ServiceAccount,预期 Vault 登录被拒绝。
- 阻断实验 Pod 到 Vault 的网络,观察现有凭据有效期和续期告警;应用不得无期限使用旧密码。
- 撤销测试 lease,验证连接池能恢复或明确报错,不在日志打印密码。
- 查看 Agent 续期不等于文件每次都会变化;同一凭据续期时 username/password 可能不变。
清理本次 Deployment、ConfigMap、ServiceAccount 和测试 namespace;只删除本次专用资源。Pod 删除不保证已有 Vault token/数据库 lease 立即失效,按测试记录主动撤销或验证到期回收。生产 auth mount 不因一次实验结束而整体 disable。