介绍
要对S3的访问权限做控制,既可以使用基于身份的策略(IAM用户策略),也可以使用基于资源的策略(ACL和存储桶策略)。
访问一个存储桶的权限控制流程如图所示:
访问存储桶中的对象的权限控制流程如图所示:
当 Amazon S3 收到对象操作请求时,它会将基于资源的所有相关权限(对象访问控制列表 (ACL)、存储桶策略、存储桶 ACL)和IAM用户策略转换为将在运行时进行评估的策略集。然后它会通过一系列步骤评估生成的策略集。在每个步骤中,它会在三个特定上下文 (用户上下文、存储桶上下文和对象上下文) 中评估一个策略子集。
简单来说就是先判断用户权限,然后判断存储桶权限,最后判断对象权限。
目前我们都是通过同一个AWS账户下的多个IAM用户去访问S3的,因此可以只使用IAM用户策略去做访问权限控制,这也基本能满足绝大部分常规的权限控制需求,如果无法满足的情况再考虑使用存储桶处理和ACL。
实战演练
准备工作
使用AWS根账号(我的账户名是Harp)登录AWS管理控制台,选择IAM服务进入,创建一个名为Administrators的组,并向其附加AdministratorAccess权限;
创建一个IAM用户(Harp-Admin),并将其添加到Administrators组;
下载Authy软件,手机版或PC版均可,并安装,用于为用户添加MFA验证;
在IAM控制台中点击用户,点击Harp-Admin,点击安全凭证;
已分配 MFA 设备目前显示未分配,点击管理,添加虚拟 MFA 设备,继续;
此时弹出如下的对话框,如果使用的Authy是手机版本的,那么点击显示QR码并扫描,如果是PC版则点击显示私有密钥,并在PC版的Authy中输入该密钥;
之后将Authy中连续两个30s的MFA CODE输入以下文本框中,并点击分配MFA;
此时Harp-Admin已经开启了MFA验证,使用该用户登录控制台时,需要在验证密码之后,再验证MFA(即输入Authy中的实时CODE);
在IAM控制台中点击账户设置,将密码策略修改如下,可根据需要调整;
创建测试用户和存储桶
根据AWS最佳实践,本步骤的操作都是使用Harp-Admin来处理的;
依次创建以下4个用户,暂不赋予任何权限;
如下图,创建Bucket一列对应的存储桶,Object不为*的需要创建对应的文件夹,权限一列是我们要实现的访问控制权限;
配置IAM用户策略
s3_common_policy
在IAM控制台中点击策略,创建策略,JSON,输入如下json,命名为s3_common_policy;
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListAllMyBuckets",
"s3:GetBucketLocation"
],
"Resource": "arn:aws:s3:::*"
},
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::derek-public*"
]
},
{
"Sid": "AllowRootLevelListingOfTheBucket",
"Action": [
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::derek-bucket3"
],
"Condition": {
"StringEquals": {
"s3:prefix": [
""
],
"s3:delimiter": [
"/"
]
}
}
},
{
"Sid": "AllowListBucketOfASpecificUserPrefix",
"Action": [
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::derek-bucket3"
],
"Condition": {
"StringLike": {
"s3:prefix": [
"public/*"
]
}
}
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::derek-public1/*",
"arn:aws:s3:::derek-bucket3/public/*"
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::derek-public2/*"
}
]
}
解释一下各条statements:
statement1: 对所有的S3资源赋予s3:ListAllMyBuckets和s3:GetBucketLocation,这两个权限是给控制台使用的,通过控制台访问S3时,需要这两个权限来正常列出所有存储桶,如果通过CLI访问则不需要;
statement2: 赋予所有derek-public开头的存储桶列出存储桶对象的权限(s3:ListBucket);
statement3: 允许列出derek-bucket3第一层路径下的对象,这个写法可以在S3的官方文档中找到;
statement4: 允许列出derek-bucket3/public下的所有对象;
statement5: 允许对derek-public1和derek-bucket3/public中的对象读写、复制操作;
statement6: 允许对derek-public2中的对象读取操作;
创建一个用户组s3_common_group,并将所有用户添加到其中,将s3_common_policy附加到这个组;
此时id为1/4/8的权限已经实现,4个用户可以正常读取derek-public1、derek-public2和derek-bucket3/public,其中derek-public2只有可读权限,如果用户尝试写入,例如创建一个文件夹,会显示“无法使用名称XXX创建文件夹”;
如果用户尝试进入无权限的bucket或者文件夹,例如derek-bucket1或derek-bucket3/user1,会显示“Access Denied”;
user1_policy
在IAM控制台中点击策略,创建策略,JSON,输入如下json,命名为user1_policy;
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::derek-bucket1",
"arn:aws:s3:::derek-bucket2"
]
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::derek-bucket1/*",
"arn:aws:s3:::derek-bucket3/user1/*"
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::derek-bucket2"
},
{
"Sid": "AllowListBucketOfASpecificUserPrefix",
"Action": [
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::derek-bucket3"
],
"Condition": {
"StringLike": {
"s3:prefix": [
"user1/*"
]
}
}
}
]
}
解释一下各条statements:
statement1: 允许列出derek-bucket1和derek-bucket2中的所有对象;
statement2: 允许对derek-bucket1和derek-bucket3/user1中的对象读写、复制操作;
statement3: 允许对derek-bucket2中的对象读取操作;
statement4: 允许列出derek-bucket3/user1下的所有对象;
因为该策略只有user1使用,我们可以不创建组,直接将其附加到user1上;
点击用户,user1,添加权限,直接附加现有策略,选择user1_policy,审核,添加权限;
此时id为3/4/6中涉及user1的权限已经配置完成;
user2_policy
在IAM控制台中点击策略,创建策略,JSON,输入如下json,命名为user2_policy;
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::derek-bucket2"
]
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::derek-bucket2/*",
"arn:aws:s3:::derek-bucket3/user2/*"
]
},
{
"Sid": "AllowListBucketOfASpecificUserPrefix",
"Action": [
"s3:ListBucket"
],
"Effect": "Allow",
"Resource": [
"arn:aws:s3:::derek-bucket3"
],
"Condition": {
"StringLike": {
"s3:prefix": [
"user2/*"
]
}
}
}
]
}
解释一下各条statements:
statement1: 允许列出derek-bucket2中的所有对象;
statement2: 允许对derek-bucket2和derek-bucket3/user2中的对象读写、复制操作;
statement3: 允许列出derek-bucket3/user2下的所有对象;
将该策略附加给user2,此时id为4/7中涉及user2的权限已经配置完成;
user3_policy
在IAM控制台中点击策略,创建策略,JSON,输入如下json,命名为user3_policy;
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::derek-bucket3"
]
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": "arn:aws:s3:::derek-bucket3"
}
]
}
将该策略附加给user3,此时id为5的权限已经配置完成;
user4_policy
根据之前的步骤,使用Harp-Admin为user4创建虚拟MFA;
在IAM控制台中点击策略,创建策略,JSON,输入如下json,命名为user4_policy;
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"s3:ListBucket"
],
"Resource": [
"arn:aws:s3:::derek-bucket4"
]
},
{
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:GetObjectAcl",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::derek-bucket4/*"
]
},
{
"Effect": "Deny",
"Action": [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObjectAcl",
"s3:DeleteObject"
],
"Resource": [
"arn:aws:s3:::derek-bucket4/mfa/*"
],
"Condition": {
"BoolIfExists": {
"aws:MultiFactorAuthPresent": false
}
}
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::derek-bucket4/mfa/*"
]
}
]
}
解释一下各条statements:
statement1: 允许列出derek-bucket4中的所有对象;
statement2: 允许对derek-bucket4中的对象读写、复制操作;
statement3: 未通过MFA验证时禁止写derek-bucket4/mfa下的所有对象;
statement4: 允许读取derek-bucket4/mfa下的所有对象;
其中涉及MFA验证的权限控制可以参考带MFA条件的示例策略;
将该策略附加给user4,此时id为9的权限已经配置完成;
如果user4通过控制台登录,必须要使用MFA验证,登录之后符合statement3的条件,因此可以在mfa文件夹下写入内容;
如果user4通过CLI直接向mfa写入,则会被拒绝,如图:
此时需要加上MFA验证,输入下图中的命令,两个红框依次替换成user4的MFA ARN和MFA当前的6位token,会返回一个json格式的临时凭证,该凭证默认有效期12h,更多关于CLI和MFA的内容可参考 如何使用 MFA 令牌对通过 AWS CLI 进行的 AWS 资源访问执行身份验证?:
修改AWS CLI的配置文件credentials,如下图红框,添加一个mfa-user,将上一步的结果复制到这里;
利用mfa-user复制文件到mfa文件夹,提示复制成功;
一些坑
在使用user1时,在derek-bucket1中建立文件夹没有问题,但是上传文件却失败,提示OptionsRequestDenied,经谷歌查询猜测可能和浏览器的AdBlock相关插件有关,于是换火狐浏览器、或者使用CLI上传,都没有问题。