通过RRSA配置ServiceAccount的RAM权限实现Pod权限隔离

基于适用于服务账户的RAM角色(RAM Roles for Service Accounts,简称RRSA)功能,您可以在集群内实现Pod维度的OpenAPI权限隔离,从而实现云资源访问权限的细粒度隔离,降低安全风险。本文介绍如何在集群中使用RRSA。

索引

背景信息

ECS实例元数据包含ECS实例(ECI实例基于ECS实例实现)在阿里云系统中的信息。您可以在运行中的实例内查看实例元数据,并基于实例元数据配置或管理实例。通过实例元数据,Kubernetes集群内应用可以获取实例RAM角色策略所生成的STS临时凭证,然后通过该临时凭证访问云资源OpenAPI。更多信息,请参见ECS实例元数据概述

image

当您需要限制集群内不同应用的RAM权限时,出于安全考虑,您应当禁止这些应用通过ECS或ECI实例元数据获取您的实例关联角色对应的临时凭证或者不为实例关联角色授予任何RAM权限策略。但这些应用仍然会需要一种安全的途径去获取访问云资源的临时凭证。因此,阿里云容器服务ACK联合RAM访问控制服务推出了RRSA功能。

基于RRSA功能,您可以在集群内实现Pod级别隔离的应用关联RAM角色功能。各个应用可以扮演独立的RAM角色并使用获取的临时凭证访问云资源,从而实现应用RAM权限最小化以及无AccessKey访问阿里云OpenAPI避免AccessKey泄露的需求。

image

从用户侧视角来看,RRSA功能的工作流程如下。

  1. 用户提交使用了服务账户令牌卷投影功能的应用Pod。

  2. 集群将为该应用Pod创建和挂载相应的服务账户OIDC Token文件。

  3. Pod内程序使用挂载的OIDC Token文件访问STS服务的AssumeRoleWithOIDC接口,获取扮演指定RAM角色的临时凭证。

    说明
    • 请提前修改RAM角色配置,允许Pod使用的服务账户扮演该RAM角色。更多信息,请参见AssumeRoleWithOIDC

    • 从文件中读取的OIDC Token是一个临时Token,建议应用程序每次在使用时都从文件中读取最新的Token,集群会在Token过期前更新替换文件内已有的Token。

  4. Pod内程序使用获取到的临时凭证访问云资源OpenAPI。

使用限制

RRSA功能目前仅支持1.22及以上版本的集群,即ACK集群基础版ACK集群Pro版ACK Serverless集群基础版ACK Serverless集群Pro版

启用RRSA功能

  1. 登录容器服务管理控制台

  2. 在控制台左侧导航栏,单击集群

  3. 集群列表页面,单击目标集群名称或者目标集群右侧操作列下的详情

  4. 在集群详情页面,单击基本信息页签,然后在集群信息区域单击RRSA OIDC对应的启用RRSA

  5. 在弹出的启用RRSA对话框,单击确定

    基本信息区域,当集群状态由更新中变为运行中后,表明该集群的RRSA特性已变更完成,RRSA OIDC右侧将显示OIDC提供商的URL链接和ARN信息。

集群开启RRSA功能后,ACK将在后台执行如下操作。

  • 自动创建一个集群专用的OIDC Issuer服务。该服务由ACK托管,无需您运维。更多信息,请参见OIDC Issuer

  • 修改当前集群的服务账户令牌卷投影功能的配置,使用本次创建的OIDC Issuer配置合并集群已有的service-account-issuer参数的值。更多信息,请参见部署服务账户令牌卷投影

  • 在您的账号下创建一个使用该OIDC Issuer的OIDC身份提供商,名称为ack-rrsa-<cluster_id>,其中 <cluster_id>为您的集群ID。更多信息,请参见管理OIDC身份提供商

使用RRSA功能

集群开启RRSA功能后,您可以参考以下内容,赋予集群内应用通过RRSA功能获取访问云资源OpenAPI的临时凭证的能力。

