株式会社クイックのWebサービス開発blog

HAPPYなエンジニア&デザイナーのブログです

【AWS S3】S3 bucket policy を使ったアクセス制限方法 ~Effectの評価優先度を考える~

こんにちは。クイックSREチームのみっちーです。
今日は、S3のbucket policy についての記事です。

前回の記事で「S3 bucket policy」については少し触れましたが、今回はもう少し内容を掘り下げていこうと思います。
おまけで、いくつかサンプル設定も載せたので、ぜひ最後まで読んでみて下さい✧(・ㅂ・)و

今回の記事は、こんな人向けです。

  • 「これからS3にアクセス制限を実施しよう!」と思っている人。

  • 「S3 bucket policy が意図した動作をしてくれない」と嘆いている人。

  • 「とりあえずサンプルが欲しい」と思っている人。

目次

1. S3で出来るアクセス制限の方法(種類)

2. bucket policy の書き方

3. bucket policyのサンプル

1. S3で出来るアクセス制限の方法(種類)

bucket policyの話に入る前に、
まずはS3で出来る「アクセス制限の方法(種類)」についてのおさらいです。
S3では大きく分けて、以下の3種類の方法でアクセス制限をする事ができます。

それぞれの設定は独立していて、併用が可能です。

S3 bucket policy を利用した方法 ※ 今回はこれについての説明です

  • bucketのアクセス「ルール」を細かく記載する。
  • JSON形式で記載。

メリット

  • 「特定IPアドレスのみ許可」 したり、 「特定アカウントと特定IPのみを許可」 と言った、やや複雑なルールも書ける。

デメリット

  • 「ルール」の評価優先度にクセがある(詳細は後述)ため、慣れるまでは扱いが難しい。

    ACL(Access Control List) を利用した方法

  • bucketにアクセスできる「ユーザ」を設定する。
    「特定アカウントのみ許可」 や、 「全ユーザ公開(public read)」 など。

メリット

  • 設定が簡単。
    管理コンソールから、「アカウント名と、許可する動作にチェックを入れるだけ」でOK。

デメリット

  • 設定が簡単な反面、単純な設定しか出来ない。

    IAM を利用した方法

  • aws IAMサービスを利用してアクセス制限をする。
  • bucketにアクセスできる「IAMユーザ」を設定する。
  • JSON形式で記載。

メリット

  • 異なるアカウント管理下にあるS3 bucketを参照したりする設定が出来る。
  • IAMの書き方がS3 bucket policyとほぼ同じで、どちらかを覚えれば応用が効く。

デメリット

  • IAMの使い方を覚える必要がある。
  • 通常、S3上のオブジェクトを公開するだけなら使う必要はない。

2. bucket policy の書き方

「ルール(Effect)」と「評価優先度」

S3 bucket policyは、「評価優先度の異なる3つのルール(Effect)」を組み合わせてアクセス制限を実装します。
この「評価優先度」の部分にクセがあるため、扱いにくいと感じる方もいるかと思います。

ポイントは3つ!!!

  • より「評価優先度」の高いルール(Effect)が適用される。

  • 適用されたルール(Effect)よりも「評価優先度」が低いルール(Effect)は、破棄(非適用)される。

  • 前述の「評価優先度」により、「ルール(Effect)」の記載順序は無関係であること。
    ※上の方に書いたから優先になる訳ではない。

S3 bucket policy が解釈できる「ルール(Effect)」の種類

Clearly Deny

  • 評価優先度:高
  • これは「Deny」だよ、と明記する場合。
  • 評価優先度「中」以下のEffectよりも優先適用される。

Clearly Allow

  • 評価優先度:中
  • これは「Allow」だよ、と明記する場合。
  • 評価優先度「低」のEffectよりも優先適用される。

Default Deny

  • 評価優先度:低
  • 特に「Deny」も「Allow」も記載されていない箇所に対して、default で適用されるEffect。



3. bucket policyのサンプル

文章だけだと分かりにくいので、実際にサンプル設定を使って説明をしていきます。
なおここに載せてあるサンプル設定は、必ず検証してから自己責任でご利用ください。

サンプル01 :
「特定のIPアドレス」からのみアクセス許可したい。

解説

この場合は、「Clearly Allow」と「Default Deny」を使用します。

まずは、以下のように「Effect」に「Allow」と記載します。※「Clearly Allow」

  {
            "Sid": "Allow-from-specific-IP-only",  ← 分かればなんでも良いです。
            "Effect": "Allow",   ←「Allow」を記載します。
            "Principal": {
                "AWS": "*"
            },

続けて、「Condition」の項目で許可したいIPアドレスを記載すればOKです。

            "Action": "s3:GetObject",   ← 閲覧権限のみを付与。
            "Resource": "arn:aws:s3:::<your S3 bucket name>/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "xxx.xxx.xxx.xxx/yy",  ← アクセス元のIPをCIDR形式で記載します。
                        "xxx.xxx.xxx.xxx/yy"   ← 複数書くときは、","で区切って記載します。
                    ]
                }
            }
 }

