AWS S3バケットに保管するデータの削除保護を実装する

# はじめに
AWSのS3バケット内のデータ (オブジェクト) は、何かしらの目的を持って保管されていますので、情報漏洩などのセキュリティリスクからの保護だけでなく、運用時の誤削除からも保護する必要があります。

本記事では基本的な権限管理の考え方と、どのようにして誤削除から守るのかを記載します。

# S3を取り巻くアクセス権限管理
AWSのS3バケットに関連するアクセス権限は、主に次の5箇所の設定で制御できます。
* IAMポリシー
* S3アクセスコントロールポリシー (ACL)
* S3バケットポリシー
* S3オブジェクトタグ
* S3アクセスポイント

本記事では、最も基本に立ち返り、IAMポリシーとS3バケットポリシーについて記述します。

## IAMポリシーとS3バケットポリシーの違い
ここで、どちらもJSONで書くことは分かっているものの、何をどのように制御するためのものなのか混乱しやすい、IAMポリシーとS3バケットポリシーの違いを見ていきます。
これらを比較すると、様々なドキュメントでは同じ **ACL** という言葉で表現されているものですが、制御するアクセスの矢印が、両者で真逆であることが分かります。

* IAMポリシー
    * ユーザーなどのエンティティに対して許可する **アクセス先と操作** を制御する
        * 全てのAWSサービスに対する操作を制御する
    * デフォルトでは全ての操作が拒否されている
        * 必要な操作だけを許可する

* S3バケットポリシー
    * S3バケットが受け入れる **アクセス元と操作** を制御する
    * IAMロールを必要とせずにクロスアカウントアクセスを制御する
        * 参考: [Example 2: Bucket owner granting cross-account bucket permissions](https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-walkthroughs-managing-access-example2.html)
    * デフォルトでプライベート (パブリックアクセス不可)

## ポリシーの基本
理解を容易にするため、以下のポリシーを参考にして見ていきます。
以下はS3バケットポリシーのサンプルです。

```json:sample01
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "statement1",
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::AccountB-ID:user/Dave"
      },
      "Action": "s3:PutObject",
      "Resource": "arn:aws:s3:::awsexamplebucket1/*",
      "Condition": {
        "StringEquals": {
          "s3:x-amz-grant-full-control": "id=AccountA-CanonicalUserID"
        }
      }
    }
  ]
}
```

引用: [Amazon S3 条件キーの例](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/amazon-s3-policy-keys.html)

この後の理解を容易にするため、各項目の意味をおさらいします。

* Statement
    * リストになっており、複数のアクセス制御の集合体です。
* Effect
    * Allow (許可) または Deny (拒否) です。
    * 常にDenyと書いたアクセス制御が優先されます。
* Principal
    * AllowまたはDenyするエンティティです。
* Action
    * AllowまたはDenyする操作です。
* Resource
    * Actionが行われる対象のリソースです。
* Condition
    * この定義されたアクセス制御が有効と判定される条件です。

S3バケットポリシーの場合 **自らに対して行われるアクセスの制限** をします。
IAMポリシーの場合、アタッチされた **エンティティが行うアクセスの制限** をします。

