S3进阶系列(二) ——权限管理
什么是S3的权限管理
S3的权限管理是任何使用S3的人都无法绕开的功能,决定了S3中的Object是否能够被访问。
权限管理本质上解决了这么一个问题: 谁(Principal)能够在何种条件(condition)下被允许或拒绝(Effect)对哪些资源(Resource)做何种操作(Action)
S3权限管理概述
S3权限管理,需要了解什么是S3的策略(Policy),有哪些策略,有多个策略时S3是如何进行评估的,以及如何选取合适的策略。
策略(Policies)
- 默认所有S3的资源都是私有的
- 只有资源的拥有者(创建资源的账号)能访问资源
- 拥有者可以通过policy来赋予其他人来访问资源
- 策略(policy)分为两类
- 直接应用于某个资源(一个Object或者一个Bucket)的策略称为资源策略(Resources Policies)
- 直接应用于某个IAM用户的被称为用户策略(User Resources)
- Resources Based Polices
- 总共有两类的资源策略
- 访问控制列表(Access Control Lists)
- 可以赋予简单的对object和bucket的读写权限给AWS账号和预定义组
- 使用XML schema
- 由一个权限条目的列表组成
- 桶策略(Bucket Policies)
- 用来赋予AWS账号或者IAM用户访问Bucket和object的权限
- 使用JSON
- 可以进行精细化控制
- 大多数情况下,可以用来替换ACL
- 访问控制列表(Access Control Lists)
- 总共有两类的资源策略
- 用户策略(User Policies)
- 使用AWS IAM添加到用户(users), 组(groups)或者角色(roles)
- 可以进行精细化控制
- 使用JSON
- 因为是直接赋给IAM users/groups/role的,因此不支持给予匿名访问的权限
- 不能被赋予root account
- 跨账户访问(Cross Account Access)
- 跨账户访问是一个账户授权另一个账户访问它的资源
- 比如Account A可以通过Bucket Policy授权Account B访问权限
- Account A通过Bucket Policy授权了Account B可以访问某个Bucket
- Account B通过User Policy授权Account B的某个IAM User访问权限
- Account B中的IAM user就可以访问Account A中Bucket的资源了
- 比如Account A可以通过Bucket Policy授权Account B访问权限
- 跨账户访问是一个账户授权另一个账户访问它的资源
S3怎么评估polices
- 整体规则:
- 当有显式拒绝时,会被判定为拒绝访问
- 没有显式拒绝,有显示允许时,会被判定为允许访问。
- 没有显式拒绝也没有显示允许时,就适用默认拒绝规则,会被判定为拒绝访问。
- 原理和例子可以参照这两篇文章 深挖AWS S3的权限管理 和 深挖AWS S3的权限管理(实验篇)
怎么选取使用哪个策略
- 一般情况下,优先使用User Policy和Bucket Policy,而不是ACL,因为它们能提供细粒度的控制。
- 如下情况下,需要使用ACL
- 需要控制不是Bucket拥有者的object的权限
- 需要控制大量零碎的,不同prefix的object的权限
- 赋予“S3 Log Delivery Group”权限到Bucket时
- 如下情况时,需要使用Bucket Policy
- 无法使用ACL授权跨账户访问时
S3的访问控制列表(ACL)
- 什么是ACL
- ACL是基于XML的,可用于bucket和object
- 每一个bucket和object都有一条ACL作为它的sub-resource来定义访问权限
- 默认的ACL是给object的拥有者完全的访问权限
- ACL 特性
- 只能被用来给AWS account和预定义的groups来赋予权限,不能管理IAM user的权限
- 只能赋予基本的读写权限
- 不能基于条件来控制读写权限
- 不能赋予显式拒绝的权限
- ACL 可以拥有最多 100 个授权
ACL 例子解析
1234567891011121314151617<?xml version="1.0" encoding="UTF-8"?><AccessControlPolicy xmlns="http://s3.amazonaws.com/doc/2006-03-01/"><Owner><ID>*** Owner-Canonical-User-ID ***</ID><DisplayName>owner-display-name</DisplayName></Owner><AccessControlList><Grant><Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:type="Canonical User"><ID>*** Owner-Canonical-User-ID ***</ID><DisplayName>display-name</DisplayName></Grantee><Permission>FULL_CONTROL</Permission></Grant></AccessControlList></AccessControlPolicy>注意Owner.ID一栏中,是拥有这个object的aws account的规范用户ID(canonical ID),而不是12位的account ID, 关于如何查找规范用户ID,可以参阅查找账户的规范用户ID
Grant的实体,分为好几类,可以是AWS account,也可以是S3预定义的组。
当为AWS account时,则Grantee中xsi:type为CanonicalUser,Grant中以ID, DisplayName字段展示
1234567<Grant><Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="CanonicalUser"><ID>user2-canonical-user-ID</ID><DisplayName>display-name</DisplayName></Grantee><Permission>READ</Permission></Grant>当为预定义组时,则Grantee中xsi:type为Group,Grant中以group的URI字段来展示。
123456<Grant><Grantee xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="Group"><URI>http://acs.amazonaws.com/groups/s3/LogDelivery</URI></Grantee><Permission>WRITE</Permission></Grant>
ACL 权限
- ACL只能几个设定好的权限集,针对Object和Bucket的ACL权限集相同。
- ACL只能几个设定好的权限集,针对Object和Bucket的ACL权限集相同。
ACL 预定义组(ACL Predefined Groups)
- ACL能授权给预定义组
- 授权预定义组时,在Grant中,使用Group URI,而不是Canonical ID
- 几个预定义组
- 经身份验证的用户组(Authenticated Users)
- 表明可以允许任何AWS账号访问资源
- Group URI=http://acs.amazonaws.com/groups/global/AuthenticatedUsers
- 所有的用户组(All Users)
- 表明可以允许世界上任何人进行访问,也就是Public
- Group URI=http://acs.amazonaws.com/groups/global/AllUsers
- 日志传输组(Log Delivery Group)
- 允许将S3访问日志写入Bucket中,用于S3 Bucket logging功能
- Group URI=http://acs.amazonaws.com/groups/s3/LogDelivery
- 经身份验证的用户组(Authenticated Users)
- ACL能授权给预定义组
-
- AWS定义了一系列预定义的ACL授权,称为标准ACL(Canned ACL)
- 设置时只能使用其中的一个canned ACL
- 最常用于AWS CLI, 如下命令拷贝xxx.jpg到S3中,并且设置为public可读
aws s3 cp xxx.jpg s3://bucket_name/public/ --acl public-read
- AWS定义了一系列预定义的ACL授权,称为标准ACL(Canned ACL)
Bucket & User Policies
- 什么是Bucket和User Policies
- Bucket和User Polices都是策略,以JSON格式定义,用来规定bucket和object的访问权限
- Bucket policies是attached在Bucket上的, 在S3中设置
- User Policies是基于用户的,在IAM中设置
- Bucket或者IAM默认都是没有任何策略的
- Bucket和User Polices都是策略,以JSON格式定义,用来规定bucket和object的访问权限
- Bucket & User Policy特性
- 都可以规定IAM User的访问权限。Bucket Policy还可以规定AWS root account的访问权限,而IAM Policy因为没法attach到root account,因此无法规定root account的权限
- 可以定义非常精细的访问权限
- 可以使用显式拒绝
- 可以设置带条件的访问权限
- JSON格式
- 大小限制在20KB
- Policy的必备要素
- 一个Policy包含如下几个元素
- Principal服务委托人 - 被允许对某个资源进行某种操作的主体,只在Bucket Policy中使用。分为以下几种:
- 特定AWS账户:
"Principal": { "AWS": "arn:aws:iam::AWS-account-ID:root" }
- IAM用户:
"Principal": { "AWS": "arn:aws:iam::AWS-account-ID:user/user-name" }
- 联合身份用户(federated identity) - web identity federation
"Principal": { "Federated": "cognito-identity.amazonaws.com" }
"Principal": { "Federated": "www.amazon.com" }
"Principal": { "Federated": "graph.facebook.com" }
"Principal": { "Federated": "accounts.google.com" }
- 联合身份用户(federated identity) - SAML identity provider
"Principal": { "Federated": "arn:aws:iam::AWS-account-ID:saml-provider/provider-name" }
- IAM角色(IAM Role)
"Principal": { "AWS": "arn:aws:iam::AWS-account-ID:role/role-name" }
- AWS 服务
"Principal": { "Service": "elasticmapreduce.amazonaws.com" }
- Everyone(匿名用户)
"Principal": "*"
或"Principal" : { "AWS" : "*" }
- 规范用户ID
"Principal": { "CanonicalUser": "79a59df900b949e55d96a1e698fbacedfd6e09d98eacf8f8d5218e7cd47ef2be" }
- 特定AWS账户:
- Effect - 规则的结果
- 有效值为Allow和Deny
- Action - 指定的策略权限,能进行何种操作
- AWS S3相关的所有策略权限,参考官网AWS S3 在策略中指定权限
- 例子
- Amazon SQS操作 -
"Action": "sqs:SendMessage"
- Amazon EC2操作 -
"Action": "ec2:StartInstances"
- Amazon SQS操作 -
- Resource - 资源名
- Resource就是ARN(aws resource name)的集合
- ARN有三种格式
- 格式一: arn:partition:service:region:account-id:resource
- 例子 arn:aws:iam:us-west-2:123456789012:user/David
- 格式二: arn:partition:service:region:account-id:resourcetype/resource
- 例子 arn:aws:s3:::my_corporate_bucket/exampleobject.png
- 格式三: arn:partition:service:region:account-id:resourcetype:resource
- 例子 arn:aws:rds:eu-west-1:123456789012:db:mysql-db
- 其中全球区的partition为aws,而中国区的partition为aws-cn
- 格式一: arn:partition:service:region:account-id:resource
- Resource可以使用通配符*和?
- 某个bucket中所有的object arn:aws:s3:::mypublicbucket/*
- SID - 每份策略的标识符
- 策略的名字,在整个Policy文件中需要唯一
- Principal服务委托人 - 被允许对某个资源进行某种操作的主体,只在Bucket Policy中使用。分为以下几种:
- 注意: 在User Policy中没有Principal,执行User Policy的主体就是Principal
- 一个Policy包含如下几个元素
-
- Condition是一个可选元素
- Condition元素可用来在Policy中授予条件时指定某些条件, 一条Policy可以有一条或者多条Condition
- 类似于在policy中添加了一个”if”语句
- 详细用法参见官网文档
一个Condition包含如下要素
- 一个条件运算符(Condition Operators),例如StringEquals,NumericEquals以及IpAddress等,所有的条件运算符参见官网文档IAM JSON 策略元素:条件运算符
- Key/Value的键值对,包含条件键(Condition Key)和允许的值(Value)
- 例子, 如下Condition的片段中,
StringEquals
就是条件运算符,s3:x-amz-acl
就是条件键,public-read
就是值。这个Condition会被解读为: s3:x-amz-acl的字符串等于(StringEquals) public-read的时候,Condition检查通过12345"Condition": {"StringEquals": {"s3:x-amz-acl":["public-read"]}}
-
允许用户只有在设置”public-read” ACL的时候才能”put” object
12345678910111213{"Version":"2012-10-17","Statement":[{"Sid":"AddCannedAcl","Effect":"Allow","Principal": {"AWS": ["arn:aws:iam::111122223333:root","arn:aws:iam::444455556666:root"]},"Action":["s3:PutObject","s3:PutObjectAcl"],"Resource":["arn:aws:s3:::examplebucket/*"],"Condition":{"StringEquals":{"s3:x-amz-acl":["public-read"]}}}]}仅允许用户在开启加密的时候才允许”put” object, 例子参考官网博文How to Prevent Uploads of Unencrypted Objects to Amazon S3
- 仅允许用户在使用multi-factor验证的时候才能删除某个object1234567891011121314{"Version": "2012-10-17","Id": "123","Statement": [{"Sid": "","Effect": "Deny","Principal": "*","Action": "s3:*","Resource": "arn:aws:s3:::examplebucket/taxdocuments/*","Condition": { "Null": { "aws:MultiFactorAuthAge": true }}}]}
带有Condition的完整Policy例子
- 允许来自源IP在192.168.143.0/24的任何人获取Bucket examplebucket中的任意object,但IP地址192.168.143.188除外。123456789101112131415161718192021{"Version": "2012-10-17","Id": "S3PolicyId1","Statement": [{"Sid": "statement1","Effect": "Allow","Principal": "*","Action":["s3:GetObject"] ,"Resource": "arn:aws:s3:::examplebucket/*","Condition" : {"IpAddress" : {"aws:SourceIp": "192.168.143.0/24"},"NotIpAddress" : {"aws:SourceIp": "192.168.143.188/32"}}}]}
- 允许来自源IP在192.168.143.0/24的任何人获取Bucket examplebucket中的任意object,但IP地址192.168.143.188除外。
记忆Policy元素的小技巧,AcloudGuru课程中有一个容易记忆的方法
- 总共6个要素(Condition可选)
- Conditions
- Principal
- Effect
- Action
- Resource
- SID
- 对于Bucket policy来说
- I “C PEARS” – 字母C读成成see,意为”我在Bucket Policy中看见了梨子”
- 对于IAM Policy来说
- I “C EARS” – 字母C读成see,意为”我在IAM Policy中看见了耳朵”
- 总共6个要素(Condition可选)
跨账户策略注意点
跨账户访问时,假设账户A设置了允许账户B上传object到A的Bucket中, 当账户B上传object到A的Bucket中时,object的owner是B,A默认是没有权限访问该Object的。
可以通过设置Bucket Policy的方式,让账户B必须要授权A能够完全控制B上传的object。
官网文章 How can I make sure the bucket owner has access to resources that are copied or moved between Amazon S3 buckets owned by different AWS accounts?跨账户授权时,如果通过Bucket Policy授权其他账户的IAM用户访问自己的Bucket,IAM用户还需要他自己的Root账户也同时授权权限访问该Bucket,否则IAM用户没有权限访问该Bucket。 被授权的其他账户的IAM账户,仍然需要自己的root账户添加授权permission才能访问源Bucket。
如果账户A使用Bucket Policy授权账户B的User C能够访问账户A的Bucket_A, 此时User C还会没法访问Bucket_A, 必须账户B在给User C的Policy中添加允许访问Bucket_A的策略后,User C才能访问Bucket_A。
总结为: 如果一个Bucket要授权给其他账号的IAM User使用时,必须要两个Account都显式授权IAM User访问权限才行。
使用签名(signed)的方式访问私有Object
什么是签名
AWS提供了一个签署签名的功能,在HTTP请求中附加签名信息后,AWS能够识别发送请求的用户,并验证请求是否是该用户授权签名的。
AWS S3中可以使用该功能来短暂的让用户访问或操作某个私有Object。
Bucket的Owner通过指定如下信息来生成一个pre-signed的URL
- 加密凭证(Security credentials)
- Bucket名字
- Object名字
- HTTP方法(GET, PUT, DELETE等)
- 过期时间
得到pre-signed URL的任何人,都能够在指定的过期时间之前,访问指定的object。
签名版本
AWS提供了两种签名版本Signature Version 4 和Signature Version 2。
对于S3来说,所有的Region都支持Signature Version 4,而Signature Version 2的签名方式,只有在2014年1月30日之前的Region才支持,在此日期之后建立的Region,一律都只支持Signature Version 4的签名方式。此处是官方说明文档Authenticating Requests (AWS Signature Version 4)
AWS CLI生成pre-signed的一个例子, 拿韩国首尔Region为例。
但是首尔Region是不支持该签名方式的,因此使用生成的上述URL访问S3时,会报告如下错误
在AWS CLI中指定首尔Region后,CLI会判断Region,从而使用Signature Version 4的加密方式
使用上述生成的URL,就能够顺利访问到原本私有的Object了。