【S3】「パブリックアクセスのブロック」を整理する

# 1. はじめに
パブリックアクセスのブロック設定とは、
AWSのストレージサービスであるS3の設定項目です。

![cap0.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/7ae9801f-843a-32ef-2915-424133079bc4.png)

初心者的には若干複雑で、設定の詳細を毎回忘れてしまうので、整理してみます。

## 1.1. ACLはスコープ外
S3には2つの方法でバケット、オブジェクトへのアクセスをコントロールできます。
「バケットポリシー」と「ACL(アクセスコントロールリスト)」です。

片方のACLは現在、AWS公式からも以下の通りあまり使わなくていいよーと説明されています。
>Amazon S3 の最新のユースケースの大部分では ACL を使用する必要がなくなっています。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/acl-overview.html#:~:text=Amazon%20S3%20%E3%81%AE%E6%9C%80%E6%96%B0%E3%81%AE%E3%83%A6%E3%83%BC%E3%82%B9%E3%82%B1%E3%83%BC%E3%82%B9%E3%81%AE%E5%A4%A7%E9%83%A8%E5%88%86%E3%81%A7%E3%81%AF%20ACL%20%E3%82%92%E4%BD%BF%E7%94%A8%E3%81%99%E3%82%8B%E5%BF%85%E8%A6%81%E3%81%8C%E3%81%AA%E3%81%8F%E3%81%AA%E3%81%A3%E3%81%A6%E3%81%84%E3%81%BE%E3%81%99%E3%80%82


私自身も同じ理解なので、この記事では主にバケットポリシーに着目して整理してみます。

![cap01.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/e245b61c-d834-08d7-b37f-57df01dac283.png)

# 2.「パブリックアクセス可能な状態」とは？
まずはS3が「パブリックアクセス可能な状態」とは何か？を整理します。

前述しましたが、S3には2つのアクセス制御方法があります。

バケットポリシーでアクセス制御を行っている場合、「パブリックアクセス可能なバケットポリシー」は以下のように定義されています。

>バケットポリシーを評価する場合、Amazon S3 はまずポリシーがパブリックであると想定します。その後、ポリシーを評価して非パブリックとしての資格があるかどうかを判断します。非パブリックと見なすには、バケットポリシーで、次のうち 1 つ以上の固定値 (ワイルドカードを含まない値またはAWS Identity and Access Managementポリシー変数) にのみアクセスを許可する必要があります。
>- AWS プリンシパル、ユーザー、ロール、またはサービスプリンシパル (例: aws:PrincipalOrgID)
>- aws:SourceIp を使用した一連のクラスレスドメイン間ルーティング (CIDR)。CIDR の詳細については、RFC Editor のウェブサイトで RFC 4632 を参照してください。
>- aws:SourceArn
>- aws:SourceVpc
>- aws:SourceVpce
>- aws:SourceOwner
>- aws:SourceAccount
>- s3:x-amz-server-side-encryption-aws-kms-key-id
>- aws:userid、「AROLEID:*」パターンの外側
>- s3:DataAccessPointArn
>- s3:DataAccessPointAccount


文字だけだと分かりづらいので、ドキュメントの具体例を確認しながら整理します。(ドキュメントが一部間違っているので、動くよう修正して転記しています)

```パブリックアクセス可能と判断されるポリシー1.json
    {
		"Principal": "*", 
		"Resource": "arn:aws:s3:::my-test-bucket/*", 
		"Action": "s3:PutObject", 
		"Effect": "Allow" 
	}
```
↑シンプルな例です。
Principalがワイルドカードで、Conditionなども特に指定されていないため、パブリックアクセス可能と判断されます。

```パブリックアクセス可能と判断されるポリシー2.json
    {
		"Principal": "*", 
		"Resource": "arn:aws:s3:::my-test-bucket/*", 
		"Action": "s3:PutObject", 
		"Effect": "Allow", 
		"Condition": { "StringLike": {"aws:SourceVpc": "vpc-*"}}
	}
```

↑パブリックアクセスのイメージがつかみやすい例です。
Conditionが指定されていますが、パブリックアクセス可能と判断されます。
```"aws:SourceVpc": "vpc-*"```条件のみでは、アクセスできるクライアントを限定しきれていないという判定だと思います。

また、以下のように修正すると、パブリックアクセスを許可**しない**ポリシーとして扱われると説明されています。
```パブリックアクセス不可能と判断されるポリシー.json
    {
		"Principal": "*", 
		"Resource": "arn:aws:s3:::my-test-bucket/*", 
		"Action": "s3:PutObject", 
		"Effect": "Allow", 
		"Condition": {"StringEquals": {"aws:SourceVpc": "vpc-91237329"}}
	}
```

Condition句の限定範囲が固定値で限定的になっていることが分かります。
```diff_json
+ "aws:SourceVpc": "vpc-91237329"
- "aws:SourceVpc": "vpc-*"
```

