上級 30分 Lesson 7

S3セキュリティ — 「公開しちゃった」を二度と起こさない

S3のアクセス制御・暗号化・Object Lockを、事故事例から学ぶ講義形式の解説

AWS S3 SCS-C03 Security

S3の歴史から学ぶ「公開事故」

2023年、アメリカの大手調査会社が政府の個人情報をS3バケットに置いていて、誰でも読める設定になっていました。2024年、金融企業が顧客の支払い履歴を全部漏らした。やっぱりS3です。

S3の履歴は「公開事故の歴史」です。悲しいですけど本当。理由は簡単です。デフォルトが分かりづらい。バケット作るとき「プライベートにします」って選んでも、ポリシーで全世界許可をつけられたら意味がない。暗号化も「どっちでもいい」みたいな雰囲気。キーは誰が持つのか、削除したら復旧できるのか、曖昧なまま本番に行く。

だから今日は真面目に。S3を「セキュアに保つ」ための全ルールを、事故例と一緒に学びます。「S3は簡単」は幻想です。実は一番引っかかりやすいサービスの一つです。

Block Public Access——マスターキルスイッチ

まず最初にやること。これをやってない企業は、ぶっちゃけ管理してる側として失格です。Block Public Access(BPA)。S3アカウント全体、あるいはバケット単位で「公開アクセスを一切許さない」という絶対的なルール。どんなポリシーでもこれを越えられない。四つの設定があります。

「Block all public access」をONにすると、4つ全部ONになります。つまり「このバケット、全世界からのアクセスなし」。例外なし。これをアカウント全体に設定してください。本当に。本番アカウントなら全バケットに対してON。ローカルテスト以外は絶対にやってください。

「でもウェブサイトをホストしたいんですけど」。分かります。その場合はCloudFrontを前に置きます。S3はプライベートのままで、CloudFront経由なら誰でも見える、という構成。後で触れます。BPAは「最後の砦」です。ポリシー評価がこんがらがっても、BPAがONならブロック。保険みたいなもの。Block Public AccessをONにする。これはセキュリティの基本中の基本です。試験にも出ます。

バケットポリシー評価——複数ルールの交差地点

では、ポリシー。バケットポリシー、IAMポリシー、ACL。複数のポリシーが存在して、最終的に「許可」か「拒否」かが決まります。ここが複雑だから事故が起きるんです。

基本ルール。1つでも明示的な拒否(Explicit Deny)があったら、全てが拒否です。IAMポリシーで許可されていても、バケットポリシーで拒否されていたら、結果は拒否。次に明示的な拒否がなければ、少なくとも1つの許可があれば、結果は許可です。IAMポリシーで許可されていなくても、バケットポリシーで許可されていたら、許可。

つまり評価順序は、明示的拒否があるか(あったら拒否、終わり)、明示的許可があるか(あったら許可)、どちらもなければデフォルト拒否。このルールを頭に入れていないと「なぜかアクセスできない」という地獄が生まれます。

事例を一つ。あるチームがS3バケットを作った。IAMロールでEC2インスタンスに「S3のGetObjectを許可」と設定。でもバケットポリシーは空。結果、アクセス拒否。なぜか。バケットポリシーで許可されていないから。IAMでは許可でも、バケット側が許可していなければ、アクセスできない。両方許可する必要があるんです。これが試験に出ます。IAMポリシー AND バケットポリシー。両方OK じゃないと、アクセスできない。

アクセスポイント(後で出ます)を使うと、この複雑さが少し和らぎます。ポリシー委譲できるので。

暗号化——「誰が鍵を管理するか」で全て変わる

次。暗号化。これも引っかかりやすい。S3の暗号化は3種類です。

SSE-S3。S3が勝手に暗号化して、勝手に復号。鍵はAWSが管理。ユーザーは何もしない。無料。ただし「AWSが鍵を持ってる」ということです。例えばFBIが「鍵を渡せ」と来たら、AWSは渡す可能性がある。コンプライアンスが必要な環境では、これは許されません。

SSE-KMS。KMS(Key Management Service)で鍵を管理。ユーザーが「どの鍵で暗号化するか」を指定。鍵のポリシーで「誰がこの鍵を使えるか」を細かく制御。トレーサビリティあり。CloudTrailで「誰が何の鍵を使った」が分かる。少し遅い(KMS APIコール必要)。

