亚马逊AWS官方博客

如何使用企业的私有证书获取云上资源的访问权限

在 Amazon IAM 中,提供了多种方式来访问云上资源。通常情况下,用户会使用 IAM User 或者 Identity Center 来登录控制台访问云上资源;会使用 IAM Role 来实现亚马逊云科技中云上资源对其他服务的访问权限;在一些开发场景下,往往还存在一些本地环境访问云上资源的场景;这时,一些用户会使用 IAM User 的 Access Key 来获得对云上资源的访问权限,比如上传和下载 S3 对象,启动 EC2 实例等。然而,在本地环境中使用 Access Key 往往会带来一些安全风险,比如:Access Key 在本地环境中被泄露,或者是会在本地开发过程中被上传到组织内或者是公开的代码仓库中等。面对 Access Key 带来的这些安全风险,用户往往会从 Access Key 的管理和权限策略着手增加一些规范和访问限制,比如定期轮换 IP,增加发起对云上资源的 API 调用的访问条件的限制等来避免由 Access Key 泄露引起的安全风险。当然,我们也可以借助于 IAM Roles Anywhere 来完全避免在本地开发环境中使用 Access Key。

使用 IAM Roles Anywhere,并结合企业内部的 PKI,可以将 IAM 角色的使用范围扩展到运行于亚马逊云科技以外的工作负载上,它将会以一种更加安全的方式为本地的开发环境、服务器、容器或者应用程序提供临时安全凭证,从而消除在本地环境中管理和创建长期的使用凭证的需要。

在本文中,将会介绍 IAM Roles Anywhere 的工作原理和相关概念,并使用 easy-rsa 构建一个私有 PKI 来配合 IAM Roles Anywhere 来获取访问亚马逊云科技云上资源的权限。

IAM Roles anywhere 工作原理

IAM Roles Anywhere 要求用户使用 PKI 的 CA 证书在其中创建一个信任锚(Trust Anchor),以此来建立 IAM Roles Anywhere 和 CA 的信任关系。运行在本地的应用程序会使用 CA 签发的证书和签发证书时使用的私钥向 IAM Roles Anywhere 发起对目标 IAM Role 的认证请求,在验证通过后,IAM Roles Anywhere 将会向应用程序返回一个目标角色的临时安全凭证。

在 IAM Roles Anywhere 中,需要创建配置文件(Profile)并在其中关联一个或者多个需要在应用中使用到的 IAM Role;此外,在 IAM Roles Anywhere 的配置文件中,还可以使用托管策略或者内联策略的方式直接将权限添加到当前的配置文件,它们会共同作用在使用当前配置文件获取到的 IAM Role 的权限上。需要注意的是,在 IAM Roles Anywhere 中关联的 IAM Role 需要同 IAM Roles Anywhere 建立信任关系,并且同时包含有 sts:AssumeRolests:SetSourceIdentitysts:TagSession 等基本权限。

构建 PKI、签发证书

easy-rsa 是一个基于 OpenSSL 的命令行工具,使用它可以轻松的创建和管理 PKI,比如创建和管理根证书机构,申请、签发和吊销证书等操作。

初始化 PKI 并创建证书颁发机构(CA)

使用 easy-rsa 提供的 init-pki 命令将一个目录初始化为 PKI 目录,并使用 build-ca 命令在其中创建一个新的证书签发机构(CA)

> easyrsa init-pki

Notice
------
'init-pki' complete; you may now create a CA or requests.

Your newly created PKI dir is:
* /home/ec2-user/root-ca/pki

Using Easy-RSA configuration:
* undefined

> easyrsa build-ca nopass
No Easy-RSA 'vars' configuration file exists!

...
-----
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:ca.examplecorp.com

Notice
------
CA creation complete. Your new CA certificate is at:
* /home/ec2-user/root-ca/pki/ca.crt