使用示例

本示例部署的应用将使用RRSA功能扮演指定角色,获取当前账号下集群列表信息。

示例配置

  • 命名空间:rrsa-demo

  • ServiceAccount:demo-sa

  • RAM角色:demo-role-for-rrsa

示例流程

使用示例流程

  • 如果您希望通过不安装ack-pod-identity-webhook组件的方式使用RRSA功能,您可以手动修改应用模板挂载应用所需的OIDC Token文件并配置相关环境变量。具体操作,请参见手动修改应用模板使用RRSA功能

  • 如果您希望使用已存在的RAM角色,不创建新的RAM角色,您可以为已有RAM角色新增相关权限。具体操作,请参见使用已存在的RAM角色并授权

  1. 安装ack-pod-identity-webhook组件。

    1. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择运维管理 > 组件管理

    2. 组件管理页面,单击安全页签,找到ack-pod-identity-webhook组件,单击组件右下方的安装

    3. 在提示对话框确认组件信息后,单击确定

  2. 创建一个名为demo-role-for-rrsa的RAM角色。

    1. 使用阿里云账号登录RAM控制台

    2. 在左侧导航栏,选择身份管理 > 角色,然后在角色页面,单击创建角色

    3. 创建角色面板,选择可信实体类型为身份提供商,然后单击下一步

    4. 配置角色页面,配置如下角色信息后,单击完成

      本示例配置如下。

      配置项

      描述

      角色名称

      demo-role-for-rrsa。

      备注

      选填有关该角色的备注信息。

      身份提供商类型

      OIDC

      选择身份提供商

      ack-rrsa-<cluster_id>。其中,<cluster_id>为您的集群ID。

      限制条件

      • oidc:iss:保持默认。

      • oidc:aud:选择sts.aliyuncs.com

      • oidc:sub:条件判定方式选择StringEquals,值的格式为system:serviceaccount:<namespace>:<serviceAccountName>

        • <namespace>:应用所在的命名空间。

        • <serviceAccountName>:服务账户名称。

        根据测试应用的信息,此处需要填入system:serviceaccount:rrsa-demo:demo-sa

  3. 步骤2创建的角色授予测试应用所需的AliyunCSReadOnlyAccess系统策略权限。具体操作,请参见为RAM角色授权

  4. 部署测试应用。关于测试应用的参考代码,请参见阿里云官方SDK使用RRSA OIDC Token的参考代码

    1. 使用以下内容,创建demo.yaml文件。

      如下YAML示例中,为命名空间增加标签pod-identity.alibabacloud.com/injection: 'on',并为服务账户增加注解pod-identity.alibabacloud.com/role-name: demo-role-for-rrsa,启用ack-pod-identity-webhook组件的配置自动注入功能。关于ack-pod-identity-webhook组件配置的更多说明,请参见ack-pod-identity-webhook

      展开查看示例代码

      ---
      apiVersion: v1
      kind: Namespace
      metadata:
        name: rrsa-demo
        labels:
          pod-identity.alibabacloud.com/injection: 'on'
      
      ---
      apiVersion: v1
      kind: ServiceAccount
      metadata:
        name: demo-sa
        namespace: rrsa-demo
        annotations:
          pod-identity.alibabacloud.com/role-name: demo-role-for-rrsa
      
      ---
      apiVersion: v1
      kind: Pod
      metadata:
        name: demo
        namespace: rrsa-demo
      spec:
        serviceAccountName: demo-sa
        containers:
          - image: registry.cn-hangzhou.aliyuncs.com/acs/ack-ram-tool:1.0.0
            imagePullPolicy: "Always"
            args:
              - rrsa
              - demo
            name: demo
        restartPolicy: OnFailure
    2. 执行以下命令,部署测试应用。

      kubectl apply -f demo.yaml
  5. 执行以下命令,查看测试应用Pod,确认ack-pod-identity-webhook组件已为Pod自动注入所需的配置。

    kubectl -n rrsa-demo get pod demo -o yaml

    展开查看预期输出

    apiVersion: v1
    kind: Pod
    metadata:
      name: demo
      namespace: rrsa-demo
    spec:
      containers:
      - args:
        - rrsa
        - demo
        env:
        - name: ALIBABA_CLOUD_ROLE_ARN
          value: acs:ram::1***:role/demo-role-for-rrsa
        - name: ALIBABA_CLOUD_OIDC_PROVIDER_ARN
          value: acs:ram::1***:oidc-provider/ack-rrsa-c***
        - name: ALIBABA_CLOUD_OIDC_TOKEN_FILE
          value: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens/token
        image: registry.cn-hangzhou.aliyuncs.com/acs/ack-ram-tool:1.0.0
        imagePullPolicy: Always
        name: demo
        volumeMounts:
        - mountPath: /var/run/secrets/kubernetes.io/serviceaccount
          name: kube-api-access-4bwdg
          readOnly: true
        - mountPath: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens
          name: rrsa-oidc-token
          readOnly: true
      restartPolicy: OnFailure
      serviceAccount: demo-sa
      serviceAccountName: demo-sa
      volumes:
      - name: kube-api-access-4bwdg
        projected:
          defaultMode: 420
          sources:
          - serviceAccountToken:
              expirationSeconds: 3607
              path: token
          - configMap:
              items:
              - key: ca.crt
                path: ca.crt
              name: kube-root-ca.crt
          - downwardAPI:
              items:
              - fieldRef:
                  apiVersion: v1
                  fieldPath: metadata.namespace
                path: namespace
      - name: rrsa-oidc-token
        projected:
          defaultMode: 420
          sources:
          - serviceAccountToken:
              audience: sts.aliyuncs.com
              expirationSeconds: 3600
              path: token

    预期输出表明,ack-pod-identity-webhook组件已为Pod自动注入了如下配置。

    类别

    配置项名称

    配置项说明

    环境变量

    ALIBABA_CLOUD_ROLE_ARN

    需要扮演的RAM角色ARN。

    ALIBABA_CLOUD_OIDC_PROVIDER_ARN

    OIDC身份提供商的ARN。

    ALIBABA_CLOUD_OIDC_TOKEN_FILE

    包含OIDC Token的文件路径。

    VolumeMount

    rrsa-oidc-token

    挂载OIDC Token的配置。

    Volume

    rrsa-oidc-token

    挂载OIDC Token的配置。

  6. 执行以下命令,查看测试应用日志。

    kubectl -n rrsa-demo logs demo

    预期输出集群列表信息:

    cluster id: cf***, cluster name: foo*
    cluster id: c8***, cluster name: bar*
    cluster id: c4***, cluster name: foob*
  7. 可选:移除角色被授予的AliyunCSReadOnlyAccess系统策略权限。具体操作,请参见为RAM角色移除权限

    等待30秒左右,执行以下命令,再次查看测试应用日志。

    kubectl -n rrsa-demo logs demo

    预期输出无权限的错误日志:

       StatusCode: 403
       Code: StatusForbidden
       Message: code: 403, STSToken policy Forbidden for action cs:DescribeClusters request id: E78A2E2D-***
       Data: {"accessDeniedDetail":{"AuthAction":"cs:DescribeClusters","AuthPrincipalDisplayName":"demo-role-for-rrsa:ack-ram-tool","AuthPrincipalOwnerId":"11***","AuthPrincipalType":"AssumedRoleUser","NoPermissionType":"ImplicitDeny","PolicyType":"ResourceGroupLevelIdentityBasedPolicy"},"code":"StatusForbidden","message":"STSToken policy Forbidden for action cs:DescribeClusters","requestId":"E78A2E2D-***","status":403,"statusCode":403}

