亚马逊AWS官方博客

如何从IDC 使用临时安全凭证访问 Amazon Secrets Manager-将 Role的使用延伸到 IDC

安全凭证的泄露是造成企业安全事故的常见原因之一. 为了解决安全的分发安全凭证,并且按时进行安全凭证的轮转的问题. 亚马逊云科技的SecretsManager提供了一个解决方案.安全凭证集中保存在 SecretsManager 服务中,由 KMS 服务加密保护.访问权限通过 IAM 来进行控制. 分发出去的是安全凭证的引用名,避免将安全凭证在分发过程中造成泄露,也避免了人员流动造成的安全凭证失控.

对 SecretsManager 的访问必须具有合适 IAM 的权限. 我们的安全最佳实践之一是建议大家尽量使用临时安全凭证,比如 role,避免使用长期安全凭证(比如user的AK/SK). 在云中的环境,我们可以给 EC2, lambda, ECS等计算资源都通过 Role 的方式赋予临时安全凭证.然而,在企业的数据中心或者其他的云环境下,无法使用 Role, 很多时候,必须使用 user 的 AK/SK 这样的长期安全凭证.随着今年 IAM Roles Anywhere这个服务的发布, 使得我们可以在亚马逊云科技之外也使用 Roles替换之前的AK/SK.降低了安全凭证的暴露风险.下文将介绍相关的方案和实践细节.

一. 方案概览

本场景中,部署于数据中心的微服务需要访问云上的数据库和数据中心的数据库.该服务器通过 IAM Roles Anywhere获取 IAM 的临时凭证,然后服务器上的微服务可以利用该临时凭证获取存储于 secrets manager中的数据库访问凭证.数据库的安全凭证的定期轮换,通过 lambda 来定期触发执行完成. Lambda函数通过数据库获取新的安全凭证后,更新 Amazon SecretsManager中的配置. 整个过程不需要在该服务器上配置 AKSK.

下图提供了方案架构的概览

  1. 在private CA和 IAM Roles Anywhere 之间建立 trust anchor,配置相应的 role 和 profile;
  2. 通过 ACM 下载证书到数据中心的服务器上;调整 Amazon SDK Config配置, 使用credential_process 获取临时安全凭证替代静态的长期安全凭证;
  3. 运行数据中心的服务器上部署的Service, 该 Service 调用 SDK, SDK 调用credential_process向AM Roles Anywhere 提出访问请求
  4. IAM Roles Anywhere 校验证书通过后到 STS 服务交换该 role 对应的临时安全凭证,返回 然后更新本地的临时安全凭证;
  5. 数据中心的服务器上的service使用更新后的临时安全凭证,向 Amazon SecretsManager提出请求, Amazon SecretsManager校验权限通过后,返回请求的数据库安全凭证;
  6. 本地Service, 通过数据库安全凭证访问云上的数据库或者本地数据库.

实施介绍

方案实施包括三个环节

一, 私有证书体系建立. 如果已经建立了私有证书体系,可以略过此章节

二, IAM Roles Anywhere 配置

三, SecretsManager 配置

第一步, 通过 privateCA创建私有 CA

CA 是 Certificate authority的缩写.在创建私有CA之前,需要根据您的企业的组织架构设计您的私有CA 体系. 参考的 CA体系架构如下图:

一般来说,根 CA 用于颁发和认证二级证书, 二级证书用于颁发和认证三级证书, 三级证书则用于签发终端实体证书 end-entity Certificate. 设计样例如下:

私有 CA 体系的设计的更多细节可以参见https://docs.thinkwithwp.com/privateca/latest/userguide/ca-hierarchy.html. 完成设计之后,就可以创建相应的CA.

创建方法(CLI)

首先创建配置文件 ca_config.txt

{
   "KeyAlgorithm":"RSA_2048",
   "SigningAlgorithm":"SHA256WITHRSA",
   "Subject":{
      "Country":"US",
      "Organization":"Example Corp",
      "OrganizationalUnit":"Sales",
      "State":"WA",
      "Locality":"Seattle",
      "CommonName":"www.example.com"
   }
}

调用CLI create-certificate-authority 命创建 CA:

aws acm-pca create-certificate-authority \
     --certificate-authority-configuration file://ca_config.json \
     --certificate-authority-type "ROOT" \
     --idempotency-token 01234567 \
     --tags  Key=Name,Value=MyPCA

使用CLI 命令describe-certificate-authority 查看刚刚创建的 CA

aws acm-pca describe-certificate-authority \
         --certificate-authority-arn arn:aws:acm:region:account:certificate-authority/CA_ID

命令返回结果样例如下