在执行结束后,在输出中可以看到当前 CA 的证书位置地址为 /home/ec2-user/root-ca/pki/ca.crt

签发证书

在签发证书之前,需要先使用 gen-req 命令生成证书的私钥,并创建证书签发请求;之后,便可以使用 sign-req 签发证书。

> easyrsa gen-req user1.ca.examplecorp.com nopass
...
Notice
------
Private-Key and Public-Certificate-Request files created.
Your files are:
* req: /home/ec2-user/root-ca/pki/reqs/user1.ca.examplecorp.com.req
* key: /home/ec2-user/root-ca/pki/private/user1.ca.examplecorp.com.key

> easyrsa sign-req client user1.ca.examplecorp.com
...
Notice
------
Certificate created at:
* /home/ec2-user/root-ca/pki/issued/user1.ca.examplecorp.com.crt

在上述操作后,便完成了证书的签发操作;以下为此次签发的证书和证书私钥的路径:

  • 证书:/home/ec2-user/root-ca/pki/issued/user1.ca.examplecorp.com.crt
  • 私钥:/home/ec2-user/root-ca/pki/private/user1.ca.examplecorp.com.key

在 IAM Roles Anywhere 中授权

构建信任锚(Trust anchor)

在 IAM Roles Anywhere 中,使用 CA 证书和 IAM Roles Anywhere 建立信任锚,以验证发起权限调用的应用程序。

> aws rolesanywhere create-trust-anchor --enabled --name <example-trust-anchor> \
  --source sourceData={x509CertificateData="`cat /your/pki/ca.crt`"},sourceType="CERTIFICATE_BUNDLE"
{
    "trustAnchor": {
        "createdAt": "2023-11-06T08:09:13.039766Z",
        "enabled": true,
        "name": "test-ca",
        "notificationSettings": [
            ...
        ],
        "source": {
            ...
        },
        "trustAnchorArn": "arn:aws:rolesanywhere:us-west-2:1234567890:trust-anchor/c775d2e4-8b0a-4d4e-9a5b-e76ca484f61f",
        "trustAnchorId": "c775d2e4-8b0a-4d4e-9a5b-e76ca484f61f",
        "updatedAt": "2023-11-06T08:09:13.039766Z"
    }
}

创建 IAM Roles Anywhere 配置文件(Profile)并关联权限

在 IAM Roles Anywhere 的配置文件中,可以同时关联多个 IAM Role;并且可以在配置文件的会话策略中添加一些内联策略或者托管策略。当客户端对 IAM Roles Anywhere 发起临时安全凭证的调用请求时,这些权限会共同附加在响应的临时安全凭证上。通常情况可以在配置文件中的会话策略添加一些预置的拒绝策略来将授权的范围缩小到目标权限。

在创建要关联到 IAM Roles Anywhere 中的 IAM 角色时,必须要保证其信任策略中允许 IAM Roles Anywhere 访问,并且具有相关的权限。以下是一个基本的信任策略模板:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "",
            "Effect": "Allow",
            "Principal": {
                "Service": "rolesanywhere.amazonaws.com"
            },
            "Action": [
                "sts:AssumeRole",
                "sts:SetSourceIdentity",
                "sts:TagSession"
            ]
        }
    ]
}

在客户端向 IAM Roles Anywhere 发起临时安全凭证的请求时,IAM Roles Anywhere 将会使用对应的信任锚的 ARN 来填充 aws:SourceArnaws:SourceAccount 的值;另外,证书中的 Subject 和 Issue 字段也会被提取出来填充到会话中的 PrincipalTag 元素中。因此,我们也可以在信任策略中组合使用 aws:SourceArnaws:SourceAccountaws:PrincipalTag 来更加精细化的控制设备权限。

在创建完成 IAM 角色之后,便可以使用以下命令在 IAM Roles Anywhere 中创建配置文件,并在配置文件中关联对应的 IAM 角色。

> aws rolesanywhere create-profile --enabled --name <RolesAnywhereAccessRole> \
  --role-arns arn:aws:iam::1234567890:role/RolesAnywhereAccessRole

验证权限

IAM Roles Anywhere 使用 CreateSession API 来提供临时访问凭证,本质上实际上是使用 x509 证书对 AssumeRole API 的一次封装,在 SDK 中并没有在直接的使用方法,需要根据签名流程自行封装。在 Python 中使用 Boto3 也可以参考 awslabs/iam-roles-anywhere-session

rolesanywhere-credential-helper 是一个开源工具,它实现了 IAM Roles Anywhere 的 CreateSession API 的签名个过程,并以 JSON 格式返回临时凭证。

> /path/to/aws_signing_helper credential-process \
then> --certificate /path/to/ca.crt \
then> --private-key /path/to/private.key \
then> --trust-anchor-arn <trust-anchor-arn> \
then> --profile-arn <iamrolesanywhere-profile-arn> \
then> --role-arn <iamrolesanywhere-profile-role-arn>

{"Version":1,"AccessKeyId":"ABCDEFG","SecretAccessKey":"abcedfg","SessionToken":"XXX====","Expiration":"2023-11-19T13:49:35Z"}

此外,rolesanywhere-credential-helper 响应的临时凭证完全兼容 AWS SDK 中的 credential_process;因此,可以在 awscli 中进行以下配置,以使用 IAM Roles Anywhere 获取临时调用凭证,并使用 awcli 验证获取到的权限:

> cat ~/.aws/config
[default]
cli_pager =
region =
credential_process = /path/to/aws_signing_helper credential-process --certificate /path/to/ca.crt --private-key /path/to/private.key --trust-anchor-arn <trust-anchor-arn> --profile-arn <iamrolesanywhere-profile-arn> --role-arn <iamrolesanywhere-profile-role-arn>

> aws sts get-caller-identity
{
    "UserId": "ABCDEFG:00e291ff801b2d8cb699a2f5733092a21e",
    "Account": "1234567890",
    "Arn": "arn:aws:sts::1234567890:assumed-role/iamrolesanywhere-profile-role/00e291ff801b2d8cb699a2f5733092a21e"
}

吊销访问权限

在应用程序从 IAM Roles Anywhere 获取临时安全凭证的流程中,IAM Roles Anywhere 会对发起 API 请求的证书在信任锚中的证书吊销列表(CRL)中进行验证,只有在证书通过 CRL 的验证之后,IAM Roles Anywhere 才会向应用程序响应临时安全凭证。因此,可以在 PKI 通过吊销证书,并在 IAM Roles Anywhere 上传和更新信任锚的证书吊销列表来撤销应用程序的权限。

在 PKI 中生成证书吊销列表

  • 在 PKI 中使用 easy-rsa 吊销签发的证书
    > easyrsa revoke user1.ca.examplecorp.com
    No Easy-RSA 'vars' configuration file exists!
    
    ...
    
    Notice
    ------
                        * IMPORTANT *
    
    Revocation was successful. You must run 'gen-crl' and upload
    a new CRL to your infrastructure in order to prevent the revoked
    certificate from being accepted.
  • 生成 PKI 中的证书吊销列表
    > easyrsa gen-crl
    No Easy-RSA 'vars' configuration file exists!
    
    ...
    
    Notice
    ------
    An updated CRL has been created:
    * /home/ec2-user/root-ca/pki/crl.pem

在 IAM Roles Anywhere 中导入证书吊销列表

在 PKI 中生成证书吊销列表之后,就可以调用 IAM Roles Anywhere 中的 API 将证书吊销列表导入信任锚,从而实现通过 PKI 来控制应用程序获取亚马逊云科技资源临时访问权限的控制。