SSE-C。ユーザーが鍵を提供。S3は鍵を保存しない。ユーザー(アプリケーション)が鍵を管理。「鍵は絶対にAWSに預けたくない」という企業向けです。

個人的には本番環境ならSSE-KMS一択です。理由はトレーサビリティです。「いつ、誰が、どのデータにアクセスした」がCloudTrailに残る。HIPAA(医療関連)、PCI-DSS(カード決済)などのコンプライアンスでも要求されます。SSE-S3は簡単だけど監査が難しい。誰が何にアクセスしたのか、トレースしづらい。本番には不安です。試験でも出ます。本番ならSSE-KMS。鍵をAWSに預ける代わりに、トレーサビリティを得ます。

Object Lock——「金庫に入れたら誰も開けられない」

さあ、次のレベル。Object Lock。通常S3のオブジェクトは削除できます。バージョニング有効でも、オーナーならDeleteを実行できる。だけど「どうしても削除させたくない」という要件がある。金融記録、医療記録、訴訟関係の証拠。こういうのは「7年保存しなきゃいけない、その間は絶対削除禁止」。

Object Lockです。オブジェクト毎に「いつまで削除禁止」というタイムスタンプを設定。期限まで誰も(IAM管理者でも、ルートユーザーでも)削除できない。二つのモードがあります。

Governance Mode。ロック期間中は削除禁止。ただし「s3:BypassGovernanceRetention」権限を持つユーザーは、強制的にロック解除できる。つまり管理者なら最終的には削除可能。企業内の「どうしても必要になったら管理者が決定」という流れに対応。

Compliance Mode。ロック期間中は誰も何も削除できない。管理者も、ルートユーザーも。期間が終わるまで待つしかない。WORM(Write Once Read Many)。法的要件が厳しい業界向けです。ここが重要なんですがCompliance Modeで7年ロックしたら、7年間本当に削除できません。管理ミスで不要なデータを7年保管する羽目になる。設定前に何度も確認。試験に出ます。Object Lockは「削除禁止」を時間軸で保証。法的要件がある業界の必須機能です。

MFA Delete——最後の防波堤

Compliance Modeと組み合わせて使うのがMFA Delete。バージョニング有効なバケットでMFA DeleteをONにする。そうするとオブジェクトを削除するには、物理的なMFAデバイス(ハードウェアキー、スマートフォンの認証アプリ)で確認が必要です。つまり攻撃者がAWSの管理画面を乗っ取っても、MFAデバイスがなければ削除できない。二要素認証の最終形です。

MFA Deleteはルートユーザーのアクセスキーとシリアル番号付きMFAデバイスでのみ設定できます。IAMでは不可。つまりかなり管理が限定される。これはセキュリティの観点からは良い。ただし「ルートユーザーのキーを生成する」ことになるので、他の箇所では使わない。MFA Delete設定専用のキー。保管も慎重に。

アクセスポイント——ポリシー複雑性からの解放

ここまでで、ポリシー評価の複雑さに疲れていると思います。大丈夫です。Access Pointを使えば、ぐっと簡潔になります。アクセスポイントはバケットの「玄関」です。「このアクセスポイント経由でのアクセスは、このポリシーで制御」と決める。複数アクセスポイント作れば、アプリケーション毎、ユーザー毎に異なるルールを適用できます。

例えば。同じバケット内でも、「写真アプリケーション」用のアクセスポイントなら、画像のみGetObject許可。「ログ集約」用のアクセスポイントなら、ログオブジェクトのみ。きれいに分離できる。バケットポリシーは統一ルール。アクセスポイントポリシーは個別ルール。推奨は、バケットポリシーで「全拒否」にして、アクセスポイント毎に「許可」。こうするとシンプルです。

Multi-Region Access Pointを使うと、複数リージョンのアクセスポイントを一つのDNS名で統合。地理的な冗長性も実現。アクセスポイント=バケットの複数の玄関。ポリシーを分散管理できます。

Macie——自動で秘密情報を嗅ぎ出す

