亚马逊AWS官方博客

在单 EC2 实例运行多应用时,如何通过 IAM Role 精细化管理授权

当在 Amazon EC2 实例上同时运行多个应用程序时,合理的 IAM 权限控制对于保证安全非常重要。本文将介绍如何为 EC2 实例上的每个应用程序配置独立的 IAM 角色,实现精细化的访问控制。

背景

很多客户会在同一个 EC2 实例上运行多个不同的应用程序,例如 Web 应用、后台处理应用等。这些应用程序通常需要访问 AWS 资源如 S3、DynamoDB 等。如果所有的应用程序都采用不同的 AKSK 的方式来获取权限,则存在安全隐患。 本文将描述如何采用 IAM Role 而非 IAM User 来为同一台 EC2 上的多个应用赋权,从而通过避免使用长期 AKSK 来将降低 AKSK 泄漏的可能性,并且您也不需要再考虑手动轮转 AKSK 了。

解决方案

为实现该目标,我们可以通过以下步骤为每个应用程序配置独立的 IAM 角色:

  1. 为每个应用创建 IAM 角色,并根据应用程序的功能为角色赋予最小的权限,此处假设有两个应用一个 WEB 应用和一个后台服务应用。Web 应用需要 S3 的访问权限,后台服务应用需要 DynamoDB 的访问权限。
  2. 为 EC2 实例本身创建一个默认角色,该角色信任上面创建的应用角色,即允许代入这些角色。
  3. 在 EC2 实例的~/.aws/config 文件中,为每个应用程序角色添加 profile 配置。该 profile 包含角色的 ARN 信息,以及使用 EC2 instance metadata 作为 credential source 的配置。
  4. 应用程序通过指定 profile 名称使用角色,无需任何密钥,SDK 会自动代入角色并获取临时证书。

详细步骤说明

  1. 创建 EC2 Instance 的 role,例如 DefaultInstanceRole,绑定到 EC2 实例。
    aws ec2 associate-iam-instance-profile --instance-id YourInstanceId --iam-instance-profile Name=YourNewRole-Instance-Profile
  2. 创建两个 Application Role ,例如 WebRole,只给予 S3 的相关 policy 权限;BackendRole,只给予 DynamoDB 的相关 policy 权限。可以通过控制台创建。创建完成后增加如下类似的 Trust Policy。确保 DefaultInstanceRole 可以代入 WebRole,BackendRole。
    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Sid": "Statement1",
                "Effect": "Allow",
                "Principal": {
                    "AWS": "arn:aws:iam::<Account ID>:role/DefaultInstanceRole"
                },
                "Action": "sts:AssumeRole"
            }
        ]
    }
    
  3. 更改 EC2 实例中的~/.aws/config 文件,增加两个 Application Role 的 profile。这种设置方式,在应用中,AWS SDK 会通过绑定在 EC2 中的 Instance role DefaultInstanceRole 代入新的 Application Role。
    [profile WebRole]
    role_arn = arn:aws:iam::<Account ID>:role/webrole
    credential_source = Ec2InstanceMetadata
    
    [profile BackendRole]
    role_arn = arn:aws:iam::<Account ID>:role/backendrole
    credential_source = Ec2InstanceMetadata
    
  4. 应用程序中在引用 AWS Credential 时,采用类似如下方式,在不同的 application 中通过 profile name 引用。如下示例采用 python boto3 代码演示,在 C++Golang 等语言中也有类似方法支持。下面代码中采用 Session 创建 Session 对象,Session 对象会自动轮转临时 token 供应用使用。
    import boto3
    import time
    
    session = boto3.Session(profile_name='WebRole')
    s3 = session.client('s3')
    
    
    sts = session.client('sts')
    print("caller:",sts.get_caller_identity())
    
    
    while True :
        response = s3.list_objects_v2(Bucket='<BucketName>',Prefix="test1/")
        # print time with formate yyyy-mm-dd hh:mm:ss
        print("------------",time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()),"--------------")
        for object in response['Contents']:
            print(object['Key'])
        time.sleep(10)
    
  5. 如果我们采用 Auto Scaling Group 管理 EC2 实例,可以方便地在启动模版的高级设置中更改 User Data,增加如下代码,在每台启动的 EC2 实例自动添加 AWS config 文件配置。
    # 安装最新版aws cli
    curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"
    unzip awscliv2.zip
    sudo ./aws/install
    # 创建.aws目录
    
    mkdir ~/.aws
    # 生成config文件内容 
    cat > ~/.aws/config <<EOF 
    [default]
    region=<AWS Region>
    output=json
    [profile WebRole]
    role_arn = arn:aws:iam::<Account ID>:role/webrole
    credential_source = Ec2InstanceMetadata
    
    [profile BackendRole]
    role_arn = arn:aws:iam::<Account ID>:role/backendrole
    credential_source = Ec2InstanceMetadata
    
    EOF
    # 添加读写权限
    chmod 600 ~/.aws/config
    ```
    

实现机制说明

IMDSv2

从上面的步骤中,大家注意到,在~/.aws/config 文件的 profile 配置有一行配置。

credential_source = Ec2InstanceMetadata

AWS IMDS(Instance Metadata Service)是 AWS 提供的一个便利的服务,它允许运行在 AWS EC2 实例上的程序获取有关该实例的信息。这里便是通过 IMDS 获取 EC2 Instance role 的权限,再通过 EC2 Instance Role 来代入对应的 Application Role 的权限。2019 年 11 月,我们发布了 AWS IMDSv2,在 IMDSv2 中,所有的请求现在都由会话认证来保护,将 EC2 IMDS 服务进行增强,以实现对开放防火墙、反向代理和 SSRF 漏洞的深度防御。建议在生产的 EC2 实例开启 IMDSv2 Only 模式,开启方式参见这里

临时 token 失效需要手动刷新吗?

本文采用的是 python 的 AWS SDK boto3 来实现 session 的管理,“当您指定拥有 IAM 角色配置的配置文件时,Boto3 会进行 AssumeRole 调用来检索临时授权凭证。之后 Boto3 的 API 调用会使用缓存的临时凭证,直到这些凭证过期。如果临时凭证过期的话,Boto3 会自动刷新凭证。请注意,Boto3 不会将这些临时凭证写入磁盘,这意味着来自 AssumeRole 调用的临时凭证只会缓存在单个 session 的内存中。从该 session 创建的所有客户端将共享相同的临时凭证。详细说明参见 boto3 的官方说明

总结

通过上述方法,我们可以为 EC2 实例上的每个应用程序配置独立的 IAM 角色,并控制每个应用程序访问 AWS 资源的权限。这遵循了最小权限原则,有助于增强安全性,是在 EC2 上运行多应用的最佳实践。相比一套密钥共享,该方案可以大大降低权限过大的风险。

参考链接

本篇作者

李岩

AWS 解决方案架构师,负责基于 AWS 云计算方案的架构咨询和落地实施;有电信,金融行业经验。加入 AWS 前曾在华为软件任职项目经理,技术架构师,在 cryptocurrency 领域创业公司担任技术管理者。喜欢钻研跨领域技术创新。