VPCエンドポイント経由のみ許可するバケットポリシー

#ドキュメントに記載されたバケットポリシーを少し改造してみた

皆さんS3のバケットポリシーどうしてますか？

私は自身含め周りにAWSに明るい人がいないため、とりあえずドキュメントを元に**[VPC エンドポイント用のバケットポリシー](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/example-bucket-policies-vpc-endpoint.html)**を適用しています。
そもそもVPCエンドポイントとはなんぞや?という方は某メソッド様の記事を読んでみるととても勉強になります。

>[S3がVPCのプライベートサブネットからアクセス可能になりました！](https://dev.classmethod.jp/cloud/vpc-endpoint-for-s3/)

##VPCエンドポイントとは
ざっくり解説すると、S3はEC2やELBと違ってVPC内に存在するサービスではないため、
通常はEC2からAWSCLI等を使用してアクセスするにはインターネットゲートウェイ(IGW)を経由する必要があります。

**"IGWを経由する"**ここがミソで、AWSはセキュリティ向上のためにも極力プライベートサブネット内にEC2を配置することをベストプラクティスにしていたりします。
IGWからインターネットへアクセスできるそれすなわち**パブリックサブネット**ということになります。

VPCエンドポイントは**VPC内部のリソースであれば**インターネットを経由せずにアクセス可能になる出入り口のようなものです。つまりインターネットへの経路がない**プライベートサブネット内のEC2**からもS3にアクセス可能になります。


###VPCエンドポイント経由でのみアクセス可能にすると何が嬉しいか
VPCエンドポイントを設定しても、VPCからはIGWを経由してアクセス可能になっても依然インターネット経由でS3へアクセスすることは可能です。

ドキュメントのバケットポリシーを適用すれば、VPC経由でのみS3にアクセスできるようになるので
**インターネット経由でS3へアクセスすること**を防ぐことが出来ます。

割とよくあるオンプレ + AWS　をDirectConnctで接続してセキュアな環境構築!!みたいな構成にはうってつけです。

(ITproか何かで拝見したのですが、S3の権限周りが起因したセキュリティ事故は割と多いらしいです。)

##ドキュメントのバケットポリシー
>[Amazon S3 の VPC エンドポイント用のバケットポリシーの例](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/example-bucket-policies-vpc-endpoint.html)

上記のドキュメントに記載されたバケットポリシーは、S3バケットをVPCエンドポイント経由からのみアクセスできるようにするバケットポリシーです。

>```json
{
   "Version": "2012-10-17",
   "Id": "Policy1415115909152",
   "Statement": [
     {
       "Sid": "Access-to-specific-VPCE-only",
       "Action": "s3:*",
       "Effect": "Deny",
       "Resource": ["arn:aws:s3:::examplebucket",
                    "arn:aws:s3:::examplebucket/*"],
       "Condition": {
         "StringNotEquals": {
           "aws:sourceVpce": "vpce-1a2b3c4d"
         }
       },
       "Principal": "*"
     }
   ]
}
```

ポリシーの内容を見ればお分かりいただけると思いますが正確にはアクセス可能にするではなく
**特定のVPCエンドポイントから以外のアクションはすべて拒否**するバケットポリシーです。

・examplebucketバケットに対するS3のアクションすべて拒否する(ただしvpce-1a2b3c4dは除く)

こうすれば伝わりますかね?

#ドキュメント通りやってみた

構成は以下の図のようにしています。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/240644/f0cf951b-d74d-6b4d-19a9-e2764563942c.png)


青線で描いたのがS3へのルートで3つあると思います。
まずバケットポリシーでインターネット経由のルートを拒否することを試してみます。

###マネジメントコンソールから覗いてみる

どうなるのか興味わきますよね???
とりあえずみんな大好きマネジメントコンソールから見てみましょう。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/240644/e76720de-8519-bfd7-aa39-69fb672ef735.png)
とりあえずAdministratorAccess権限のあるIAMユーザでログイン後、S3バケットを作成して、オブジェクトをアップロードしておきます。

そして、バケットポリシーをドキュメントと同じものを適用します。(バケット名は自分の作成したものにあわせてください)

マネジメントコンソールはお家からログインしています。