手动修改应用模板使用RRSA功能

您可以通过手动修改应用模板挂载应用所需的OIDC Token文件以及配置相关环境变量,在不安装ack-pod-identity-webhook组件的情况下使用RRSA功能。

应用模板示例代码如下。

展开查看应用模板示例代码

apiVersion: v1
kind: Pod
metadata:
  name: demo
  namespace: rrsa-demo
spec:
  containers:
  - args:
    - rrsa
    - demo
    env:
    - name: ALIBABA_CLOUD_ROLE_ARN
      value: <role_arn>
    - name: ALIBABA_CLOUD_OIDC_PROVIDER_ARN
      value: <oid_provider_arn>
    - name: ALIBABA_CLOUD_OIDC_TOKEN_FILE
      value: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens/token
    image: registry.cn-hangzhou.aliyuncs.com/acs/ack-ram-tool:1.0.0
    imagePullPolicy: Always
    name: demo
    volumeMounts:
    - mountPath: /var/run/secrets/ack.alibabacloud.com/rrsa-tokens
      name: rrsa-oidc-token
      readOnly: true
  restartPolicy: OnFailure
  serviceAccount: demo-sa
  serviceAccountName: demo-sa
  volumes:
  - name: rrsa-oidc-token
    projected:
      defaultMode: 420
      sources:
      - serviceAccountToken:
          audience: sts.aliyuncs.com
          expirationSeconds: 3600
          path: token
