はじめに
S3 Bucketへのアクセスを制御したい場合、IAMポリシー、ACLまたはパケットポリシーで制御することができます。
やり方は色々あると思いますが、今回はバケットポリシーを使ったS3 Bucketへのアクセス制御について下記3点の方法を簡単に説明して、
- Principalを使ったアクセス制御
- NotPrincipalを使ったアクセス制御
- Conditionを使ったアクセス制御
Conditionを使ったS3 Bucketへのアクセス制御をおすすめします。
パケットポリシーでのアクセス制御について
Principalを使ったアクセス制御
サンプルパケットポリシー
{
"Version": "2012-10-17",
"Id": "Policy146935390****",
"Statement": [
{
"Sid": "Stmt146935390****",
"Effect": "Deny",
"Principal": {
"AWS": "arn:aws:iam::2847****1948:user/test-user1"
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::jobbin-key"
}
]
}
- IAMユーザtest-user1の場合、バケットjobbin-keyに対するListBucketを明示的にDenyされる
- IAM User以外、IAM RoleやAWSアカウントなども指定できます。ただしIAM Groupを指定することができません。詳細はAWSのPrincipalを確認ください。
サンプルバケットポリシーの適用による結果
- IAMユーザtest-user1の場合

- test-user1以外のIAMユーザの場合

Principalを使ったアクセス制御の欠点
IAM UserやIAM Roleなどを追加するたびに、バケットポリシーを更新しないといけません。(嫌な作業ですよね)
NotPrincipalを使ったアクセス制御
NotPrincipalを使えば、指定するもの(IAM User/Role、AWS Serviceなど)のみ許可することができなすので、Principalを使ったアクセス制御の欠点を回避できます。
サンプルパケットポリシー
{
"Version": "2012-10-17",
"Id": "Policy146935390****",
"Statement": [
{
"Sid": "Stmt146935390****",
"Effect": "Deny",
"NotPrincipal": {
"AWS": "arn:aws:iam::2847****1948:user/test-user1"
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::jobbin-key"
}
]
}
- IAMユーザtest-user1以外の場合、バケットjobbin-keyに対するListBucketを明示的にDenyされる
- 構文などはPrincipalと同じです。詳細はAWSのNotPrincipalを確認ください。
サンプルバケットポリシーの適用による結果
- IAMユーザtest-user1の場合

- test-user1以外のIAMユーザの場合

NotPrincipalを使った制御の欠点
NotPrincipal / PrincipalはIAM Roleを指定することができます。
IAM Roleには普通のRoleとAssumeRole用のRoleといった2種類のRoleがあります。
普通のRoleのNotPrincipalの値は
{ "AWS": "arn:aws:iam::AWS-account-ID:role/role-name" }
に対して、
AssumeRole用のRoleのNotPrincipalの値は
{ "AWS": "arn:aws:sts::AWS-account-ID:assumed-role/role-name/role-session-name" }
になっています。
role-session-nameはAssumeRoleする側で指定可能ですので、変わる可能性があります。しかし、プリンシパルを指定する際に、アスタリスク( * )は ARN の一部に一致させることはできません。
下記の内容は、AWSのPricipalの説明から引用したものです。
Note
アスタリスクは、すべてのユーザー/匿名ユーザーのプレースホルダーとしてのみ使用できます。これをワイルドカードとして使用して、名前または ARN の一部に一致させることはできません。
role-session-nameが決まっている場合は問題がありませんが、決まっていない場合はrole-session-nameごとにユーザを指定する必要があります。これはNotPrincipalを使った制御の欠点です。
ワイルドカード( * )を使わずに,下記のサンプルバケットポリシーを使って検証してみます。
- 別アカウントIAMユーザがロールtest-assumeroleにAssumeRoleして、バケットjobbin-keyにアクセスしてみます。
- AssumeRole用のRoleに必要な権限を付与しています。
{
"Version": "2012-10-17",
"Id": "Policy146935390****",
"Statement": [
{
"Sid": "Stmt146935390****",
"Effect": "Deny",
"NotPrincipal": {
"AWS": "arn:aws:iam::2847****1948:role/test-assumerole"
},
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::jobbin-key"
}
]
}
サンプルバケットポリシーが問題なく適用されますが、role-session-nameを指定していないので、結果はこうなります。
Conditionを使ったアクセス制御
Conditionを使えば、NotPrincipalを使った制御の欠点を回避できます。
具体的には、文字列条件演算子StringNotLikeとキーaws:useridを使います。
(条件演算子ArnNotLikeとキーaws:SourceArnを使ってみましたが、うまくできませんでした。別のいい方法があれば、是非教えて下さい。)
サンプルパケットポリシー
{
"Version": "2012-10-17",
"Id": "Policy146927794****",
"Statement": [
{
"Sid": "Stmt146927793****",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::jobbin-key",
"Condition": {
"StringNotLike": {
"aws:userid": "AROAISXGEH----G266U2S:*"
}
}
}
]
}
- AssumeRole用のロールtest-assumerole以外の場合、バケットjobbin-keyに対するListBucketをDenyされます。
- test-roleのRoleId(AROAISXGEH----G266U2S)はaws iam get-roleで取得可能です。
$ aws iam get-role --role-name test-assumerole
{
"Role": {
"AssumeRolePolicyDocument": {
"Version": "2012-10-17",
"Statement": [
{
"Action": "sts:AssumeRole",
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::8918****5875:root"
}
}
]
},
"RoleId": "AROAISXGEH----G266U2S",
"CreateDate": "2016-07-24T11:31:00Z",
"RoleName": "test-assumerole",
"Path": "/",
"Arn": "arn:aws:iam::2847****1948:role/test-assumerole"
}
}
サンプルバケットポリシーの適用による結果
- test-assumeroleをAssumeRoleした場合

- test-assumerole以外の場合

まとめ
Principalを使ったアクセス制御の欠点はNotPrincipalを使えば回避できます。
さらに、NotPrincipalを使ったアクセス制御の欠点はConditionを使えば回避できます。
状況によって、使い分けが必要だと思いますが、S3 BucketへのアクセスをAssumeRole用のロールに限定したい場合は、Conditionの利用をおすすめします。
以上となりますが、少しでも皆さんにお役に立てれば、嬉しいです。