[S3バケット一覧]
![image.png](https://qiita-image-store.s3.amazonaws.com/0/240644/0fbccdd3-1dc2-0b3f-9971-8ceb8ea1f2af.png)

[S3バケット内]
![image.png](https://qiita-image-store.s3.amazonaws.com/0/240644/a953594f-62e4-4a7a-f2d6-49755841c0a6.png)

[バケットポリシー]
![4.JPG](https://qiita-image-store.s3.amazonaws.com/0/240644/342a8c74-048a-9e13-4446-5087b3f87f6f.jpeg)

見事にアクセス拒否されています!

###VPC内のEC2からAWSCLIを使って覗いてみる

踏み台サーバとプライべートサブネット内EC2両方からCLIコマンドを実行します。
両方のEC2にAdministratorAccess権限のIAMポリシーをIAMロールにアタッチして、CLIコマンドを使用します。

踏み台サーバのいるサブネットは0.0.0.0/0へのルートがあります。つまりIGW経由でインターネットへ出れます。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/240644/de704212-d494-41ab-cae6-0e102bff863d.png)

```console
$ aws s3 ls s3://qiita-test-001

An error occurred (AccessDenied) when calling the ListObjects operation: Access Denied

$ aws s3api get-bucket-policy --bucket qiita-test-001

An error occurred (AccessDenied) when calling the GetBucketPolicy operation: Access Denied
```
全部のアクションを試すのは流石にきついので、リストコマンドとバケットポリシーの取得コマンドを打鍵してみました。
しっかりAccessDeniedされています。

####プライベートサブネット内のEC2
このEC2がいるサブネットはIGWへのルートがなく、代わりにVPCエンドポイントへのルートがあります。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/240644/8aec88f3-0d8f-a37b-5eb2-4e96698c1783.png)

```console
$ aws s3 ls s3://qiita-test-001
2018-03-01 23:52:59         63 index.html

$ aws s3api get-bucket-policy --bucket qiita-test-001 --output text | jq --indent 4 .
{
    "Version": "2012-10-17",
    "Id": "Policy1415115909152",
    "Statement": [
        {
            "Sid": "Access-to-specific-VPCE-only",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::qiita-test-001",
                "arn:aws:s3:::qiita-test-001/*"
            ],
            "Condition": {
                "StringNotEquals": {
                    "aws:sourceVpce": "vpce-ef935086"
                }
            }
        }
    ]
}
```

CLIコマンド経由でバケット内のindex.htmlとバケットポリシーがリストできてます。

これでドキュメント通りVPCエンドポイントからのみS3へアクセスできるように設定できました。

###マネジメントコンソールはVPCの外
なぜマネジメントコンソールからはS3へのアクセスが拒否されるかというと
**特定のVPCエンドポイントから以外のアクションはすべて拒否**
と書いた通りです。

マネジメントコンソールは投稿主の家からログインしているため、当然VPCの外です。
なのでアクセスが拒否されたわけです。

厳密にはマネジメントコンソールからS3バケットを見るためのListアクションがバケットポリシーで拒否されたといった方が近いかもしれません。

##本題:バケットポリシーアレンジしてみた
このバケットポリシーを適用するとセキュアにできますが、すごい不便です。
なんせオブジェクトがあるかの確認や、バケット設定どうしてたかなーと思ってもCLIコマンド等を使用しないと見れません。
セキュリティと引き換えにユーザビリティはすごい低いかもしれません(汗)

という訳で基本的にはVPCエンドポイント経由のみとしつつ、一部例外を適用できないか模索してみました。

###Not Action
バケットポリシーではなくIAMのドキュメントとにらめっこしてて見つけたのが**Not Action**です。

[IAM JSON ポリシーエレメント: NotAction](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_notaction.html)

ちなみに意味はEffectがAllowなのかDenyかで変わります。

>- 許可の NotAction
NotAction で指定されたアクションを除いて、"Effect": "Allow" のステートメントで NotAction 要素を使用して、AWS サービス内のすべてのアクションへのアクセスできます。
- 拒否のNotAction
"Effect": "Deny" のステートメントでNotAction 要素を使用すると、NotAction 要素で指定されているアクションを除いて、リストされたすべてのリソースへのアクセスを拒否できます。

許可の NotActionであれば、指定したアクション以外が許可されます。
例えば、s3:Delete*　などを指定してあげれば削除以外の許可を与えられます。

拒否のNotActionであれば、指定したアクションは明示的拒否されません。
ただし、デフォルト拒否の扱いです。
つまりIAMポリシー側にAllowの権限があれば許可されます。

###マネジメントコンソールでListとバケットポリシーを見えるようにする
ではマネジメントコンソールから見えるようにしたいと思います。

ここでNotActionに必要そうな権限をドキュメントから見つけてきましょう。

>[ポリシーでのアクセス許可の指定](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/using-with-s3-actions.html)

>|アクセス許可のキーワード  |対応する Amazon S3 オペレーション  |
|---|---|
|s3:CreateBucket	PUT Bucket |s3:DeleteBucket	DELETE Bucket  |
|s3:ListBucket	 |GET Bucket (List Objects)、HEAD Bucket   |
|s3:ListBucketVersions  |GET Bucket Object versions  |
|s3:ListAllMyBuckets  |GET Service  |
|s3:ListBucketMultipartUploads  | マルチパートアップロードのリスト |

今回は"s3:ListBucket""s3:ListAllMyBuckets"と「バケットサブリソースオペレーションに関連する Amazon S3 アクセス許可」から"s3:GetBucketPolicy"を選択してみます。
※当然マネジメントコンソールからバケットポリシーの修正はできません。
ただし例外が存在します。それはルートアカウントです。

[マネジメントコンソール]
![image.png](https://qiita-image-store.s3.amazonaws.com/0/240644/18214ba8-c7ff-716b-361d-363e3665f426.png)

![image.png](https://qiita-image-store.s3.amazonaws.com/0/240644/17673025-94c5-5fea-9f1e-477177a85292.png)

[踏み台サーバ]

```console
$ aws s3 ls s3://qiita-test-001
2018-03-01 23:52:59         63 index.html

$ aws s3api get-bucket-policy --bucket qiita-test-001 --output text | jq --indent 4 .
{
    "Version": "2012-10-17",
    "Id": "Policy1415115909152",
    "Statement": [
        {
            "Sid": "Access-to-specific-VPCE-only",
            "Effect": "Deny",
            "Principal": "*",
            "NotAction": [
                "s3:ListAllMyBuckets",
                "s3:ListBucket",
                "s3:GetBucketPolicy"
            ],
            "Resource": [
                "arn:aws:s3:::qiita-test-001",
                "arn:aws:s3:::qiita-test-001/*"
            ],
            "Condition": {
                "StringNotEquals": {
                    "aws:sourceVpce": "vpce-ef935086"
                }
            }
        }
    ]
}
```

これで先ほどのドキュメント通りに設定したVPCエンドポイント経由のみに例外として
バケットのリストとバケットポリシーの取得を追加できました。

ちなみにNotActionに加えても、IAMポリシー側にアクションに対する許可がないと
バケットポリシーだけではデフォルト拒否状態なのでご注意ください。
どのアクションをを加えるかはユースケースに合わせてカスタマイズしてみてください。

以上です。
長々失礼いたしました。