重要

请替换应用模板示例代码中的如下字段。

  • <oid_provider_arn>:替换为当前集群的OIDC提供商ARN。该ARN可在容器服务管理控制台集群信息页面的基本信息页签获取。

  • <role_arn>需要替换为当前应用使用的RAM角色ARN。该ARN可在RAM控制台角色页面的角色详情页面获取。

  • audience字段值必须为sts.aliyuncs.com。该字段值对应的是开启RRSA功能时自动创建的OIDC身份提供商中配置的客户端ID,与SDK访问STS的AssumeRoleWithOIDC接口时使用的域名无关,您可以在使用SDK时指定使用合适的STS域名。

  • expirationSeconds:单位为秒,取值范围为[600, 43200],即10分钟~12小时。如果设置的值大于43200(12小时),实际的OIDC Token的过期时间仍为12小时。

部署修改后的应用模板后,应用内程序可以使用容器内挂载的OIDC Token(环境变量ALIBABA_CLOUD_OIDC_TOKEN_FILE指向的文件内容,每次使用时都需要从文件中读取最新的Token)、角色的ARN(环境变量ALIBABA_CLOUD_ROLE_ARN配置的值)以及OIDC身份提供商的ARN(环境变量ALIBABA_CLOUD_OIDC_PROVIDER_ARN配置的值),调用STS的AssumeRoleWithOIDC接口,获取一个扮演指定RAM角色的临时凭证,然后使用该临时凭证访问云资源OpenAPI。应用参考代码,请参见阿里云官方SDK使用RRSA OIDC Token的参考代码。更多信息,请参见AssumeRoleWithOIDC

使用已存在的RAM角色并授权

如果您的应用需要使用已存在的RAM角色,而非创建新的单独RAM角色,您可以修改RAM角色的信任策略,新增一条允许使用指定的服务账户的应用有权限通过扮演此RAM角色获取临时凭证的信任策略。更多信息,请参见修改RAM角色的信任策略

RAM角色信任策略中新增的Statement条目内容示例如下。

{
  "Action": "sts:AssumeRole",
  "Condition": {
    "StringEquals": {
      "oidc:aud": "sts.aliyuncs.com",
      "oidc:iss": "<oidc_issuer_url>",
      "oidc:sub": "system:serviceaccount:<namespace>:<service_account>"
    }
  },
  "Effect": "Allow",
  "Principal": {
    "Federated": [
      "<oidc_provider_arn>"
    ]
  }
}
重要