ここからは検出のフェーズ。あなたのバケット。何百万のオブジェクトがある。その中に、うっかり顧客のクレジットカード番号が含まれたファイルがあるとしたら。気付きますか。人間じゃ無理です。Amazon Macieです。機械学習使ってS3内の「秘密情報」を自動検出。クレジットカード番号、社会保障番号(SSN)、APIキー、プライベートキー。

設定は簡単。「S3スキャンを有効にする」。Macieが勝手に全バケットをスキャン。怪しいオブジェクト見つけたら、EventBridge経由で通知。SNSでSlackに送信、とか。Macie自体は無料だけど、スキャンはオブジェクト単位で課金。大規模バケットだと月数十万の課金になることもある。その場合は「本当に秘密情報が漏れてないか」の監査的スキャンだけに絞る。CloudTrailで「誰が何にアクセスした」を見つつ、Macieで「秘密情報はないか」を見る。二つの目で検視。Macie=自動秘密検出。監査的スキャンで、漏らした情報の発見を自動化。

CloudFrontとの組み合わせ——ウェブサイト公開の正解

ここで「S3でウェブサイト公開したいんですけど」という話に戻ります。昔のやり方。S3で「ウェブサイトホスティング」を有効にして、バケットポリシーで「全世界許可」。すると誰でもアクセス可能。これ脆弱性の塊です。誰もが直接S3APIにアクセスできるからレート制限なし。悪質なボットが大量アクセスして、料金が跳ね上がる。

正解はCloudFront前置です。S3はBlock Public Accessで完全プライベート。CloudFrontだけがS3に「背面」でアクセス。ユーザーはCloudFront経由でのみ見える。CloudFrontはキャッシュ層になるし、DDoS防御も入るし(Shield Standard)、WAFも付けられます。設定は、S3バケット作成(全プライベート)、CloudFrontディストリビューション作成、OriginとしてS3指定、Origin Access Identity(OAI)でS3へのアクセス制限。すると CloudFrontからのアクセスだけ許可。publicには見えない。完璧です。S3でウェブ公開するなら CloudFront前置が鉄則。直接アクセス許可は避けます。

よくある事故パターン——これは避けろ

最後に実際の事故例です。パターン1は「IAMポリシーで許可、バケットポリシーで拒否」。IAMでは「S3GetObject許可」だけど、バケットポリシーが空。結果、アクセス拒否。IAMとバケット、両方確認するクセをつけてください。

パターン2は「ワイルドカード無視」。バケットポリシーで「Effect: Allow, Principal: *」。つまり誰でもアクセス可能。本当によくある。BPAで防ぎましょう。これで防げます。

パターン3は「暗号化鍵の管理忘れ」。SSE-KMSで暗号化したけど、KMSキーのポリシーを整備していない。KMSキーのデフォルトポリシーは「ルートユーザーのみアクセス可能」。つまりIAMユーザーは暗号化オブジェクトにアクセスできない。KMSキーポリシーで「このロールは鍵を使用可能」と書く必要があります。これよく落ちます。

パターン4は「バージョニング有効だけど削除防止なし」。バージョニング有効で「過去のバージョンなら復旧可能」と思ってる。でもオブジェクトロック設定していないなら、全バージョン削除可能。オブジェクトロック設定するか、少なくともMFA Deleteで保護。

パターン5は「Macieスキャン忘れ」。秘密情報が混在してるか、誰も確認していない。本番バケットなら、Macieは必須。少なくとも月1回のスポットスキャン。事故の9割は「設定漏れ」です。チェックリスト必須。

S3セキュリティのチェックリスト

本番環境を立ち上げるなら、これを全部確認してください。Block Public Accessは全てONか。バケットポリシーは定義されているか(IAMポリシーだけじゃないか)。暗号化はSSE-KMSか(キーのポリシーは設定されたか)。機密データは含まれるか(Macieでスキャンしたか)。ウェブ公開ならCloudFront前置か(S3直接公開ではないか)。

バージョニング有効か(重要ファイルなら Object Lockで保護されているか)。CloudTrailで全APIをログしているか(定期的に確認しているか)。アクセスパターンは明確か(複数のアクセスポイントを使い分けているか)。全部「はい」なら、かなり安全です。

明日からS3に触るなら、この習慣をつけてください。簡単に見えるサービスほど、落とし穴が深い。では次は WAFとShield です。Webアプリケーションレイヤーの防御を見ていきましょう。