再度、「パブリックアクセス可能なバケットポリシー」の定義を確認してみます。
>次のうち 1 つ以上の固定値にのみアクセスを許可する必要があります 
>- AWS プリンシパル、ユーザー、ロール、またはサービスプリンシパル (例: aws:PrincipalOrgID)
>- aws:SourceIp を使用した一連のクラスレスドメイン間ルーティング (CIDR)。CIDR の詳細については、RFC Editor のウェブサイトで RFC 4632 を参照してください。
>- aws:SourceArn
>- aws:SourceVpc
>- aws:SourceVpce
>- aws:SourceOwner
>- aws:SourceAccount
>- s3:x-amz-server-side-encryption-aws-kms-key-id
>- aws:userid、「AROLEID:*」パターンの外側
>- s3:DataAccessPointArn
>- s3:DataAccessPointAccount

記載例と合わせ、「パブリックアクセスが可能」なポリシーとはつまり、
**具体的な主体を指定していないAllowなstatementを含むポリシー**だということが分かりました。

# 3. 各設定項目の整理

パブリックアクセスの定義がなんとなく整理できたので、設定項目も読み解いていこうとおもいます。
前述しましたが、ACLの設定項目は今回スコープ外とします。

## 3.1. マネコンで確認
バケットポリシー関連の2つの項目が存在します。

### 3.1.1 新しいパブリックバケットポリシーをブロック

![cap9.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/aac97fd7-9def-3f67-21ba-e2d17f883cfa.png)

>**新しいパブリックバケットポリシーまたはアクセスポイントポリシーを介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする**
S3 は、バケットとオブジェクトへのパブリックアクセスを許可する新しいバケットポリシーおよびアクセスポイントポリシーをブロックします。この設定は、S3 リソースへのパブリックアクセスを許可する既存のポリシーを変更しません。

パブリックアクセスを可能とするバケットポリシーの追加を禁止する設定です。
この設定がチェックされている場合、パブリックアクセスを可能とするバケットポリシーの追加がエラーとなります。

実際に挙動を試してみます。

![cap0.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/21830bf7-ba1b-225b-0a79-a1c5a8160b40.png)

デフォルトではパブリックアクセスのブロック設定は全て有効化されています。

![cap2.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/28bbefa0-0a67-4dba-afe2-1f202d43eb6b.png)

ドキュメントに記載されたパブリックアクセス可能なポリシーをアタッチしてみましたが、エラーとなりました。

![cap3.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/17892ff0-50df-4d57-a43f-97bb1b59e93c.png)

設定をOFFにし、再度、パブリックアクセス可能なポリシーをアタッチしてみます。

![cap4.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/0f8ba54a-b269-b5ba-22b4-72fc1ff42b25.png)

成功しました！

### 3.1.2 パブリックバケットポリシーを介したバケットとオブジェクトへのパブリックアクセスをブロックする

![cap10.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/07289924-7c3d-3a08-b323-d9fd9094c922.png)

>**任意のパブリックバケットポリシーまたはアクセスポイントポリシーを介したバケットとオブジェクトへのパブリックアクセスとクロスアカウントアクセスをブロックする**
S3 は、バケットとオブジェクトへのパブリックアクセスを付与するポリシーを使用したバケットまたはアクセスポイントへのパブリックアクセスとクロスアカウントアクセスを無視します。

パブリックアクセスを可能とするバケットポリシーを無効化する設定です。
この設定がチェックされている場合、パブリックアクセスを可能とするバケットポリシーは無効化されます。

![cap5.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/c5507812-6d51-8ac1-4a36-636fb0e7dcbf.png)

実際に設定を無効化します。

```パブリックアクセス可能と判断されるポリシー1.json
    {
		"Principal": "*", 
		"Resource": "arn:aws:s3:::my-test-bucket/*", 
		"Action": "s3:PutObject", 
		"Effect": "Allow" 
	}
```

また、バケットには上記パブリックアクセスを可能とするバケットポリシーを付与します。

![cap6.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/57bfe44e-bf2d-4ae9-c1c9-b6f5114e1840.png)

パブリックアクセス可能なポリシーをブロックする設定が有効化されていないので、アクセス可能となります。

![cap7.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/48dcfc62-22fe-1966-6859-89104723acdb.png)

再度、パブリックアクセスを可能とするバケットポリシーを無効化してみます。

![cap8.PNG](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3654730/e346e741-6b1d-7776-bf68-857cc80ff614.png)

パブリックアクセス可能なバケットポリシーが付与されていますが、アクセスが拒否されました。

## 3.2. Terraformで確認
Terraformでは、aws_s3_bucket_public_access_blockリソースとして定義できます。
マネコンの各設定項目に１：１で対応しています。
```s3.tf
resource "aws_s3_bucket_public_access_block" "main" {
  bucket = aws_s3_bucket.main.id

  # 新しいアクセスコントロールリスト (ACL) を介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
  block_public_acls       = true

  # 任意のアクセスコントロールリスト (ACL) を介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
  ignore_public_acls      = true

  # 新しいパブリックバケットポリシーまたはアクセスポイントポリシーを介して付与されたバケットとオブジェクトへのパブリックアクセスをブロックする
  block_public_policy     = true

  # 任意のパブリックバケットポリシーまたはアクセスポイントポリシーを介したバケットとオブジェクトへのパブリックアクセスとクロスアカウントアクセスをブロックする
  restrict_public_buckets = true
}

```

# おわりに
きちんとドキュメントを読めばあまり難しい話ではなかったです（この記事もほとんどドキュメントのコピペ・・・）。
AWSのドキュメントは機械翻訳が微妙かつ誤記も多いのであまり好きじゃないのですが、
がんばって読めるようになりたいと思いました。