ここに記載の無いIPアドレスについては、
条件不一致 =「Default Deny」として処理されます。


サンプル01 の設定まとめ

この設定は、まとめると以下のような形になります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Allow-from-specific-IP-only",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<your S3 bucket name>/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "xxx.xxx.xxx.xxx/yy",
                        "xxx.xxx.xxx.xxx/yy"
                    ]
                }
            }
        }
    ]
}

備考

他にも、以下のように「Clearly Deny」でこのIP以外は拒否という形でもOKです。
ただしこの場合は、「Clearly Allow」と組合せることが出来ない(Clearly Denyが優先され、Clearly Allowは破棄される)ので、拡張性に乏しくなります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Allow-from-specific-IP-only",
            "Effect": "Deny",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<your S3 bucket name>/*",
            "Condition": {
                "NotIpAddress": {    ←「指定IP以外を拒否する」
                    "aws:SourceIp": [
                        "xxx.xxx.xxx.xxx/yy",
                        "xxx.xxx.xxx.xxx/yy"
                    ]
                }
            }
        }
    ]
}



サンプル02 :
「特定のIPアドレス」と「CloudFront」からのアクセスのみ許可したい。

解説

この場合も、「Clearly Allow」と「Default Deny」を使用します。
ポイントは、「Clearly Allow」を2つ使うことです。
「Clearly Allow」は複数束ねると「OR条件」として使えます。

先程と同様に、まずは「Clearly Allow」で許可したいIPアドレスを記載します。
次に、同じく「Clearly Allow」で、CloudFrontのOrigin Access Identityを記載します。

  {
            "Sid": "Allow-from-specific-IP-only",  
            "Effect": "Allow",   
            "Principal": {
                "AWS": "*"
            },
・・・略)

 {
            "Sid": "Allow-from-CloudFront",
            "Effect": "Allow",  
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <your CloudFront Origin-Access-Identity>"   ←これは別途CloudFrontを操作してIDの取得をしてください。
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<your S3 bucket name>/*"
        }

こうすることで、Allow の OR条件として判定されます。
そして最後に、上記にマッチしないアクセス全てを「Default Deny」で拒否します。

注意点としては、「Clearly Deny」でIP制限を書かないことです。
理由は「Clearly Deny」の優先度が最も高いため、指定したIP以外はアクセスできなくなるからです。

サンプル02 の設定まとめ

{
    "Version": "2012-10-17",
    "Statement": [
  {
            "Sid": "Allow-from-specific-IP-only",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<your S3 bucket name>/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "xxx.xxx.xxx.xxx/yy",
                        "xxx.xxx.xxx.xxx/yy"
                    ]
                }
            }
        },
        {
            "Sid": "Allow-from-CloudFront",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <your CloudFront Origin-Access-Identity>"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<your S3 bucket name>/*"
        }
    ]
}



サンプル03 :
「特定のIPアドレス」と「CloundFront」および「AWS CLI」からのみアクセス許可したい。

解説

サンプル02の条件に加えて、「AWS CLI ※」での操作を可能とする設定です。
※ ”aws s3 sync” コマンド等のことです。

S3の閲覧やオブジェクトのダウンロードは、通常はブラウザ経由が多いと思いますが、
AWS CLIを利用してオブジェクトコピーをしたりする開発者は多いと思います。
そういう場合に、AWS CLIでの操作だけはS3の全権限を付与した設定のサンプルです。

{
            "Sid": "Allow-full-control-for-API",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<your account No>:<user name>"
            },
            "Action": "s3:*",   ←S3の全操作権限を付与
            "Resource": [
                "arn:aws:s3:::<your S3 bucket name>/*",
                "arn:aws:s3:::<your S3 bucket name>"
            ]
        }

これも基本はさっきと同じで、
「Clearly Allow」で許可したい条件を記載し、それ以外はDefaultDenyで拒否しています。

サンプル03 の設定まとめ

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Allow-from-CloudFront",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity <your CloudFront Origin-Access-Identity>"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<your S3 bucket name>/*"
        },
        {
            "Sid": "Allow-from-specific-IP-only",
            "Effect": "Allow",
            "Principal": {
                "AWS": "*"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<your S3 bucket name>/*",
            "Condition": {
                "IpAddress": {
                    "aws:SourceIp": [
                        "xxx.xxx.xxx.xxx/yy",
                        "xxx.xxx.xxx.xxx/yy"
                    ]
                }
            }
        },
        {
            "Sid": "Allow-full-control-for-API",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::<your account No>:<user name>"
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::<your S3 bucket name>/*",
                "arn:aws:s3:::<your S3 bucket name>"
            ]
        }
    ]
}



いかがでしたか。

S3 bucket policyの設定がうまく行かなくて悩んでいる方の助力になれば幸いです。
今後もAWS関連の記事を書いていこうと思っているので、興味を持って頂けたらぜひまた読んでみて下さい!

それでは~ (・о・) /

この記事のトップへ戻る