繰り返しになりますが、それぞれのポリシーで表現される **アクセスの方向 (矢印) は真逆** です。
これこそが、**[別の記事](https://qiita.com/nasuvitz/items/ba1ab421a67beaccebec#%E8%A9%B3%E7%B4%B0-aws%E3%81%AB%E3%81%8A%E3%81%91%E3%82%8B%E3%83%9D%E3%83%AA%E3%82%B7%E3%83%BC%E3%81%AE%E7%A8%AE%E9%A1%9E%E3%81%A8%E3%81%AF)** で書いたポリシーのカテゴリの違いであり、IDポリシーであるIAMポリシーと、リソースポリシーであるS3バケットポリシーでは、定義するアクセス制御の方向が異なります。

両方のポリシーが意図するものとなっていない場合、誤削除を含む意図しないアクセスが実行される可能性があります。

# 誤削除を防ぐアクセス制限の大原則
それではIAMポリシーとS3バケットポリシーの両方で、どのように制限すれば誤削除を防ぐことができるのかを考えていきます。

## IAMポリシー
最も基本的な原則は、以下となります。
* **AllowするActionを、AWSの管理ポリシーである 「AmazonS3ReadOnlyAccess」 に限定します。**
    * **この時点で少なくとも削除できなくなります。**
    * Access Denied になります。

つまり 「S3オブジェクトを削除されないようにしたい」 という要件が登場した瞬間に、とりあえずでもIAMポリシーで許可するS3のActionを 「AmazonS3ReadOnlyAccess」 に限定すれば、誤削除は防げます。

基本中の基本のことですが、これだけを覚えておくだけでも安心できます。

## S3バケットポリシー
最も基本的な原則は、以下となります。

* **全てのPrincipalからの `s3:DeleteObject` をDenyします。**
    * **この時点で少なくとも削除できなくなります。**
    * Access Denied になります。

```json:sample02
{
  "Id": "Policy1645848096658",
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "Stmt1645848092234",
      "Principal": "*",
      "Action": [
        "s3:DeleteObject"
      ],
      "Effect": "Deny",
      "Resource": "arn:aws:s3:::awsexamplebucket1/*"
    }
  ]
}
```


つまり 「S3オブジェクトを削除されないようにしたい」 という要件が登場した瞬間に、とりあえずでもS3バケットポリシーで上記のポリシーを書いてしまえば、誤削除は防げます。

基本中の基本のことですが、これだけを覚えておくだけでも安心できます。


## (参考) アクセス制御の判定フロー
IAMポリシーとS3バケットポリシーの両方で、どう誤削除からオブジェクトを保護するのかについて記載しました。

ここで、そもそもIAMポリシーとS3バケットポリシーはどのようにして評価され、最終的にアクセスがAllowまたはDenyされるのかについて振り返ってみます。
下の図は、2013年にAWSの公式ブログに掲載された、最も基本的なフローです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/b85290f8-825b-61b7-7e27-70f6c3600875.png)
引用: [IAM Policies and Bucket Policies and ACLs! Oh, My! (Controlling Access to S3 Resources)](https://aws.amazon.com/jp/blogs/security/iam-policies-and-bucket-policies-and-acls-oh-my-controlling-access-to-s3-resources/)

上記フローの(2)で、IAMポリシーとS3バケットポリシーが評価されます。
評価の結果、(3)でDenyがあればその時点でDeny、Denyが無いものは(4)でAllowがあればその時点でAllow、Allowも無いものは(5)でDenyとなります。

IAMポリシーの「AmazonS3ReadOnlyAccess」は読み取り制限ではありますが、Allowしている範囲が広めのポリシーです。
繰り返しになりますが、Denyが優先されますので、「AmazonS3ReadOnlyAccess」に記載されたActionの中で拒否したいものを個別にDenyすれば、Allowする範囲を狭めることができます。

なお(2)ではIAMポリシーとS3バケットポリシーの他、VPCエンドポイントポリシーとS3オブジェクトACLも評価の対象となりますが、本記事では割愛します。

# 誤削除を防ぐS3バケットの設定
次に、アクセス権限以外の観点でS3オブジェクトの誤削除を防止する方法を記載します。

## S3オブジェクトのバージョニング
これも最も基本なことですが、バージョニングを設定すれば、S3オブジェクトがアップロードされた時に、現バージョンが単純に上書きされて消失してしまうことを防げます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/7dcbd3c9-5463-e614-6f9d-dada38899474.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/211986/c4b7b09d-6212-ef71-e226-32fc72e1700f.png)
引用: [S3 バージョニングの仕組み](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/versioning-workflows.html)


# まとめ
2022年現在、AWSにはService Control Policy、IAM Permission Boundary、S3オブジェクトロックなど、広い範囲をターゲットにしたアクセス制限が登場しており、何をどうすれば良いか分からないと悩まれている方も多いと思います。
紹介した内容は本当に基本的なことばかりですが、ここに記載した設定を行うだけでもS3オブジェクトの誤削除から守ることができます。

今はアクセス制限を行うために様々な機能があり、あれもこれもと手を出していきたくなりますが、まずは基本的なことができているかを確認することが最善です。

# 参考文献
*  [Example 2: Bucket owner granting cross-account bucket permissions](https://docs.aws.amazon.com/AmazonS3/latest/userguide/example-walkthroughs-managing-access-example2.html)
* [Amazon S3 条件キーの例](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/amazon-s3-policy-keys.html)
* [IAM Policies and Bucket Policies and ACLs! Oh, My! (Controlling Access to S3 Resources)](https://aws.amazon.com/jp/blogs/security/iam-policies-and-bucket-policies-and-acls-oh-my-controlling-access-to-s3-resources/)
* [S3 バージョニングの仕組み](https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/versioning-workflows.html)