バケットポリシーを使ったS3 Bucketへのアクセス制御について

# はじめに
　S3 Bucketへのアクセスを制御したい場合、IAMポリシー、ACLまたはパケットポリシーで制御することができます。
　やり方は色々あると思いますが、今回はバケットポリシーを使ったS3 Bucketへのアクセス制御について下記３点の方法を簡単に説明して、

1. Principalを使ったアクセス制御
2. NotPrincipalを使ったアクセス制御
3. 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*を<font color="red">*明示的にDeny*</font>される
- IAM User以外、IAM RoleやAWSアカウントなども指定できます。ただしIAM Groupを指定することができません。詳細はAWSの[Principal](http://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements.html#Principal)を確認ください。

### サンプルバケットポリシーの適用による結果

 - IAMユーザtest-user1の場合
<img width="1672" alt="1.pic.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/117156/5028adc6-7e17-7c6a-ea34-4de72daabc85.jpeg">

 - test-user1以外のIAMユーザの場合
 <img width="1634" alt="2.pic.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/117156/522c80c2-300b-ecf4-562e-e277d0543e2f.jpeg">


### 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*を<font color="red">*明示的にDeny*</font>される
- 構文などはPrincipalと同じです。詳細はAWSの[NotPrincipal](http://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements.html#NotPrincipal)を確認ください。
### サンプルバケットポリシーの適用による結果

- IAMユーザtest-user1の場合
<img width="1672" alt="4.pic.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/117156/248a2477-9484-5013-5ffd-026324d93956.jpeg">

- test-user1以外のIAMユーザの場合
<img width="1504" alt="3.pic.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/117156/8af02f44-3160-4ca8-cdaa-514c9b235b17.jpeg">

### NotPrincipalを使った制御の欠点
　NotPrincipal / PrincipalはIAM Roleを指定することができます。
　IAM Roleには<font color="red">普通のRole</font>と<font color="red">AssumeRole用のRole</font>といった２種類の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" }```
　になっています。
　<font color="red">role-session-name</font>はAssumeRoleする側で指定可能ですので、**変わる可能性があります**。しかし、<font color="red">プリンシパルを指定する際に、アスタリスク( * )は ARN の一部に一致させることはできません</font>。
　下記の内容は、AWSの[Pricipal](http://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements.html#Principal)の説明から引用したものです。
>Note
アスタリスクは、すべてのユーザー/匿名ユーザーのプレースホルダーとしてのみ使用できます。これをワイルドカードとして使用して、名前または ARN の一部に一致させることはできません。

　role-session-nameが決まっている場合は問題がありませんが、<font color="red">決まっていない場合はrole-session-nameごとにユーザを指定する必要があります。</font>これは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を指定していないので、結果はこうなります。
<img width="1570" alt="8.pic.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/117156/b4dc6391-0d6c-9cfb-1b77-97faa01a0153.jpeg">



## Conditionを使ったアクセス制御

Conditionを使えば、NotPrincipalを使った制御の欠点を回避できます。

具体的には、文字列条件演算子<font color="red">StringNotLike</font>とキー<font color="red">aws:userid</font>を使います。
(条件演算子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**)は<font color="red">**aws iam get-role**</font>で取得可能です。

```
$ 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した場合
<img width="1574" alt="6.pic.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/117156/ae7bb8f1-ac1c-a075-050f-83d800f5ee98.jpeg">

- test-assumerole以外の場合
<img width="1582" alt="7.pic.jpg" src="https://qiita-image-store.s3.amazonaws.com/0/117156/cb2a51fb-796b-3880-eb11-213bf7501698.jpeg">

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