请替换Statement条目内容示例中的如下字段。

  • <oidc_issuer_url>:替换为当前集群的OIDC提供商URL。该URL可在容器服务管理控制台集群信息页面的基本信息页签获取。

  • <oidc_provider_arn>:替换为当前集群的OIDC提供商ARN。该ARN可在容器服务管理控制台集群信息页面的基本信息页签获取。

  • <namespace>:替换为应用所在的命名空间。

  • <service_account>:替换为应用使用的服务账户。

您也可以使用命令行工具ack-ram-tool通过自动化的方式配置该策略。对应的命令行示例如下。

ack-ram-tool rrsa associate-role --cluster-id <cluster_id> \
    --namespace <namespace> --service-account <service_account> \
    --role-name <role_name> --create-role-if-not-exist

阿里云官方SDK使用RRSA OIDC Token的参考代码

SDK参考代码

目前,阿里云V2.0 SDK已经内置了支持使用RRSA OIDC Token进行OpenAPI认证的功能,所有基于V2.0 SDK生成并且支持STS Token认证的云产品SDK都将默认支持RRSA OIDC Token认证。支持此功能的SDK版本信息和参考代码如下。

编程语言

支持认证的SDK版本

使用示例

Go

Alibaba Cloud Credentials for Go 1.2.6及以上版本。更多信息,请参考方式七:使用OIDCRoleArn

Go SDK使用示例

Java

Alibaba Cloud Credentials for Java 0.2.10及以上版本。更多信息,请参考方式六:使用OIDCRoleArn

Java SDK使用示例

Python 3

Alibaba Cloud Credentials for Python 0.3.1及以上版本。更多信息,请参考方式七:使用OIDCRoleArn

Python 3 SDK使用示例

Node.js和TypeScript

Alibaba Cloud Credentials for TypeScript/Node.js 2.2.6及以上版本。更多信息,请参考方式七:使用OIDCRoleArn

Node.js和TypeScript使用示例

部分云产品自研的SDK也可以参考上面的方法实现使用RRSA OIDC Token进行OpenAPI认证的功能。具体实现方式的参考代码如下。

云产品

SDK

使用示例

对象存储

OSS GO SDK

更多信息,请参考OIDC访问凭证

Go SDK使用示例

OSS Java SDK

更多信息,请参考OIDC访问凭证

Java SDK使用示例

OSS Python SDK

更多信息,请参考OIDC访问凭证

Python SDK使用示例

日志服务

日志服务Java SDK

更多信息,请参考Java SDK快速入门

Java SDK使用示例

SDK报错信息解决方法

不同报错信息的解决方法如下表所示。

报错信息

原因

解决方法

{
 "Code": "AuthenticationFail.OIDCToken.Expired",
 "Message": "This JsonWebToken is expired."
}

您的应用使用的OIDC Token已过期。

您需要每次都从环境变量ALIBABA_CLOUD_OIDC_TOKEN_FILE指向的文件中读取最新的OIDC Token。建议您使用阿里云官方SDK而不是自行实现获取临时凭证的逻辑。更多信息,请参见阿里云官方SDK使用RRSA OIDC Token的参考代码

{
 "Code": "Throttling.User",
 "Message": "Request was denied due to user flow control."
}

您的应用获取临时凭证的操作太频繁,导致操作被限流。

请勿过于频繁调用获取临时凭证的接口,在临时凭证过期前您无需频繁获取新的凭证。建议您使用阿里云官方SDK而不是自行实现获取临时凭证的逻辑。更多信息,请参见阿里云官方SDK使用RRSA OIDC Token的参考代码

{
 "Code": "AuthenticationFail.OIDCToken.AudienceNotMatch",
 "Message": "Invalid audience."
}

您的应用模板中audience配置项的值不是sts.aliyuncs.com

您需要修改应用模板,确保配置项audience的值是预期的sts.aliyuncs.com

{
 "Code": "AuthenticationFail.OIDCToken.IssuerConfigurationBroken",
 "Message": "Get public keys from OIDC Provider failed, the issuer is https://kubernetes.default.svc."
}
{
 "Code": "AuthenticationFail.OIDCToken.IssuerNotMatch",
 "Message": "The issuer in the OIDC Token doesn't match the OIDC Provider registered."
}