在 IAM Roles Anywhere 的管理控制台中,暂时还没有实现对证书吊销列表的相关操作;因此需要通过 awscli 或者 API 调用来实现对证书吊销列表的导入、更新、删除、查询等操作。

  • 将证书吊销列表导入信任锚;需要注意的是,在证书吊销列表导入信任锚后默认不会启用;需要在导入时使用 --enabled 参数显式指定启用当前导入的证书吊销列表,或者是在导入后使用 EnableCrl API 来启用指定的证书吊销列表;
    > aws rolesanywhere import-crl --name revoke-crl \
    then> --crl-data fileb:///path/to/pki/crl.pem \
    then> --trust-anchor-arn arn:aws:rolesanywhere:us-west-2:1234567890:trust-anchor/284547ec-4418-4999-8020-c96543ad50c5 \
    then> --enabled
    
    {
        "crl": {
            "createdAt": "2023-11-22T07:37:25.037479+00:00",
            "crlArn": "arn:aws:rolesanywhere:us-west-2:1234567890:crl/3551e29a-e269-4b4a-99f2-b6effe3d59b9",
            "crlData": "xxxxxxxxxxxxx==",
            "crlId": "3551e29a-e269-4b4a-99f2-b6effe3d59b9",
            "enabled": true,
            "name": "revoke-crl",
            "trustAnchorArn": "arn:aws:rolesanywhere:us-west-2:1234567890:trust-anchor/284547ec-4418-4999-8020-c96543ad50c5",
            "updatedAt": "2023-11-22T07:37:25.037479+00:00"
        }
    }
  • 使用 aws_signing_helper 验证吊销的权限:此时可以看到在发起获取临时安全凭证的调用时,在响应内容中会响应证书被吊销;
    > /path/to/aws_signing_helper credential-process \
    then> --certificate /path/to/ca.crt \
    then> --private-key /path/to/private.key \
    then> --trust-anchor-arn <trust-anchor-arn> \
    then> --profile-arn <iamrolesanywhere-profile-arn> \
    then> --role-arn <iamrolesanywhere-profile-role-arn>
    
    >2023/11/22 07:41:43 AccessDeniedException: Certificate revoked

最佳实践

  • 由于 IAM Roles Anywhere 使用 PKI 中的 CA 来作为信任锚,PKI 的受损往往会给云上资源带来较大的安全风险,因此需要在 PKI 上执行严格的安全措施和保护措施,避免 PKI 受损;在一些企业级的生产环境中,强烈建议使用由亚马逊云科技托管的私有证书颁发机构 Private CA 服务,它和 IAM Roles Anywhere 的集成也会有更简单的使用方式;
  • 在本地运行的应用程序往往和云上运行的资源对权限有不一样的要求;因此,强烈建议在 IAM Roles Anywhere 中使用独立的 IAM Role,为不同的工作负载配置不同的 IAM Role,并且严格控制关联到 IAM Role 会上的权限策略,从而来保证在本地运行的应用程序只能拿到应用所需要的云上资源的权限,控制爆炸半径;
  • 使用 PKI 的设置或者在信任锚中配置对 CA 证书和获取临时凭证的证书的有效期的监控和告警,避免在证书失效后验证失败导致应用程序无法获取临时访问凭证。

本篇作者

薛佳庆

亚马逊云科技解决方案架构师,负责为互联网出海客户提供云上服务的解决方案;在无服务器,容器技术,数据分析等方面有丰富的经验。

杨东祥

领创集团运维总监,目前主要负责领创集团 IT 基础设施的维护和管理;另外在云计算、容器技术、Devops 等领域都有丰富的实践经验,致力于通过自动化提高企业运维的效率。

穆迪

亚马逊云科技技术客户经理,负责支持亚马逊云科技企业出海客户在云上的架构优化、成本管理、技术咨询等服务。深耕互联网行业多年,在数据中心管理、服务器、存储及网络等领域有丰富的实践经验。加入亚马逊云科技前,任职于搜狐担任基础架构部高级研究员,后担任系统集成商解决方案经理及云事业部总监。