对象存储权限管理概述
对象存储(s3)是当下最热门的非结构化分布式存储,满足了众多复杂业务场景的需求。权限管理是这些复杂业务最基本的管理能力。对象存储目前最主要的权限管理能力有ACL和policy。
ACL即访问控制列表,通过多组描述用户具备的权限记录关联到具体资源。每条记录是绑定了被授权对象与权限关系。被授权的对象除了规范的用户标识外还可以是emailAddress、预定用户组;可选的权限有'READ','WRITE'','FULL_CONTROL','READ_ACP','WRITE_ACP'。ACL语义简洁,容易上手,适合不复杂的业务场景使用。
policy是一套基于json描述的访问策略。主要可分为基于资源的访问策略(bucket policy)和基于身份的访问策略(user policy)。bucket policy适用于跨账号间授权使用,user policy适用于子账号授权使用。policy语义极其丰富,支持资源等各维度的模糊匹配,能几乎满足所有业务场景使用。本文将以对象存储(融合版)产品的policy实现来阐述。
policy语法和结构
无论bucket policy还是user policy,语法结构是一样的。policy基本元素如下:
policy语法:
policy = {
<version_block>,
<statement_block>
}
<version_block> = "Version" : ("2012-10-17")
<statement_block> = "Statement" : [ <statement>, <statement>, ... ]
<statement> = {
<effect_block>,
<action_block>,
<resource_block>,
<condition_block?>
}
<effect_block> = "Effect" : ("Allow" | "Deny")
<action_block> = "Action" :
("*" | [<action_string>, <action_string>, ...])
<resource_block> = "Resource" :
("*" | [<resource_string>, <resource_string>, ...])
<condition_block> = "Condition" : <condition_map>
<condition_map> = {
<condition_type_string> : {
<condition_key_string> : <condition_value_list>,
<condition_key_string> : <condition_value_list>,
...
},
<condition_type_string> : {
<condition_key_string> : <condition_value_list>,
<condition_key_string> : <condition_value_list>,
...
}, ...
}
<condition_value_list> = [<condition_value>, <condition_value>, ...]
<condition_value> = ("String" | "Number" | "Boolean" | "Date and time" | "IP address")
- Effect
Effect元素用来指定授权的效果是允许还是拒绝,是必选元素。取值:Allow和Deny。其中Deny的效果优先级高
- Action
Action元素用于描述允许或拒绝的特定操作,是必选元素。取值:对象存储服务所定义的API操作名称
- Resource
Resource元素用于描述被授权的一个或多个对象,适用于基于身份的策略,是必选元素。Resource元素的取值:对象存储资源ARN
- Condition
Condition元素用于指定授权生效的限制条件,是可选元素。Condition元素也称为条件块(Condition Block),它是由一个或多个条件子句构成。一个条件子句由条件操作类型、条件关键字和条件值组成
- Principal
Principal元素用于指定允许或拒绝访问资源的主体,仅适用于基于资源的策略。
policy判定流程
上图为每条policy进行权限判定的流程:
- Deny效用优先,首先检查请求是否命中Deny语句
- 是:判定结束,返回判定结果为Explicit Deny
- 依次轮流检查是否命中Allow语句
- 是:判定结束,返回结果为Allow。
- 否:判定结束,返回判定结果为Implicit Deny
常见场景下授权实践
实现文件夹中对象的公共读
场景描述:用户userA需要把桶bucket1中文件夹filefolder下所有的对象变成公共读。
实现:
{
"Version" : "2012-10-17",
"Statement": [
{
"Sid": "policy1686712182",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::bucket1/filefolder/*"
]
}
]
}
其中‘Principal’字段用了"*"表示所有的用户即公共;‘Action’字段指定了具体接口“s3:GetObject”表示针对读取对象的接口,这两个合起来即公共读;‘Resource’字段指定了资源范围以及“*”模糊匹配,限制了此条policy作用在文件夹filefolder下所有对象。
不同访问用户间读写分离
场景描述:用户userA有一个桶bucket1,需要让用户userB往这个桶写数据,再给用户userC来读取。
实现:
{
"Version" : "2012-10-17",
"Statement": [
{
"Sid": "policy1686712183",
"Effect": "Allow",
"Principal": {
"AWS": ["arn:aws:iam:::user/userC"]
},
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::bucket1/*"
]
},
{
"Sid": "policy1686712184",
"Effect": "Allow",
"Principal": {
"AWS": ["arn:aws:iam:::user/userB"]
},
"Action": [
"s3:PutObject"
],
"Resource": [
"arn:aws:s3:::bucket1/*"
]
}
]
}
其中此条policy的'Statement'字段有两个"Allow"效果的元素,这两条只要其中一条匹配上就能生效。'Principal'字段用于指定可以访问的用户。
根据访问来源IP设置黑白名单
场景描述:现有两个局域网络A(192.168.0.1/24)、网络B(192.168.1.1/24),出于安全考虑,需要让网络A所有节点可以访问bucket1,网络B所有节点不能访问bucket1。
实现:
{
"Version" : "2012-10-17",
"Statement": [
{
"Sid": "policy1686712185",
"Effect": "Allow",
"Principal": {
"AWS": "*"
},
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::bucket1/*"
],
"Condition":{
"IpAddress":{
"aws:SourceIp":"192.168.0.1/24"
}
}
},
{
"Sid": "policy1686712186",
"Effect": "Deny",
"Principal": {
"AWS": "*"
},
"Action": [
"s3:GetObject"
],
"Resource": [
"arn:aws:s3:::bucket1/*"
],
"Condition":{
"IpAddress":{
"aws:SourceIp":"192.168.1.1/24"
}
}
}
]
}