您可以在应用Pod中以文件系统或Secret挂载的形式,将存储在阿里云KMS凭据管家中的密文引入到应用程序中使用,避免敏感数据在应用开发构建流程中传播和泄露。ack-secret-manager和csi-secrets-store-provider-alibabacloud插件可用于解决默认从文件系统读取密钥配置的Kubernetes负载应用和阿里云凭据管家交互的兼容性问题。本文介绍如何使用ack-secret-manager或csi-secrets-store-provider-alibabacloud导入阿里云KMS服务凭据。
组件介绍
ack-secret-manager组件支持通过Kubernetes Secret实例的形式向集群导入或同步KMS凭据信息,实现密钥数据的自动更新,应用负载可以通过文件系统挂载指定Secret实例使用凭据信息。
csi-secrets-store-provider-alibabacloud组件除了支持Kubernetes Secret实例形式导入和同步凭据外,还支持通过CSI Inline文件系统的形式直接在应用中挂载凭据密钥,从而降低凭据密文在Secrets实例中暴露的可能。
功能 | ack-secret-manager | csi-secrets-store-provider-alibabacloud |
支持Secret同步和更新 | ||
支持CSI Inline文件系统 |
安全说明
ack-secret-manager和csi-secrets-store-provider-alibabacloud组件用于解决默认从文件系统读取密钥配置的Kubernetes负载应用和阿里云凭据管家交互的兼容性问题。同时也支持将密钥同步创建为集群中的Kubernetes原生Secrets实例,用于环境变量挂载使用。使用前请您评估如下的安全风险。
当密钥在文件系统中可访问时,攻击者可能通过应用中的例如目录遍历(Directory traversal)CVE安全漏洞窃取密钥。
由于一些Debug端点或Logs权限的误配置都可能导致密钥泄露,所以通过环境变量挂载引用的方式消费密钥是一个不安全且不推荐的方式。
当开启Secret实例同步特性时,需要基于权限最小化原则严格控制访问权限。
鉴于上述原因,如果应用中并不需要密文的持久化存储,安全上推荐使用通过RRSA配置ServiceAccount的RAM权限实现Pod权限隔离为应用配置pod维度的最小化权限,并通过凭据管理直接在应用中获取密钥凭据,以减少密钥内容在Pod文件系统或Kubernetes集群Secrets中的暴露面。
配置认证信息
您需要确保ack-secret-manager组件有权限获取KMS服务中的凭据信息,否则ack-secret-manager组件将无法向集群中导入或同步凭据信息,您可以根据集群信息选择如下三种授权配置方式。
方式一:为集群对应的WorkRole添加权限:适用于ACK托管集群。
方式二:通过RRSA授权:适用于1.22及以上版本的ACK托管集群和ACK Serverless集群,推荐在多租场景下使用。
方式三:通过设置AK扮演指定RAM角色:适用于所有容器服务Kubernetes集群。
方式一:为集群对应的WorkRole添加权限
由于ACK Serverless集群没有绑定WorkerRole,该方式只适用于ACK托管集群。
创建自定义权限策略,策略内容如下。具体操作,请参见步骤一:创建自定义权限策略。
{ "Action": [ "kms:GetSecretValue" ], "Resource": [ "*" ], "Effect": "Allow" }
为集群的WorkerRole添加上一步创建的自定义权限。具体操作,请参见步骤二:为集群的Worker RAM角色授权。
方式二:通过RRSA授权
RRSA适用于1.22版本的ACK托管集群和ACK Serverless集群。相比其他授权方式,RRSA授权方式可以实现Pod维度的权限隔离,推荐在多租场景下使用。
创建RAM角色。
您需要创建ack-secret-manager组件使用的RAM角色。具体操作,请参见创建可信实体为阿里云账号的RAM角色。
修改RAM角色信任策略。
您需要修改RAM角色的信任策略,确保指定的服务账户的ack-secret-manager组件有权限获取一个扮演这个RAM角色的临时凭证。更多信息,请参见修改RAM角色的信任策略。
RAM角色信任策略内容示例如下,您也可以使用命令行工具ack-ram-tool中的associate-role命令帮助完成指定的服务账户到角色的信任绑定。
重要在以下策略内容中,需要替换如下字段:
<oidc_issuer_url>
:替换为当前集群的OIDC提供商URL,该URL可以在集群详情的基本信息页签获取。示例格式为:https://oidc-ack-****.oss-****.aliyuncs.com/****
<namespace>
:替换为部署ack-secret-manager的命名空间, 默认为kube-system。<account_uid>
:替换为阿里云账号UID。<cluster_id>
:替换为集群ID。
{ "Statement": [ { "Action": "sts:AssumeRole", "Condition": { "StringEquals": { "oidc:aud": "sts.aliyuncs.com", "oidc:iss": "<oidc_issuer_url>", "oidc:sub": "system:serviceaccount:<namespace>:ack-secret-manager" } }, "Effect": "Allow", "Principal": { "Federated": [ "acs:ram::<account_uid>:oidc-provider/ack-rrsa-<cluster_id>" ] } } ], "Version": "1" }
创建自定义授权策略并为步骤2已创建的RAM角色授权。
在集群中创建名称为alibaba-credentials的Secret,用于配置RRSA中的角色ARN和指定OIDC服务提供商ARN。
使用以下内容,创建alibaba-credentials.yaml文件。
如下
oidcproviderarn
表示当前集群的OIDC提供商ARN,获取该ARN可登录RAM管理控制台,在左侧导航栏选择SSO管理,然后单击OIDC页签,在OIDC身份供应商列表中找到集群对应的OIDC提供商并进入详情页面,获取对应的ARN详情。apiVersion: v1 data: oidcproviderarn: **** rolearn: **** # 指定扮演的RAM角色ARN,需要base64编码。 kind: Secret metadata: name: alibaba-credentials namespace: kube-system type: Opaque
执行以下命令,部署Secret。
kubectl apply -f alibaba-credentials.yaml
方式三:通过设置AK扮演指定RAM角色
创建RAM角色。
您需要创建ack-secret-manager组件使用的RAM角色。具体操作,请参见创建可信实体为阿里云账号的RAM角色。
创建自定义授权策略并为上一步已创建的RAM角色授权。
创建扮演上述角色的自定义授权策略,并为指定RAM用户授权。
在集群中创建名称为alibaba-credentials的Secret,用于配置角色扮演的凭证信息。
使用以下内容,创建alibaba-credentials.yaml文件。
apiVersion: v1 data: id: **** #方式三的步骤3指定RAM用户的AK。 secret: **** #方式三的步骤3指定RAM用户的SK。 rolearn: **** #方式三的步骤1创建的RAM角色ARN。 rolesessionname: **** #可自定义的角色sessionname。 kind: Secret metadata: name: alibaba-credentials namespace: kube-system type: Opaque
执行以下命令,部署Secret。
kubectl apply -f alibaba-credentials.yaml
使用ack-secret-manager
前提条件
安装ack-secret-manager组件
登录容器服务管理控制台,在左侧导航栏选择 。
在应用目录页签下选中全部页签,在搜索框中搜索并选中ack-secret-manager。然后在ack-secret-manager页面右上角,单击一键部署。
在弹出面板中,选择集群,命名空间和发布名称可保持默认值,然后单击下一步。
在参数配置页面,设置相应参数,然后单击确定。
创建成功后,会自动跳转到目标集群的ack-secret-manager页面,检查安装结果。若下图中所有资源创建成功,则表明组件安装成功。
使用示例
通过在阿里云KMS凭据管家中添加一个测试凭据,并在目标集群中创建一个ExternalSecret实例用于展示从凭据管家中导入密钥到集群中创建并同步Secret的过程。
您也可以使用在KMS凭据管家中已有的凭据。
执行以下命令,在KMS凭据管家中添加凭证。更多信息,请参见管理通用凭据。
如果您使用的专属KMS实例,请登录密钥管理服务控制台创建凭据。具体操作,请参见管理及使用通用凭据。
aliyun kms CreateSecret --SecretName test --SecretData 1234 --VersionId v1
使用以下YAML内容,创建hello-service-external-secret.yaml文件。
apiVersion: 'alibabacloud.com/v1alpha1' kind: ExternalSecret metadata: name: hello-service spec: data: - key: test name: password versionStage: ACSCurrent
执行以下命令,创建ExternalSecret测试实例。
kubectl apply -f hello-service-external-secret.yml
执行以下命令,查看目标Secret是否创建成功。
kubectl get secret hello-service -o yaml
预期输出:
apiVersion: v1 kind: Secret metadata: name: hello-service type: Opaque data: password: MTIzNA==
如果存在以上预期输出,表明Secret已创建成功。
修改并同步Secret。
在未关闭自动同步配置的前提下,您还可以修改KMS凭据管家中的密钥信息,等待片刻后查看目标Secret是否已经完成同步。
如果您需要解析一个JSON格式的Secret,并将其中指定的key-value对同步到K8s Secret中,可以使用jmesPath字段。例如,如果您在KMS Secrets Manager中有如下JSON格式的Secret:
{ "username": "testuser", "password": "testpassword" }
为解析其中的
username
和password
键值对并将其独立同步到K8s Secret中,您可以使用如下的jmesPath字段进行配置。当使用jmesPath字段时,必需指定以下两个子字段:
path
:必选项,基于JMES path规范解析JSON中的指定字段。objectAlias
:必选项,用于指定解析出的字段同步到K8s Secret中的Key名称。
data: - key: testJson name: password jmesPath: - path: "username" objectAlias: "MySecretUsername" - path: "password" objectAlias: "MySecretPassword"
同步后的Secret实例如下。
apiVersion: v1 kind: Secret metadata: name: hello-service type: Opaque data: MySecretPassword: dGVzdFBhc3N**** MySecretUsername: dGVzdFVz****
使用csi-secrets-store-provider-alibabacloud
前提条件
已创建ACK集群,且版本为1.20及以上版本。支持ACK托管集群、ACK专有集群、ACK注册集群,暂不支持ACK Serverless集群。具体操作,请参见创建ACK托管集群。
安装csi-secrets-store-provider-alibabacloud
登录容器服务管理控制台,在左侧导航栏选择 。
在应用目录页签下选中全部页签,在搜索框中搜索并选中csi-secrets-store-provider-alibabacloud。然后在csi-secrets-store-provider-alibabacloud页面右上角,单击一键部署。
在弹出面板中,选择集群,命名空间和发布名称可保持默认值,然后单击下一步。
选择Chart版本为最新版本,然后在参数配置页面,设置相应参数后,单击确定。
创建成功后,会自动跳转到目标集群的csi-secrets-store-provider-alibabacloud页面,检查安装结果。若下图中所有资源创建成功,则表明组件安装成功。
使用示例
SecretProviderClass模板格式定义如下所示。
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 kind: SecretProviderClass metadata: name: <NAME> spec: provider: alibabacloud # 此处配置固定为'alibabacloud'。 parameters:
其中
parameters
通常包含挂载请求的三个字段:参数
类型
说明
objects
必选
挂载Secrets凭据的YAML配置声明。例如
parameters: objects: | - objectName: "MySecret"
objects可包含以下子字段:
objectName:必选,对应为指定凭据管家中的密钥名称。更多信息,请参见SecretName。
objectAlias:可选,可用于指定凭据在Pod中挂载的文件名称,如果不指定将默认使用objectName的值。
objectVersion:可选,对应凭据管家中的参数VersionId。
objectVersionLabel:可选,对应凭据管家中的参数VersionStage。
jmesPath:可选,用于解析JSON格式的凭据中的指定键值对字段,例如,以下test凭据示例包含了一段JSON:
{ "username": "testuser", "password": "testpassword" }
如需将
username
和password
分别挂载为一个独立的密钥文件,可以使用如下的jmesPath字段配置。当使用jmesPath字段时,必需指定以下两个子字段:path
:必选项,基于JMES path定义路径检索指定配置项。objectAlias
:必选项,指定的键值对将会以此参数配置作为文件路径挂载。
region
可选
用于请求指定Region下的阿里云凭据管家后端。如果不指定该参数,则默认使用节点对应的阿里云Region。但在大规模应用Pod部署时,可能会带来额外的性能开销,所以推荐配置该参数指定Region。
pathTranslation
可选
如果在凭据管家的密钥凭据包含了文件分隔符,挂载到Pod中的密钥文件会使用该配置指定的字符作为路径之间的分隔符。例如,凭据管家中的
My/Path/Secret
会被挂载为名称是My_Path_Secret的密钥文件。如果不指定该参数,则默认即使用下划线作为分隔符。
如果该参数指定为
“False”
,则路径分割符在挂载时对应的文件名将不会使用任何字符。
一个简单的SecretProviderClass示例模板如下所示。
apiVersion: secrets-store.csi.x-k8s.io/v1alpha1 kind: SecretProviderClass metadata: name: test-secrets spec: provider: alibabacloud # 此处固定配置为 'alibabacloud'。 parameters: objects: | - objectName: "test"
使用以下内容,创建deploy.yaml。
包含一个Nginx Deploy实例,通过CSI Inline文件系统的形式声明使用了上面示例中已经创建的SecretProviderClass,并会在Pod中的
/mnt/secrets-store
目录下挂载凭据密钥。关于Deploy实例更多信息,请参见Deployment示例。apiVersion: apps/v1 # 1.8.0之前版本请使用apps/v1beta1。 kind: Deployment metadata: name: nginx-deployment-basic labels: app: nginx spec: replicas: 2 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: volumes: - name: secrets-store-inline csi: driver: secrets-store.csi.k8s.io readOnly: true volumeAttributes: secretProviderClass: "test-secrets" containers: - name: nginx image: nginx:1.7.9 # 替换为您的实际镜像。 ports: - containerPort: 80 resources: limits: cpu: "500m" volumeMounts: - name: secrets-store-inline mountPath: "/mnt/secrets-store" readOnly: true
执行以下命令,部署Deploy应用。
kubectl apply -f deploy.yaml
验证密钥是否被正常挂载。
登录Pod查看Secret的目标挂载路径
/mnt/secrets-store
下是否已经创建了SecretProviderClass实例中指定密钥名称为文件名的密钥文件,同时查看文件内容是否为KMS凭据中指定的密文。