您的集群未启用RRSA功能。

您需要为应用所在集群启用RRSA功能。操作方法,请参见启用RRSA功能。完成启用RRSA功能操作后,您还需要重建使用RRSA功能的应用Pod。

{
 "Code": "EntityNotExist.Role",
 "Message": "The role not exists: acs:ram::19981***:role/***. "
}

您的应用所使用的RAM角色不存在。

您需要创建对应的RAM角色。操作方法,请参见创建OIDC身份提供商的RAM角色以及使用示例

{
  "Code": "AuthenticationFail.NoPermission",
  "Message": "There is no permission"
}

您的应用所使用的RAM角色未完成所需的信任策略配置。

您需要修改RAM角色的信任策略,允许您的应用扮演该角色。操作方法,请参见使用已存在的RAM角色并授权

常用命令行工具使用RRSA OIDC Token

借助ack-ram-tool,可以赋予部分常用命令行工具在容器内使用RRSA OIDC Token的能力。具体配置和使用示例详见下表。

命令行工具

配置方法

使用示例

阿里云CLI

您可以在配置文件~/.aliyun/config.json中通过配置mode配置项的值为OIDC的方式使用RRSA OIDC Token。

说明
  • 仅v3.0.206及以上版本的阿里云CLI支持该特性。

  • 需要将配置文件中region_id的值替换为您期望的地域。

{
  "current": "rrsa",
  "profiles": [
    {
      "name": "rrsa",
      "mode": "OIDC",
      "region_id": "cn-hangzhou",
      "ram_session_name": "test-rrsa"
    }
  ],
  "meta_path": ""
}
$ aliyun sts GetCallerIdentity
{
    "AccountId": "11380***",
    "Arn": "acs:ram::1138***:assumed-role/test-rrsa-***/test-rrsa",
    "IdentityType": "AssumedRoleUser",
    "PrincipalId": "33300***:test-rrsa",
    "RequestId": "20F78881-F47E-5771-90D6-***",
    "RoleId": "33300***"
}

您也可以不创建配置文件,直接执行阿里云CLI相关命令。

说明

仅v3.0.206及以上版本的阿里云CLI支持该特性。

$ aliyun sts GetCallerIdentity --region cn-hangzhou --role-session-name=test-rrsa
{
	"AccountId": "11380***",
	"Arn": "acs:ram::1138***:assumed-role/test-rrsa-***/test-rrsa",
	"IdentityType": "AssumedRoleUser",
	"PrincipalId": "33300***:test-rrsa",
	"RequestId": "20F78881-F47E-5771-90D6-***",
	"RoleId": "33300***"
}

日志服务CLI

暂不支持在日志服务CLI的配置文件中指定使用RRSA OIDC Token,您需要使用命令ack-ram-tool export-credentials -f environment-variables -- aliyunlog执行日志服务CLI相关命令。

$ ack-ram-tool export-credentials -f environment-variables -- aliyunlog log list_project --region-endpoint=cn-hangzhou.log.aliyuncs.com

{"count": 1, "projects": [
{"createTime": "1676282996", "description": "k8s log project, ***",
 "lastModifyTime": "1676282996", "owner": "", "projectName": "k8s-log-c0edc***", 
 "region": "cn-hangzhou", "resourceGroupId": "rg-***", "status": "Normal"}],
  "total": 24}

Terraform

您可以在配置文件中通过配置assume_role_with_oidc配置项的方式使用RRSA OIDC Token。

说明
  • 仅v1.222.0及以上版本的阿里云Provider支持该配置项。

  • 需要将配置文件中region的值替换为您期望的地域。

provider "alicloud" {
  assume_role_with_oidc {
    role_session_name = "terraform-with-rrsa-auth-example"
  }
  region = "cn-hangzhou"
}

Terraform使用示例

相关文档