{
       "CertificateAuthority":{
          "Arn":"arn:aws:acm-pca:region:account:certificate-authority/CA_ID",
          "CreatedAt":"2022-09-30T09:53:42.769000-07:00",
          "LastStateChangeAt":"2022-09-30T09:53:43.784000-07:00",
          "Type":"ROOT",
          "Serial":"serial_number",
          "Status":"PENDING_CERTIFICATE",
          "CertificateAuthorityConfiguration":{
             "KeyAlgorithm":"RSA_2048",
             "SigningAlgorithm":"SHA256WITHRSA",
             "Subject":{
                "Country":"US",
                "Organization":"Example Corp",
                "OrganizationalUnit":"Sales",
                "State":"WA",
                "Locality":"Seattle",
                "CommonName":"www.example.com"
             }
          },
          "RevocationConfiguration":{
             "CrlConfiguration":{
                "Enabled":false
             },
             "OcspConfiguration":{
                "Enabled":false
             }
          },
    ...

注意,这个时候,CA 创建起来,status 是“PENDING_CERTIFICATE”, 表明还需要安装证书

通过 Console 安装证书的过程会比较简单一些

为你的私有Root CA创建和安装证书

打开AWS Private CA 控制台 https://console.thinkwithwp.com/acm-pca/home. 在 Private certificate authorities 页面, 选择刚才创建的 root CA , 状态是 Pending certificate.

选择 Actions, Install CA certificate 来打开Install root CA certificate 页面.

在 Specify the root CA certificate parameters, 制定相关的私有证书的参数:

Validity — CA 证书的过期时间. AWS私有CA 赋予 根 CA 证书的缺省过期时间是10年.

Signature algorithm — 选择使用该CA签名颁发新证书的算法. 可选项包括:

SHA256 RSA

SHA384 RSA

SHA512 RSA

检查您的设置是否正确,然后点击 Confirm and install. AWS Private CA 会为您的 CA 导出一份CSR, 使用根CA 证书模板创建一个证书, 完成自签名. 然后AWS Private CA 导入这份自签名的 根 CA 证书.

如果证书安装成功, 这个新创建的根 CA 的状态就会变成Active. 根CA的创建就完成了.

注:创建 CA 的其他选项参见 https://docs.thinkwithwp.com/privateca/latest/userguide/Create-CA-CLI.html

使用 CA 颁发终端实体证书

完成根 CA 的安装和配置之后,就可以到 ACM申请终端实体证书了.

点击 Next. 完成必要参数的选择,包括
选择刚才创建的对应您的组织架构的 private Certificate Authority, 填写合适的 domain name.

根据需要,选择该证书的加密算法, 支持包括 RSA 2048, ECDSA P 256, ECDSA P 384.

点击 Next, 即可以完成对End Entity Certificate 的签发;

导出终端实体证书

私有证书是支持导出的.在 Amazon Certificate Manager 控制台中,从证书列表中选择之前创建的终端实体证书, 选择导出即可进入下面的界面

注意填写用于加密证书私钥的口令,为了安全, 证书私钥将通过该口令加密, 加密后的证书和证书私钥将通过浏览器下载到本地.

导出的证书,在使用前,需要将加密的私有证书密钥解密为明文.

可以使用 openssl 执行解密

openssl rsa -in private_key.pem -out decrypted_private_key.pem 
Enter pass phrase for private_key.pem: 
writing RSA key

当提示 “Enter pass phrase for private_key.pem:” 输入前面设置的加密口令, 回车,即可将加密的证书私钥还原为明文证书私钥. 将该明文证书私钥妥善保存在本地备用

第二步, 配置 Roles Anywhere

创建trust anchor

进入控制台, 导航至 IAM 服务,在 Roles 页面, 右侧页面拉到下方,可以看到 Roles Anywhere, 点击“manage”

即可打开 roles anywhere 的管理页面

点击 “Create a trust anchor”

输入Trust Anchor 的名字, 选择刚才创建的 CA, 点击 “create a trust anchor” , 即可.

创建roles

在继续创建 Profiles 之前,我们需要先创建相应的 Roles, 这个Roles 就是后继步骤中会与证书绑定的 role.

导航至 IAM 的 Roles 页面, 点击 “Create role”, 打开role 的创建向导。

这个步骤的关键在与, trusted entity type 的选择, 如图所示,在“Use cases for other AWS services:” 下拉框输入 roles, 找到 “Roles Anywhere”, 选中该服务. 点击Next即可.其他的步骤与创建常规的 role 是一样的,这里不再赘述.

或者直接编辑该 role 的“Trusted relationships” 的 policy 文件也可以, 样例如下:

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

创建profiles

完成 role 的创建之后,可以开始创建 profiles

返回刚才 Roles Anywhere的管理页面. 选择 “Create a profile”

进入到 profile 的创建页面, 给profile 起个名字之后,点击 role 的编辑框,这里就会列出, 在trust entity 中赋予 “rolesanywhere.amazonaws.com”信任关系的 role 的名字. 灰色表示该 role 已经和某个 profile 绑定了, 黑色表示可用的 role. 选择一个可用的 role 后, 点击” Create a profile”,就能完成 profile 的创建.

Profile 安全性增强(可选,推荐)

为了增强安全性,建议在创建 profile 的时候, 在“Session policies” 里的 “Inline policy” 编辑增加访问的限制条件.

这样可以通过白名单的方式极大增强安全性. 样例如下:

至此, IAM Roles Anywhere的云端配置完成.下面开始配置客户端

下载 aws_signing_helper

亚马逊云科技的  Amazon SDK Config是在客户端常用的安全凭证配置工具.Config 除了可以提供静态的方式配置 AK/SK,还支持使用 credential_process 指定外部的

工具或者 SDK生成身份验证凭证. IAM Roles Anywhere 提供了一个开源的工具aws_signing_helper, 这个工具可以使用本地的证书, 跟IAM roles Anywhere服务交换这个证书绑定的 role 的临时安全凭证. 详细信息参见从 “IAM Roles Anywhere获取临时安全凭证”. 有兴趣的同学,还可以到 github 上研究研究这个工具的源代码 aws_signing_helper.

为aws_signing_helper添加可执行权限后,即可以配置 config 文件.

验证证书与 IAM Roles Anywhere 的配置

可以直接执行 aws_signing_helper 命令查看结果

命令样例如下

./aws_signing_helper credential-process
--certificate <Full Path>/certificate.pem
--private-key <Full Path>/decrypted_private_key.pem
--trust-anchor-arn <TA_ARN>
--profile-arn <PROFILE_ARN>
--role-arn <Role_ARN>
{
"Version":1,
"AccessKeyId":"ASIAXXXXXXXXXCF3WVC",
"SecretAccessKey":"Dux1X1NcXXXXXXXXXXXXXXXXXXagsUO",
"SessionToken":"IQoJb3JpZ2luX2VjEOf//////////xxxxxxxxxxxxxxxxxtAiBHxBYiUE2jw9dTuUSXXwk8ppi9bHeszqtJ2/VRzdnfAyqBBAjQ//////////8BEAMaDDQ4NDYyNjAyMTEyNyIMuum2SejZwa1I/Vy8KtUDQiDR9kLyWJBIX4WBZO5Ss9Robt09sgslvH2T02MdyBhPVttMrLJfI4jle3U5OA4W3LLouN5rHkV37XwxnNt7ss1nYWtnh6fYnjbGFh2z9pKPpGD5Rs6ABldl9s6REo0SjYxc94bSYL/V7BvSOCwfUGARXcIAgLQFUmUHJlKemEVUbPJOwX2W5Bp5iOiLBrpEgIyEZhlpewVoHxizLqo87HFgxKsqGA7hDRi7NbOltnSQmRoz8H7b1vWBZFgLrnpBRhKIEj5lk7acFV09flloLgjDB6M8b8MqMd/oEYLPPswPxppT6uRzlRurHlPE7iTzSRo2FLGkoOOTLV31Go2xFq+gUTti3S9a2dPCw6PMQ7yTYKZTAZ2bYPNtLuhhO2V7hg53ZN22GmC8q2Cw30vbXRidmU647EB0RSxG7cWS5uZzB6awVVxnmtloV/6+osHcnc47YBSXASVkrWWLHCAeuh2E4S3kHVJP3nLkhiCZw/1JYwyQIyqb1dXbSc6vCjRR3ppZaNdLCMrbKjsj1ZvFqVcWJqcjS1LWslDGeGSwWcstZ7CXJQCRHYczw1bSLE7vNw/eiw+Z7/mHls8WhIDJLWcH/3UjxTKSSOy9kjlAuEPQwvdwsDDJ7ZKbBjrEATf7CJMf22wTayzUfxKcH+XBcK5pwRSM7jNzw43/jLpkZpastUZAXZW7IZBor11GdDMkf1y3QLWZaD5TuHIlXaLfcjuuOQqvXwLSdC/6LpYquTbXROD2aROZdYk94ZmNrxIW1R5HQ55iB6qdOwXFLMykSaaIMeXnK7421y+ftda48ZerH6Np/GemJFMSBqpZQR6C3OKDlKYU3M9ZxdFaI8M9B3gNsShNeTEZris3BOtGogXjr2ItTprZ06zq57gn0M2tLs4=",
"Expiration":"2022-11-04T07:52:57Z"
}

返回结果的“Expiration”字段表明这个 AKSK 是一个临时的安全凭证. 没有Expiration字段,则被SDK判断为该 AKSK 是一个长期的安全凭证.

验证无误,则可以开展配置 config 文件

配置 Config, 通过credential_process获取临时凭证

在 config 对应的配置文件中, 在linux 下修改~/.aws/config, 使用aws_signing_helper 动态获取 AKSK,替代原来的静态方式

[default]
region = us-east-1 
credential_process = <Full Path>/aws_signing_helper credential-process \
      --private-key <Full Path>/decrypted_private_key.pem \
      --certificate <Full Path>/certificate.txt \
      --trust-anchor-arn arn:aws:rolesanywhere:us-east-1:484xxxxx1127:trust-anchor/71c2c6fb-78a0-4867-9006-ba8axxxx3a3d \
      --profile-arn arn:aws:rolesanywhere:us-east-1:484xxxxx1127:profile/677a13fb-ef3a-4246-9c1c-9c05xxxxa3e0 \
      --role-arn arn:aws:iam::484xxxxx1127:role/demorolesanywhere4s3 \
      --region us-east-1

验证是否能够拿到正确的 role 的权限

aws sts get-caller-identity
{
 "UserId": "AROAXBVPWHMDYFFW4Z6SU:56aeaef8561d326a67528dcd4f0334f8",
 "Account": "4846xxxxx1127",
 "Arn": "arn:aws:sts::4846xxxx1127:assumed-role/demorolesanywhere4s3/56aeaef8561d326a67528dcd4f0334f8"
}

可以看到,返回结果中的 role 的 arn, 如果跟之前的 profile 里面配置的证书绑定的 role 的 arn 一致,则表明结果准确;

友情提示: 如果您之前在测试环境下配置过 AKSK, 需要删除~/.aws/credentials 文件. 否则通过 get-caller-identity 返回的是该 AKSK 对应的用户 id.

还可以进一步通过服务调用验证权限.通过 CLI命令,通过分别访问该 role 权限范围内的资源和权限范围外的资源验证权限是否正确.

使用 aws_signing_helper 来获取动态的临时权限,可以看到, 在~/.aws/config 目录下,并不会存在 credential 文件.

证书管理建议

证书的私有密钥是保存在您的数据中心的服务器上的. 我们在使用的时候应该尽可能的增加控制措施最小化证书私钥泄露的风险, 包括但不限于

  • 使用操作系统的文件管理权限严格限制只有 owner 拥有只读权限;
  • 永远不要把证书私钥提交到代码库中. 证书私钥与源代码分开存储,以便降低意外泄露的风险. 如果条件许可,可以把证书私钥保存在加密的存储中.

第三步配置Amazon SecretsManager

打开控制台, 导航至 Amazon SecretsManager页面, 选择 “Store a new secret”

在Secret type 选择“Credential for Amazon RDS database”, 输入这个数据库实例的 Credential 信息, 选择一个Encryption key, 再选择要管理的数据库实例, 点击 Next, 进入下一个配置页面

在 Secret name中为这个安全凭证起一个名字. 名字是支持“/”的,我们的建议是名字里体现出组织架构的信息,可以用“/”做划分.优点是比较容易明确归属关系,便于Ops 管理员使用通配符简化权限分配和管理. 下文会有样例

Resource permission 的配置

这是一个可选项, 如果您希望允许其他账户的role 来访问这个账户的数据库,可以使用 resource permission 允许跨账户访问该数据库安全凭证的权限. 详细可参见“不同账户中用户对 AWS Secrets Manager 密钥的访问权限

完成配置后,点击 Next, 即可进入下一个配置页面

在这个页面里面,将完成对密钥轮转的配置.这是一个可选步骤,我们还是强烈建议开启定时轮转.在完成安全凭证的存储创建之后,再开启启配置也是可以的.

Rotation Schedule 里面可以配置轮换的周期,是按天还是按周还是按月轮换.上图中的样例给出的是每三个月的第一个周一的21点开始做轮换,时间窗口为4个小时. 关于时间窗口的设置可以参考” 配置轮换并创建轮换函数

Rotate Function : Amazon SecretsManager利用了 lambda 函数来帮助实现安全凭证的轮换.

场景A, 保护亚马逊云科技托管的数据库安全凭证

对于 亚马逊云科技的托管服务,目前已经支持的包括Amazon RDS, Amazon Redshift, Amazon DocumentDB,可以选择让系统帮助创建可用的 lambda 函数.

场景B, 保护数据中心的数据库安全凭证

如果是自建的数据库或者其他的服务的安全凭证,需要自行创建 lambda 函数用于安全凭证的轮换. 可以参考 github上的lambda 样例进行修改,避免从零开始编写. 模板参见 “AWS Secrets Manager 轮换函数模板

 IAM Roles Anywhere的 证书赋权

为了确保通过 IAM Roles Anywhere能够从本地数据中心访问 Amazon SecretsManager, 需要创建具备相应的权限的 Roles, 具体步骤可以参见 创建Role, 注意需要确保赋予该 role 访问 Amazon SecretsManager中特定Secret以及KMS中用于加密保护该Secret的CMK的解密权限. 然后创建一个新的 Profile 绑定该 role. 修改config 文件, 在命令中使用新的 profile 即可.

访问Amazon SecretsManager的IAM权限 policy 参考样例 如下:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "SecretsManagerRead",
            "Effect": "Allow",
            "Action": "secretsmanager:GetSecretValue",
            "Resource": "arn:aws:secretsmanager:<Region>:<Accountid>:secret:test/demo/*"
        },
        {
            "Sid": "KMSCMKaccess",
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": "arn:aws:kms:<region>:<Accountid>:key/<keyid>"
        }
    ]
}

