[S3]バケットポリシー書き方まとめ

#はじめに

初歩的な書き間違いで数時間ロスしたので、勉強がてら書き方を整理します。
S3のバケットポリシーを例に、jsonの要素を一つずつ確認していきます。

# 他のアクセス制御方法との比較

書き方の理解のためにも、少しバケットポリシーについておさらいします。
S3のユーザーアクセス権限の設定方法は以下の3種類です。

|名称|概要|
|:-----|:-----|
|IAMポリシー|IAMユーザ、グループ、ロールに割り当てる。要はS3のIAMポリシー。他のAWSアカウントに付与することはできないため、自アカウントに対する制御に限られる。|
|バケットポリシー|バケット単位での柔軟な設定が可能。バケットごとに割り当てる必要がある。他のＡＷＳアカウントに対する設定も可能。|
|アクセスコントロールリスト（ACL）|バケット単位だけでなく、オブジェクト単位でも指定できるのが特徴。読みとり/書き込みの許可の設定ができる（拒否の設定はできない）。オブジェクトに付与されたURLについても、HTTPアクセスの許可が可能。|
また、**パブリックアクセス**設定機能を利用することで、簡単にオブジェクトのアクセス制御を行うこともできます。

※Aのアカウントで作成したバケットの操作権限を、Bのアカウントのユーザーに付与したい場合は、IAMポリシーとバケットポリシーの両方での設定が必要です。
>参考
>[Amazon S3 バケットに対し、オブジェクトをアップロードするアクセス権を、別の AWS アカウントのユーザーに与えるにはどうすれば良いですか？](https://aws.amazon.com/jp/premiumsupport/knowledge-center/s3-cross-account-upload-access/)
>[S3で誤ったデータの公開を防ぐパブリックアクセス設定機能が追加されました](https://dev.classmethod.jp/articles/s3-block-public-access/)


以下、バケットポリシーの要素についてまとめています。

# 先にざっくりまとめ

|要素|概要|
|:-----|:-----|
|Version|"2012-10-17"で固定（2021.12時点）。|
|Statement|「ここからステートメントを書きますよ～」という宣言みたいなもの。|
|Effect|ステートメントの内容を「許可/拒否」するか。|
|Action|「どのAWSサービス」の「どの操作」を「許可/拒否」するか。|
|Resource|ステートメントを「どのリソースに」適用するか。ARN形式。|
|Principal|「誰が」使うか。ARN形式。|
|Condition|セキュリティ強化のためのオプション。|


# 具体的には

[こちら](https://docs.aws.amazon.com/ja_jp/AmazonCloudWatch/latest/logs/S3ExportTasksConsole.html)のAWS公式に記されている、CloudWatch LogsからS3へエクスポートするためのバケットポリシーを例に取ってみます。

```
{
    "Version": "2012-10-17",
    "Statement": [
      {
          "Action": "s3:GetBucketAcl",
          "Effect": "Allow",
          "Resource": "arn:aws:s3:::my-exported-logs",
          "Principal": { "Service": "logs.us-west-2.amazonaws.com" }
      },
      {
          "Action": "s3:PutObject" ,
          "Effect": "Allow",
          "Resource": "arn:aws:s3:::my-exported-logs/random-string/*",
          "Condition": { "StringEquals": { "s3:x-amz-acl": "bucket-owner-full-control" } },
          "Principal": { "Service": "logs.us-west-2.amazonaws.com" }
      }
    ]
}
```

## Version

ポリシーの作成に使用される、ポリシー言語のバージョンを指定します。
ユーザーが作成したバケットポリシーのバージョニング指定ではありません。
指定できるバージョンは2種類のみ。

|バージョン|概要|
|:-----|:-----|
|2012-10-17|ポリシー言語の現行バージョン。ポリシー変数などの機能を利用できるのは、このバージョンのみ。|
|2008-10-17|ポリシー言語の旧バージョン。非推奨。|

現時点（2021.12）で、実質`2012-10-17`で固定です。

## Statement

ポリシーの主要要素。バケットポリシーの本体なので必須です。
`Statement`という記述自体は、あくまでこれ以降の要素のコンテナなので、これでなにかを指定するということはありません。
以下の記法によって、複数個のステートメントを含むことができます。

```
"Statement": [{...},{...},{...}]
```

例のバケットポリシーでは、2つのステートメントを記載していますね。

以降の要素は`Statement`の中身となります。

## Action

ポリシーで許可または拒否するアクションのリスト。

言い換えれば、「どのAWSサービス」の「どの操作」を「許可/拒否」するかの設定。
複数個指定することができます。

書き方は、

```
"Action(NotAction)":"サービス名（iam、ec2 sqs、sns、s3 など）:アクションの名前"

"Action": "s3:GetBucketAcl"
"Action": "s3:PutObject"
```

これを押さえれば、例の`Action`の意味も分かります。
`"Action": "s3:GetBucketAcl"`は、「S3バケットのアクセス制御リスト（ACL）を返すこと」を許可しています。
`"Action": "s3:PutObject" `は、「S3バケットにオブジェクトを追加すること」を許可しています。

アクセスのリストについては、各サービスの[APIリファレンスドキュメント](https://docs.aws.amazon.com/ja_jp/index.html)を参照。

とは言え、基本的なアクセス許可の設定についてはテンプレートが用意されているので、そちらを見た方が早いです。

>S3の場合
>[Amazon S3 のアクション](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/using-with-s3-actions.html#using-with-s3-actions-related-to-objects)


## Effect

必須要素。
ここで定義したステートメントの内容を、許可するか、拒否するかの指定。

`Allow` と `Deny`のどちらかで許可/拒否を指定します。

例の記載順に倣って`Action`の次に項目を書いていますが、`Effect`を先に置いた方が理解しやすいと思います。

`Action`との違いですが、

|要素|概要|
|:-----|:-----|
|Action|AWSサービスごとの許可/拒否の設定。|
|Effect|ステートメントそのものの許可/拒否の設定。|

例えば、
条件1：`Action`でS3へのアクセスを許可（Action）。
条件2：`Effect`で拒否（Deny）。
結果：S3へのアクセスは拒否される。

`Effect`>`Action`
という優先順位の解釈で、とりあえず間違いはないかと。

ちなみに、
拒否（Deny）>許可（Allow）
の優先順位です。
複数個のステートメントを書く際は個別に`Effect`を指定するので、頭に入れておくと良いかもしれません。

## Resource 

ステートメントで取り扱う一連のオブジェクトの指定。
言い換えれば、ステートメントを「どのリソースに」適用するかの指定。

`Resource` または `NotResource`要素を用います。
リソースの特定には、**ARN**形式を用います。

ARNとは、 「Amazonリソースネーム」のことです。AWS以外にも広く用いられるJSONとは異なり、ARNはAWS独自の記法です。

ARNの基本的な書き方は、

```
arn:partition:service:region:account-id:resource-id

arn:aws:s3:::my-exported-logs
arn:aws:s3:::my-exported-logs/random-string/*
```

|要素|概要|
|:-----|:-----|
|partition|リソースが置かれているパーティション。"aws"でほぼ固定。中国リージョンか GovCloud (US) リージョンを利用する場合は、書き方が変わる。|
|service|サービス名（iam、ec2 sqs、sns、s3 など）|
|region|リソースの置かれているリージョン（ap-northeast-1など）|
|account-id|リソースを所有しているアカウントのid。123456789012など、数字部分。 |
|resource-id|リソース識別子。リソースの名前、ID、リソースパスのいずれかを指定する。リソースパスには、ワイルドカードやアスタリスクを用いることも可能。|

例の場合、`my-exported-logs`が`resource-id`に当たります。

ARNの書き方を踏まえた上で、`Resource`の書き方は、

```
"Resource(NotResource)": "arn:partition:service:region:account-id:resource-id"
```

ご覧の通り、ほぼARNです。

ちなみに、バケットポリシーのような"リソースベース"のポリシーの場合、`Resource`はオプションです。この要素を書かなかった場合は、ポリシーがアタッチされているリソースに自動的にステートメントが適用されます。

## Principal

「誰が使うか」を指定する。
いわば、`Resource`要素で定義した「ステートメントを適用するリソース」を、「誰が使うか」という部分です。

` Principal`は、ユーザーベースポリシーにはない要素です。ユーザーベースポリシーはiamユーザーやiamロールに関連づけるため、操作主体をあえてポリシーで指定する必要がないからです。
対してリソースベースポリシーは、リソースに関連づけるため、操作主体を指定する必要があります。

`Resourece`と同じく、ARNを用いて記述しますが、書き方の種類が結構多いです。
>参考。記述方法が分類されています。
>[AWS JSON ポリシーの要素: Principal](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_principal.html)

例では、サービスロールを利用した"サービスプリンシパル"という書き方をしています。ユーザーではなく、サービスに操作が許可されるというイメージです。
困ったら、取りあえず例と同様の記載をしておけば大丈夫です。

```
"Principal": { "Service": "サービス名.リージョン名.amazonaws.com" }
```

## Condition

一言で言えば、オプションです。
色々できます。色々できるので、その分別途勉強した方がいいです。
取りあえずは「セキュリティ強化のための要素」程度の認識で大丈夫かと。

書き方は、

```
"Condition" : { "{condition-operator}" : { "{condition-key}" : "{condition-value}" }}

"Condition": {"StringEquals": {"s3:x-amz-acl": "bucket-owner-full-control"}}
```

|名称|概要|参考|
|:-----|:-----|:-----|
|condition-operator|条件演算子|[IAM JSON ポリシー要素: 条件演算子](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements_condition_operators.html)|
|condition-key|グローバル条件キーまたはサービス固有の条件キー|[AWS グローバル条件コンテキストキー](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_condition-keys.html)、[IAM および AWS STS の条件コンテキストキー](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_iam-condition-keys.html)|
|condition-value|値|[ポリシーの要素: 変数とタグ](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_variables.html)|

例では、
「S3オブジェクトのACL（s3:x-amz-acl）」が
「バケットのオーナーに設定（bucket-owner-full-control）」されている
「場合のみ（StringEquals）」
許可するよう書いています。

>例文の内容について詳しくは、
>[S3 のオブジェクトの所有権を使用したアップロードされたオブジェクトの所有権の管理](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/about-object-ownership.html)







# おわりに

間違いがあれば御指摘してくださると幸いです。


YAMLに対応してくれないかなぁ。

>参考
>[IAM JSON ポリシー要素のリファレンス](https://docs.aws.amazon.com/ja_jp/IAM/latest/UserGuide/reference_policies_elements.html)
>[Amazon リソースネーム (ARN)](https://docs.aws.amazon.com/ja_jp/general/latest/gr/aws-arns-and-namespaces.html)
>[S3のアクセスコントロールリスト(ACL)の基礎を学ぼう](https://dev.classmethod.jp/articles/amazon-s3-acl-basics/)