S3 入門 — バケットポリシーとアクセス制御を理解する

概要

Amazon S3 はシンプルに見えて、アクセス制御の仕組みが複数レイヤーに分かれているため、入門者がつまずきやすいサービスです。「意図せず公開してしまった」「正しく設定したつもりがアクセスできない」といった事故の多くは、各制御レイヤーの関係を理解していないことに起因します。

本記事では、S3 のアクセス制御を構成する以下の要素を整理し、実際のポリシー例とともに最小権限での設計方針を解説します。

  • IAM ポリシー(ユーザー・ロール側)
  • バケットポリシー(リソース側)
  • ブロックパブリックアクセス
  • ACL(レガシー)

掲載するポリシーは公開ドキュメントに基づく一般例であり、特定の本番構成を示すものではありません。

S3 のアクセス制御は「複数レイヤーの合成」で決まる

S3 へのリクエストが許可されるかは、複数の制御を合成した結果で決まります。

レイヤー 誰が設定するか 役割
IAM ポリシー リクエスト元(ユーザー/ロール)側 このプリンシパルは何ができるか
バケットポリシー リソース(バケット)側 このバケットに誰が何をできるか
ブロックパブリックアクセス バケット/アカウント 公開設定の最終防波堤
ACL バケット/オブジェクト レガシー。原則無効化推奨

基本原則は次の2つです。

  1. 明示的な Deny が1つでもあれば拒否(Deny が最優先)
  2. Deny が無い場合、IAM かバケットポリシーの いずれか で Allow されていればアクセス可(同一アカウント内)

この「Deny 優先」「Allow はいずれかで足りる」という評価ルールが、入門時に最も誤解されやすいポイントです。

IAM ポリシーとバケットポリシーの違い

  • IAM ポリシー: 主語はプリンシパル。「このユーザー/ロールが操作できる対象」を定義する。
  • バケットポリシー: 主語はリソース。Principal を明示でき、クロスアカウントや条件付き制御を表現できる。

IAM ポリシーの例(特定バケットへの読み書き)

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "ListTheBucket",
      "Effect": "Allow",
      "Action": "s3:ListBucket",
      "Resource": "arn:aws:s3:::example-bucket"
    },
    {
      "Sid": "ReadWriteObjects",
      "Effect": "Allow",
      "Action": ["s3:GetObject", "s3:PutObject"],
      "Resource": "arn:aws:s3:::example-bucket/*"
    }
  ]
}

ここで重要なのは、バケット ARN(arn:aws:s3:::example-bucket)とオブジェクト ARN(.../*)を区別する 点です。ListBucket はバケットに対するアクション、GetObject/PutObject はオブジェクトに対するアクションなので Resource の指定が異なります。混同すると「一覧は取れるがダウンロードできない」といった事象が起きます。

バケットポリシーの実例

例1: HTTPS 通信以外を拒否する

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyInsecureTransport",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::example-bucket",
        "arn:aws:s3:::example-bucket/*"
      ],
      "Condition": {
        "Bool": { "aws:SecureTransport": "false" }
      }
    }
  ]
}

Deny と Condition を組み合わせ、「非 SSL 通信だけを拒否する」という条件付き Deny を表現しています。Deny は最優先なので、他で Allow されていても条件に合致すれば拒否されます。

例2: 特定の VPC エンドポイント経由のみ許可する

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Sid": "DenyUnlessFromVpce",
      "Effect": "Deny",
      "Principal": "*",
      "Action": "s3:*",
      "Resource": [
        "arn:aws:s3:::example-bucket",
        "arn:aws:s3:::example-bucket/*"
      ],
      "Condition": {
        "StringNotEquals": {
          "aws:sourceVpce": "vpce-xxxxxxxx"
        }
      }
    }
  ]
}

Allow のホワイトリストより、Deny + StringNotEquals の除外条件で書くほうが抜け漏れが起きにくくなります。

ブロックパブリックアクセスは「最後の砦」

意図しない公開を防ぐのが ブロックパブリックアクセス(Block Public Access) です。4つの設定からなります。

設定 内容
BlockPublicAcls 公開 ACL の付与を拒否
IgnorePublicAcls 既存の公開 ACL を無視
BlockPublicPolicy 公開バケットポリシーの設定を拒否
RestrictPublicBuckets 公開ポリシーがあってもアクセスを制限

特段の理由がなければ、アカウントレベル・バケットレベルの両方で全て有効にするのが基本方針です。

aws s3api put-public-access-block \
  --bucket example-bucket \
  --public-access-block-configuration \
  BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true

静的サイトホスティングなどで公開が必要な場合でも、まず「CloudFront + OAC(Origin Access Control)経由にして、バケット自体は非公開のまま」という構成を検討するのが安全です。

確認方法

# 一覧取得・オブジェクト取得(許可されるべき操作)
aws s3 ls s3://example-bucket/
aws s3 cp s3://example-bucket/sample.txt ./sample.txt

# 公開状態の確認
aws s3api get-public-access-block --bucket example-bucket
aws s3api get-bucket-policy-status --bucket example-bucket   # IsPublic: false を確認

アクセスできるべきでないケースで AccessDenied が返ること、できるべきケースで成功することの 両方 を確認します。「拒否されるべきものが拒否される確認」まで行うのが、アクセス制御検証の勘所です。

注意点

  • Deny は最優先。Allow を足しても Deny があれば通らない。トラブル時はまず Deny を疑う。
  • ListBucket と GetObject で Resource が異なる。バケット ARN とオブジェクト ARN(/*)を取り違えない。
  • ACL は原則使わない。「Bucket owner enforced」を有効化し ACL を無効にするのが推奨。
  • 公開が必要でも、まず CloudFront + OAC を検討。バケット直公開は最終手段。
  • 本番ではまず読み取り権限から。書き込み・削除は影響範囲を確認してから付与する。

まとめ

S3 のアクセス制御は、IAM ポリシー(誰が)・バケットポリシー(このバケットに誰が・どの条件で)・ブロックパブリックアクセス(公開の最終防波堤)という複数レイヤーの合成で決まります。「Deny 優先・Allow はいずれかで足りる」という評価ルールと、「ListBucket と GetObject の Resource の違い」を押さえるだけで、入門時のつまずきの大半は回避できます。最小権限を基本に、公開は BPA で守りつつ必要なら CloudFront 経由で、という設計を習慣化しましょう。

\ 最新情報をチェック /

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください。