前陣子收到客戶的請求要將 Amazon S3 設定的權限更加嚴謹,在預設情況下 Amazon S3 Bucket 以及 Object 都是「只允許同帳號訪問、跨帳號禁止且禁止 Public 訪問」所以權限邊界畫在 Account-level 內有比較寬裕的訪問權限。
By default, all Amazon S3 buckets and objects are private. Only the resource owner which is the AWS account that created the bucket can access that bucket. The resource owner can, however, choose to grant access permissions to other resources and users.
但是在客戶的情境中甚至希望在同一個帳號下也應該要 default deny all,並且採用白名單 (Whitelist) 方式訪問,在這個場景中的白名單有幾位:
- ROOT user 以防止權限設定錯誤時,可以透過 ROOT 恢復
- 指定的 IAM users/roles
- Amazon CloudFront service
- 指定的 Amazon EKS worker nodes 並且只能透過 VPC endpoint 訪問
要限縮 Amazon S3 的訪問權限有幾種方法:
- Lake Formation
- Amazon S3 Bucket Policy
Lake Formation 的專長是針對 Data Lake 做到 fine-grained access control 在這個 case 上根本殺雞焉用牛刀。所以小弟用 S3 Bucket Policy 試寫出需求場景。
在這之前先理解 Amazon S3 Bucket Policy 本身是「default allow resource owner, deny when any deny action」意味著幾件事:
- 沒有 Bucket Policy 時,同一個 Account IAM 只要有 action 就能訪問 Amazon S3 Bucket
- Bucket Policy 只要有任何一條 deny 符合,就是 deny。
- 當符合 allow 以及 deny 時,仍然 deny。
依照上述條件,Amazon S3 Bucket 分為兩個邏輯撰寫:
- deny all 然後排除 whitelist
- allow 來自 cross account 的訪問
第一條:deny all exclude whitelist
{
"Sid": "DefaultDenyWithWhitelist",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::bucket-whitelist-example",
"arn:aws:s3:::bucket-whitelist-example/*"
],
"Condition": {
"ArnNotLike": {
"aws:PrincipalArn": [
"arn:aws:iam::012345678910:root",
"arn:aws:iam::012345678910:user/shazi7804",
"arn:aws:iam::012345678910:role/AmazonEKSNodeGroupRole",
"arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E4JD8MK25L..."
]
}
}
}
第二條:限縮 Amazon EKS 僅能從 VPC endpoint 訪問
{
"Sid": "AllowOnlyAmazonEKSFromVpcEndpoint",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::bucket-whitelist-example",
"arn:aws:s3:::bucket-whitelist-example/*"
],
"Condition": {
"StringNotEquals": {
"aws:SourceVpce": "vpce-0a1b2c3d4e"
},
"ArnLike": {
"aws:PrincipalArn": "arn:aws:iam::012345678910:role/AmazonEKSNodeGroupRole"
}
}
}
第三條:allow 來自 CloudFront 的訪問
{
"Sid": "AllowCloudFrontWithOAI",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E4JD8MK25L..."
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::bucket-whitelist-example/*"
}
在這個 Bucket Policy 中用到了 aws:PrincipalArn 這個 Global condition key 用來指定所有 Principal 訪問,我也嘗試過使用 NotPrincipal 來排除 Principal,但是 NotPrincipal 在處理 IAM Role 時會將 Role ARN 和 Role session name 分開定義而不能像 aws:PrincipalArn 只寫 Role ARN 就涵蓋 Role session name,所以在 Bucket Policy 上 aws:PrincipalArn 會更好用一些。