亚马逊AWS官方博客

通过 STS Session Tags 来对 AWS 资源进行更灵活的权限控制

前言

S3是非常受欢迎的云对象存储,很多客户使用S3来存储他们的用户文件。终端用户可以直接通过HTTP的方式上传和管理在S3中的文件,而不需要经过服务器中转。那么如何限制S3对象的访问权限,让终端用户只有管理自己拥有的文件的权限,则成了很多客户关心的问题。熟悉AWS的朋友可能知道,IAM的Policy是用来管理AWS访问权限的,那么如何让Policy更灵活、更动态,可以让获取到的权限凭证可以匹配到单个终端用户的S3文件目录下,是我们今天要讨论的主题。

STS 介绍

您可以用编程方式调用 AWS Security Token Service (AWS STS) 的API,获取访问AWS资源的临时安全凭证,并将这些凭证下发给终端用户,用于后续终端用户发起访问AWS资源请求时进行身份验证。

在调用STS API的过程中,STS支持在请求会话(session)中传入的一个或多个tag参数,tag为Key Value的键值对,在IAM Policy中使用变量名${aws:PrincipalTag/Key},便可在IAM Policy中获取到Value值。通过在STS session中动态地传入变量值,便可以灵活地为不同的S3对象分配权限。

临时安全凭证与长期有效的安全凭证的区别

熟悉AWS的朋友应该知道,在AWS IAM中创建User后,会分配一对access key ID和secret access key(以下简称AK/SK),在AWS CLI和SDK中都需要配置AK/SK,当以编程方式调用API时,会使用AK/SK对请求执行身份验证,这对AK/SK长期有效。

而临时安全凭证,包含AK/SK和Session Token,AK/SK用于标识用户身份,Session Token用于验证凭证的有效性,AK/SK不随User一起存储,而是动态生成,且使用期限有限,可将这些凭证的有效时间配置几分钟到几小时。

这些差异使得可利用临时凭证获得以下优势:

  • 您不必随应用程序分配或嵌入长期 AWS 安全凭证,降低安全凭证泄露的风险。
  • 可允许用户访问您的 AWS 资源,而不必为这些用户定义 AWS 身份。临时凭证是角色和联合身份验证的基础。
  • 临时安全凭证的使用期限有限,因此,在不需要这些凭证时不必轮换或显式撤销这些凭证。临时安全凭证到期后无法重复使用。

请求流程

通过STS获取临时安全凭证流程如下图。

 

 

  1. 终端用户的客户端发出访问请求到服务器端。
  2. 服务器端调用STS API,以获取临时安全凭证。
  3. STS服务返回临时安全凭证。
  4. Server将获取到的临时安全凭证下发给客户端。
  5. 客户端使用临时安全凭证来访问AWS资源,本文中是S3桶。

下面来看下具体如何实现。本文为了方便展示,使用AWS CLI方式来演示整个权限配置和获取的过程,在真实场景中建议在应用中使用AWS SDK代码来实现以上流程。

在AWS云上的配置

在AWS云上创建一个IAM User,名为ServerUser,将其AK/SK配置在服务器端,其至少拥有调用STS AssumeRole操作的权限,如下策略所示。

{
    "Version": "2012-10-17",
    "Statement": [
        {
        "Sid": "VisualEditor0",
        "Effect": "Allow",
        "Action": "sts:AssumeRole",
        "Resource": "*"
        }
    ]
}

 

创建一个AssumedRole,其所具有的Policy如下。该Policy中BUCKET和PREFIX根据实际情况填写,用${aws:PrincipalTag/userid}来引用STS Session传入的Tag的key,作为变量,来获取到value值,以匹配上实际的目录。文中使用的key是userid,此Policy限定了每个user只能获取其userid目录下的文件列表,和读写和删除的权限。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "ListYourObjects",
            "Effect": "Allow",
            "Action": "s3:ListBucket",
            "Resource": [
                "arn:aws:s3:::BUCKET"
            ],
            "Condition": {
                "StringLike": {
                    "s3:prefix": [
                        "PREFIX/${aws:PrincipalTag/userid}/"
                    ]
                }
            }
        },
        {
            "Sid": "ReadWriteDeleteYourObjects",
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::BUCKET/PREFIX/${aws:PrincipalTag/userid}/",
                "arn:aws:s3:::BUCKET/PREFIX/${aws:PrincipalTag/userid}/*",
            ]
        }
    ]
}

修改此AssumedRole的信任关系,如下所示。通过控制台创建的Role的信任关系里的Principal是AWS的服务,在这里需要修改为上一步创建的IAM User,为ServerUser,以信任SeverUser来使用此Role来获取临时凭证。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::account-id:user/ServerUser"
            },
            "Action": [
                "sts:AssumeRole",
                "sts:TagSession"
            ]
        }
    ]
}

 

演示

在服务器端,配置AWS CLI,使用ServerUser的AK/SK对。使用CLI,调用assume-role命令,传入tag,key为userid,value为123456,表明为userid为123456的用户生成临时安全凭证。

aws sts assume-role --role-arn arn:aws:iam::account-id:role/AssumedRole --role-session-name my-session --tags Key=userid,Value=123456 —duration-seconds 1800
{
"AssumedRoleUser": {
"AssumedRoleId": "AROA23ZIK3DO7XQDDB4I4:my-session",
"Arn": "arn:aws:sts::account-id:assumed-role/AssumedRole/my-session"
},
"Credentials": {
"SecretAccessKey": "xxxxxxxxxxxxxx",
"SessionToken": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"Expiration": "2020-04-10T07:34:12Z",
"AccessKeyId": "xxxxxxxxxxx"
},
"PackedPolicySize": 3
}

在客户端,使用上一步在服务器端获得的userid为123456的临时安全凭证,这里使用CLI export到环境中。

export AWS_ACCESS_KEY_ID=xxxxxxxxxxx
export AWS_SECRET_ACCESS_KEY=xxxxxxxxxxxxxx
export AWS_SESSION_TOKEN=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

使用CLI上传一个文件到userid为123456的S3目录下,能够成功。

aws s3 cp ./myfile s3://BUCKET/PREFIX/123456/

查看此文件家里的目录,可以看到能够返回文件列表。

aws s3 ls s3://BUCKET/PREFIX/123456/
2020-03-25 08:02:37 0 myfile

尝试查看userid为234567的目录,会返回如下错误。

aws s3 ls s3://xucy-static/app/234567/
An error occurred (AccessDenied) when calling the ListObjectsV2 operation: Access Denied

读者可以自行验证读写、删除等操作的权限,本文不再赘述。

 

小结

在本文中,我们通过STS服务传递session tags实现了终端用户只能管理自己的文件的场景。不难发现,sesstion tags在AWS的权限管理更具灵活性,可基于这些tags来允许或拒绝资源的访问,可将使用场景拓展到别的AWS服务中。

 

参考资料

https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_credentials_temp_request.html

https://docs.aws.amazon.com/zh_cn/IAM/latest/UserGuide/id_session-tags.html

 

本篇作者

许昌月

AWS解决方案架构师,负责基于AWS的云计算方案架构咨询和设计,实施和推广,擅长软件开发,具有丰富的解决客户实际问题的经验。