通过 CredentialProvider 将存放在阿里云 KMS 凭据管家中的 API Key 统一纳管,由 ack-agent-identity 组件经 OIDC 从 KMS 专属实例代取,按 Agent 身份为 AI Agent 工作负载按需下发凭据,应用侧与业务 Pod 均无需内置明文密钥,也无需直连 KMS。
功能介绍
在 AI Agent 场景中,Agent 常需调用第三方服务(如 OpenAI、通义千问等 LLM 服务)的 API Key。若将真实 API Key 直接写入应用代码、镜像或环境变量,存在凭据泄露与难以轮转的风险。
CredentialProvider 是 ack-agent-identity 提供的凭据来源自定义资源(CRD)。当类型为 APIKey 且来源为 KMS 时,它从阿里云 KMS 凭据管家读取指定凭据的值作为 API Key,并具备以下能力:
真实 API Key 托管在 KMS 凭据管家中,由 KMS 统一管理、轮转与审计。应用与业务 Pod 都不接触明文密钥,也不直连 KMS,而是由 ack-agent-identity 组件经 OIDC 代取。
通过 AgentRole / AgentRoleBinding 授权机制,精细控制每个 Agent 身份可获取哪些 CredentialProvider 的凭据。
secretName支持模板变量,可按 Agent 身份等上下文动态引用不同的 KMS 凭据,实现“一份配置、按身份取不同凭据”。
与 Kubernetes 来源相比,KMS 来源把密钥托管从集群内 Secret 上移到了云端 KMS 凭据管家,适合需要集中托管、轮转与审计密钥的场景。
CredentialProvider 除 APIKey 外还支持 RAM 等类型。本文仅介绍 type: APIKey + KMS 专属实例 OIDC(ACK)来源,其余类型与来源请参见对应文档。
涉及的资源对象
配置一次可用的 KMS 凭据下发,通常涉及以下 CR,下文操作步骤将分别创建:
资源对象 | 说明 |
| 承载 KMS 实例的接入信息(实例 Endpoint、认证 AAP、实例 CA 证书),与”取哪个凭据”解耦。 |
| 定义 Agent 身份标识,是授权与凭据下发的主体。 |
| 定义凭据来源。本文中 |
| 定义权限规则,声明允许获取哪个 CredentialProvider 的凭据。 |
| 将 AgentRole 绑定到指定 AgentIdentity,完成授权。 |
适用范围
集群版本 >= 1.28。
在集群组件管理页面,确认
ack-agent-identity组件版本 >= 0.5.0。集群内已安装 coredns 组件。
已购买并启用 KMS 专属实例,且实例镜像版本 >= dkms-4.0.0。低于该版本请先升级,具体操作请参见升级KMS实例的镜像版本。
已在集群集群信息页的基本信息页签中开启 RRSA OIDC(OIDC(ACK) 认证依赖此特性)。
集群与 KMS 专属实例在同一地域但所在 VPC 不一致时,需在 KMS 侧为集群 VPC 配置 VPC 共享(绑定),否则集群内无法通过实例 Endpoint 访问 KMS。具体操作请参见同地域多VPC访问KMS实例。
集群与 KMS 专属实例不在同一地域时,需配置跨地域访问 KMS。具体操作请参见应用跨地域访问KMS实例。
准备 KMS 专属实例接入
在集群内创建资源前,需先在 KMS 侧完成专属实例的 OIDC(ACK) 接入配置,得到组件访问 KMS 所需的应用接入点、实例 Endpoint 和实例 CA 证书。
应用接入点(Application Access Point,简称 AAP)是 KMS 用于云原生接入的访问身份:它绑定一种认证方式(本文为 OIDC(ACK),即信任指定集群 ServiceAccount 的 JWT)与一组 RBAC 权限,组件持集群 ServiceAccount 的 Token 向 KMS 换取临时凭据后,即以该 AAP 的身份和权限访问实例中的凭据。
登录密钥管理服务控制台,左侧导航栏选择应用接入 > 云原生接入,然后切换到容器 > ACK。
在集群列表中找到目标集群,并单击其右侧的配置ACK接入。认证方式选择 OIDC(ACK),按下表配置并生成应用接入点:
OIDC(ACK) 接入的完整控制台操作(含开启 RRSA OIDC、创建 AAP 等)请参见ACK 快速接入。
配置项
取值
Namespace
固定填
ack-agent-identity。ServiceAccount
固定填
credential-provider。作用域
选择指定的 KMS 实例(即本专属实例)。
RBAC权限
选择 CryptoServiceSecretUser(允许读取实例中的凭据)。
允许访问的资源
勾选应用需要访问的凭据和密钥(用于凭据加解密)。
Namespace 与 ServiceAccount 必须填上述固定值,因为向 KMS 证明身份的是 ack-agent-identity 组件(其 ServiceAccount 为
ack-agent-identity命名空间下的credential-provider),而不是业务 Pod 的 ServiceAccount。业务 Pod 全程不直连 KMS。配置完成后,记录以下信息,供下文创建 ExternalSecretService 使用:
应用接入点(AAP):可用其短名(name,如
my-aap)或完整 ARN(如acs:kms:cn-hangzhou:123456789012:applicationaccesspoint/my-aap)。实例 Endpoint:专属实例网关域名,形如
kst-hzz00example.cryptoservice.kms.aliyuncs.com。实例 CA 证书:专属实例网关的 CA 证书(PEM,公开信息),用于校验实例网关的 TLS 证书。
在 KMS 凭据管家中创建或确认存放 API Key 的凭据,记录其凭据名称(secretName)。
配置 KMS 凭据下发
以下集群内资源(AgentIdentity、ExternalSecretService、CredentialProvider、AgentRole、AgentRoleBinding)需创建在同一命名空间下。
将以下内容保存为
kms-external-secret-service.yaml并执行kubectl apply -f kms-external-secret-service.yaml命令,创建 ExternalSecretService,承载 KMS 专属实例的接入信息。将endpoint、aap.name、caBundle替换为上一步记录的实际值。apiVersion: agentidentity.alibabacloud.com/v1alpha1 kind: ExternalSecretService metadata: name: kms-dedicated-instance namespace: <YOUR-NAMESPACE> spec: provider: KMS kms: endpoint: kst-hzz00example.cryptoservice.kms.aliyuncs.com # 专属实例网关 Endpoint auth: type: AAP # AAP OIDC 认证 aap: name: my-aap # AAP 短名 # 专属实例网关的 CA 证书,必填。接受 base64 编码的 PEM(如 `base64 -w0 ca.pem`)或裸 PEM caBundle: REPLACE_WITH_BASE64_ENCODED_PEM_OF_YOUR_DEDICATED_KMS_INSTANCE_CAExternalSecretService 在创建时会同步校验
caBundle是否为合法 PEM,并对endpoint进行网络探活。若caBundle非法或实例 Endpoint 不可达,apply 会被直接拒绝。请确认集群到 KMS 专属实例的网络连通(参见适用范围中的 VPC 共享说明)。将以下内容保存为
agent-identity.yaml并执行kubectl apply -f agent-identity.yaml命令,创建 AgentIdentity 定义 Agent 身份标识。apiVersion: agentidentity.alibabacloud.com/v1alpha1 kind: AgentIdentity metadata: name: my-agent # Agent 身份名称,后续授权中引用 namespace: <YOUR-NAMESPACE> spec: description: "示例 AI Agent 身份"将以下内容保存为
credential-provider-kms.yaml并执行kubectl apply -f credential-provider-kms.yaml命令,创建 CredentialProvider,引用上述 ExternalSecretService 并指定要读取的 KMS 凭据。apiVersion: agentidentity.alibabacloud.com/v1alpha1 kind: CredentialProvider metadata: name: llm-api-key namespace: <YOUR-NAMESPACE> spec: type: APIKey apiKey: source: provider: KMS kms: secretName: my-kms-secret-name # KMS 凭据管家中的凭据名称 serviceRef: name: kms-dedicated-instance # 上一步创建的 ExternalSecretService 名称 # versionStage: ACSCurrent # 可选,凭据版本阶段,默认 ACSCurrent # versionId: "" # 可选,指定凭据版本 ID # maxCacheValidity: 15m # 可选,凭据值缓存上限,默认 15msecretName支持使用模板变量按上下文动态引用不同的 KMS 凭据,详见secretName 模板变量。将以下内容保存为
agent-role-kms.yaml并执行kubectl apply -f agent-role-kms.yaml命令,创建 AgentRole 和 AgentRoleBinding,授权 Agent 身份获取该 CredentialProvider 的凭据。apiVersion: agentidentity.alibabacloud.com/v1alpha1 kind: AgentRole metadata: name: get-llm-key namespace: <YOUR-NAMESPACE> spec: rules: - effect: Allow action: "GetResourceCredential" resource: "CredentialProvider/llm-api-key" # 上一步创建的 CredentialProvider 名称 --- apiVersion: agentidentity.alibabacloud.com/v1alpha1 kind: AgentRoleBinding metadata: name: my-agent-get-llm-key namespace: <YOUR-NAMESPACE> spec: agentRoleRef: apiGroup: agentidentity.alibabacloud.com kind: AgentRole name: get-llm-key subjects: - authorizationType: "Agent" agentAuthorizationConfiguration: agentName: my-agent # 与 AgentIdentity name 一致确认资源已就绪。ExternalSecretService 的
Available表示 spec 合法且已通过网络探活;CredentialProvider 的Available表示其serviceRef已解析到存在的 ExternalSecretService。kubectl get externalsecretservice kms-dedicated-instance -n <YOUR-NAMESPACE> kubectl get credentialprovider llm-api-key -n <YOUR-NAMESPACE>预期输出:
NAME PROVIDER AVAILABLE AGE kms-dedicated-instance KMS True 30s NAME AVAILABLE AGE llm-api-key True 30sCredentialProvider 的
Available=True仅表示serviceRef已解析,并不代表已成功从 KMS 取到凭据。AAP 权限不足、实例 CA 不匹配、凭据不存在、VPC 网络不通等问题会在实际获取凭据时才暴露,详见状态与排查。
消费凭据
创建并授权好的 API Key 凭据,通常由 Agent Sandbox 出口流量凭据注入消费:在 SecurityProfile 的 tokenTransformation 规则中引用本 CredentialProvider,Sandbox 应用使用占位符 Token 发起请求,出口网关在转发时自动替换为从 KMS 取到的真实 API Key。完整的端到端配置(SecurityProfile、SandboxSet、SandboxClaim 及验证)请参见为Agent Sandbox出口流量配置凭据注入。
secretName 模板变量
secretName 除填写固定的凭据名称外,还可嵌入 ${ack:agent-identity/...} 模板变量。系统在获取凭据时按当前请求身份上下文渲染出实际凭据名称,从而按身份读取不同的 KMS 凭据。例如 llm-api-key-${ack:agent-identity/agent-name} 会按 Agent 名称解析为 llm-api-key-my-agent。
支持的模板变量如下:
模板变量 | 说明 |
| 当前 Agent 身份关联的 AgentIdentity 名称。 |
| 身份 Token 签发时写入的自定义 metadata 中指定 Key 的值, |
以下示例演示按租户动态引用不同的 KMS 凭据:不同租户的 API Key 分别存放在以 llm-api-key-<租户标识> 命名的 KMS 凭据中,CredentialProvider 通过 ${ack:agent-identity/metadata/tenant-id} 在获取凭据时解析出对应的凭据名称。
metadata 的值来自身份 Token 签发时写入的自定义 metadata;在 Agent Sandbox 场景中,可通过 SandboxClaim 的 security.agents.kruise.io/<key> 注解传入(注解去掉前缀后即为 metadata 的 Key):
apiVersion: agents.kruise.io/v1alpha1
kind: SandboxClaim
metadata:
name: my-claim
namespace: <YOUR-NAMESPACE>
spec:
templateName: my-sandbox-set
replicas: 1
annotations:
# 以下 annotation 去掉前缀后可在模板中通过 ${ack:agent-identity/metadata/tenant-id} 引用
security.agents.kruise.io/tenant-id: acme
labels:
security.agents.kruise.io/agent-name: my-agent对应的 CredentialProvider:
apiVersion: agentidentity.alibabacloud.com/v1alpha1
kind: CredentialProvider
metadata:
name: llm-api-key
namespace: <YOUR-NAMESPACE>
spec:
type: APIKey
apiKey:
source:
provider: KMS
kms:
secretName: 'llm-api-key-${ack:agent-identity/metadata/tenant-id}' # 解析为 llm-api-key-acme
serviceRef:
name: kms-dedicated-instance上述配置下,当请求身份的 metadata tenant-id 为 acme 时,secretName 解析为 llm-api-key-acme,即读取该租户专属的 KMS 凭据。
若模板变量在当前请求上下文中无法解析(例如引用的 metadata Key 不存在),凭据获取请求会失败并返回明确的错误信息,而非静默返回空值。
字段说明
ExternalSecretService
provider: KMS 的 spec 结构如下:
spec:
provider: KMS # 必填,外部凭据服务类型;创建后不可变更
kms:
endpoint: <instance-endpoint> # 必填,KMS 实例访问域名
auth:
type: AAP # 必填,认证方式,本文取 AAP(OIDC)
aap:
arn: <aap-arn> # 与 name 二选一,AAP 完整 ARN
# name: <aap-name> # 与 arn 二选一,AAP 短名
caBundle: <ca-pem-or-base64> # 必填,专属实例网关 CA 证书关键字段说明如下:
字段 | 是否必填 | 说明 |
| 是 | 外部凭据服务类型,本文取 |
| 是 | KMS 实例访问域名。专属实例网关形如 |
| 是 | KMS 认证方式,本文取 |
| 二选一 | AAP 完整 ARN,形如 |
| 二选一 | AAP 短名,组件按地域与账号 ID 拼成完整 ARN。与 |
| 是 | 专属实例网关的 CA 证书(公开信息)。接受 base64 编码的 PEM 或裸 PEM。 |
CredentialProvider
type: APIKey + KMS 来源的 spec 结构如下:
spec:
type: APIKey # 必填,凭据类型;创建后不可变更
apiKey:
source:
provider: KMS # 必填,凭据来源
kms:
secretName: <secret-name> # 必填,KMS 凭据名称,支持模板变量
serviceRef:
name: <ess-name> # 必填,同命名空间 ExternalSecretService 名称
versionStage: ACSCurrent # 可选,凭据版本阶段,默认 ACSCurrent
versionId: <version-id> # 可选,指定凭据版本 ID
maxCacheValidity: 15m # 可选,凭据值缓存上限,默认 15m关键字段说明如下:
字段 | 是否必填 | 说明 |
| 是 | 凭据类型,本文取 |
| 是 | 凭据来源,本文取 |
| 是 | KMS 凭据管家中的凭据名称,其值即作为 API Key 下发。支持模板变量。 |
| 是 | 引用的 ExternalSecretService 名称,须与 CredentialProvider 同命名空间。不支持跨命名空间引用。 |
| 否 | 读取的凭据版本阶段,默认 |
| 否 | 读取指定版本 ID 的凭据值;与 |
| 否 | 凭据值缓存上限,默认 |
状态与排查
两个 CR 的运行状态均记录在各自的 status.conditions 中,可通过 kubectl describe 查看。
ExternalSecretService 常见 Condition 与 Reason:
Condition / Reason | 说明 |
| spec 合法且通过了实例 Endpoint 的网络探活。 |
| 实例 Endpoint 无法连通(检查 VPC 共享/网络连通、Endpoint 与 CA 是否正确)。 |
CredentialProvider(KMS 来源)常见 Condition 与 Reason:
Condition / Reason | 说明 |
|
|
|
|
CredentialProvider 的协调阶段只校验 serviceRef 是否存在,不校验能否成功从 KMS 取到凭据。因此与 KMS 访问相关的错误不会体现在 CredentialProvider 状态上,而是在实际获取凭据时才暴露。常见运行时错误及排查方向如下:
现象 | 排查方向 |
获取凭据报权限/认证错误 | 核对 KMS 侧 OIDC(ACK) 的 AAP 配置:Namespace 为 |
获取凭据报 TLS/证书错误 | ExternalSecretService 的 |
获取凭据报凭据不存在 |
|
获取凭据报网络不通/超时 | 集群 VPC 与 KMS 实例 VPC 不一致但未配置 VPC 共享,或安全组/网络策略拦截。参见适用范围中的 VPC 共享说明。 |
使用限制
限制项 | 说明 |
同命名空间引用 | CredentialProvider 只能引用同命名空间下的 ExternalSecretService,不支持跨命名空间。 |
仅专属实例 OIDC 范围 | 本文仅覆盖 KMS 专属实例 + OIDC(ACK) 接入。 |
实例镜像版本 | KMS 专属实例镜像版本需 >= dkms-4.0.0。 |
凭据值缓存 | KMS 源对凭据值有缓存, |
常见问题
CredentialProvider 已 Available,但 Sandbox 获取不到 KMS 凭据?
CredentialProvider 的 Available 仅代表 serviceRef 已解析,不代表能成功从 KMS 取到凭据。请按以下方向排查:
核对 KMS 侧 OIDC(ACK) 的 AAP:Namespace 为
ack-agent-identity、ServiceAccount 为credential-provider(这是组件的 ServiceAccount,不是业务 Pod 的),作用域为目标专属实例,RBAC 含CryptoServiceSecretUser,且目标凭据在允许访问的资源内。确认 ExternalSecretService 的
endpoint与caBundle与专属实例网关一致,且kubectl describe externalsecretservice的 status.conditions 中未出现 Reason 为EndpointUnreachable的记录。确认
secretName(或渲染后的名称)在 KMS 凭据管家中存在。若集群 VPC 与 KMS 实例 VPC 不一致,确认已在 KMS 侧配置 VPC 共享(绑定集群 VPC)。
ExternalSecretService 创建失败提示 no such host?
组件无法解析实例 Endpoint。确认集群 VPC 与 KMS 实例 VPC 一致,或已在 KMS 侧为集群 VPC 配置 VPC 共享/绑定;同时确认 endpoint 填写正确。
ExternalSecretService 一直是 EndpointUnreachable?
组件无法连通实例 Endpoint。确认集群 VPC 与 KMS 实例 VPC 一致,或已在 KMS 侧为集群 VPC 配置 VPC 共享/绑定;同时确认 endpoint 填写正确、caBundle 为该实例网关的 CA。
Agent 获取凭据时被拒绝(无权限)?
确认已创建 AgentRole(action: GetResourceCredential、resource: CredentialProvider/<name>)及 AgentRoleBinding,且 AgentRoleBinding 的 agentName 与目标 AgentIdentity 名称一致,相关资源位于同一命名空间。