在 policy中,在访问资源的 arn 里,是支持使用通配符的. “test/demo/*” 表明允许访问这个分支下的所有安全凭证.

[default]
region = us-east-1 
credential_process = <Full Path>/aws_signing_helper credential-process \
      --private-key <Full Path>/decrypted_private_key.pem \
      --certificate <Full Path>/certificate.txt \
      --trust-anchor-arn arn:aws:rolesanywhere:us-east-1:484xxxxx1127:trust-anchor/71c2c6fb-78a0-4867-9006-ba8axxxx3a3d \
      --profile-arn < 修改的profile 的 arn> \
      --role-arn < 修改的Role的 arn>  \
      --region us-east-1

在本地笔记本电脑上使用 CLI 命令测试结果

aws sts get-caller-identity
{
    "UserId": "AROAXBxxxxxxx3OYUIOJ:56aeaef8xxxxxxxx8dcd4f0334f8",
    "Account": "484xxxxxx127",
    "Arn": "arn:aws:sts::484xxxxxxx27:assumed-role/secretsManagerRole4anywhere/56aeaef85xxxxxxxxxx8dcd4f0334f8"
}
aws secretsmanager get-secret-value --secret-id test/demo/mysqldemo

{
    "ARN": "arn:aws:secretsmanager:us-east-1:484xxxxxx127:secret:test/demo/mysqldemo-CvVcJA",
    "Name": "test/demo/mysqldemo",
    "VersionId": "dcf1d620-10bb-468b-af59-3d728c7ed0e0",
    "SecretString": "{\"username\":\"admin\",\"password\":\"xxxxxxxxxx\",\"engine\":\"mysql\",\"host\":\"demomysql.cmxxxxxxxxq6k.us-east-1.rds.amazonaws.com\",\"port\":3306,\"dbInstanceIdentifier\":\"demomysql\"}",
    "VersionStages": [
        "AWSCURRENT"
    ],
    "CreatedDate": "2022-11-15T15:18:21.480000+08:00"
}

测试成功获取数据库的安全访问凭证

在本篇博客中, 我们讨论了如何利用新发布的 IAM Roles Anywhere 服务帮助在亚马逊云科技公有云之外工作负载上安全而方便的获取 Amazon SecretsManager 上保护的安全凭证, 并进而获取访问关键资源的权限. 当你将 IAM roles的能力扩展到您的自建服务器/容器或者其他运行在Amazon 公有云之外的应用上的时候,您可以废除对 AK/SK 这种长期安全凭证的需求, 这样意味着不再需要担忧分发,保存和轮换带来的开销. 当然,除了通过 IAM Roles Anywhere 获取临时安全凭证访问 Amazon SecretsManager, 我们还可以通过修改 Profiles绑定的 Roles 的权限,获取对亚马逊云科技的其他服务资源的访问权限.

本篇作者

陈昇波

亚马逊云科技解决方案架构师,负责基于亚马逊云科技的云计算方案架构的咨询和设计,同时致力于亚马逊云科技云服务在国内的应用和推广。现致力于网络安全和大数据分析相关领域的研究。在加入亚马逊云科技之前,在爱立信东北亚区担任产品经理,负责产品规划和方案架构设计和实施,在用户体验管理以及大数据变现等服务方面有丰富经验。