リソースポリシーでバケットを保護する

AWSBeginner
オンラインで実践に進む

はじめに

バケットの所有者は、一つのレポート用ロールにアクセスを与え、非公開データを保護したいと考えています。バケットポリシーを設定し、ロール自身のポリシーと比較して、一致する Deny がアクセスに与える影響をテストします。

最初に IAM ロールで一時認証情報を使う と レポートの読み取り役に最小権限を与える を完了してください。この新しい VM は default、report-role、other-role を提供します。ロールプロファイルは既に一時セッションを取得できます。/home/labex/project と AWS View を使ってください。認証情報とキャッシュは非公開に保ってください。

認定試験との関連

認定資格 試験タスク 演習内容
Cloud Practitioner (CLF-C02) タスク 2.3 リソースポリシーと明示的な拒否の優先規則。
Solutions Architect – Associate (SAA-C03) タスク 1.1 リソースポリシーと明示的な拒否の優先規則。
Developer – Associate (DVA-C02) タスク 2.1 リソースポリシーと明示的な拒否の優先規則。
CloudOps Engineer – Associate (SOA-C03) タスク 4.1 リソースポリシーと明示的な拒否の優先規則。
Security – Specialty (SCS-C03) タスク 4.2 基礎演習:リソースポリシーと明示的な拒否の優先規則。
Data Engineer – Associate (DEA-C01) タスク 4.2 基礎演習:リソースポリシーと明示的な拒否の優先規則。
DevOps Engineer – Professional (DOP-C02) タスク 6.1 基礎演習:リソースポリシーと明示的な拒否の優先規則。
Solutions Architect – Professional (SAP-C02) タスク 2.3 基礎演習:リソースポリシーと明示的な拒否の優先規則。

ラボの概要

概念図:同一アカウントのレポートリクエストについて、ロールのアイデンティティポリシーと S3 バケットポリシーを比較します。一致する明示的な Deny は Allow より優先されます。

バケットから一つのロールにアクセスを与える

このステップでは、ReportReader に reports プレフィックスへのアクセスを与えるリソースポリシーを設定します。アイデンティティポリシーと異なり、バケットポリシーは Principal を指定する必要があります。ロールを識別する IAM ロール ARN を使ってください。assumed-role セッションの ARN は、その一回の使用を識別します。

これまではアイデンティティ側からアクセスを許可しました。今度はバケット所有者がリソース側から許可します。二つのロールプロファイルは準備済みなので、信頼は変更せず、バケットポリシーとロールの権限ポリシーが同じリクエストにどう影響するかに集中します。

リソースポリシーは、リソースに保存されます。S3 のバケットポリシーはその一例です。Principal は、ステートメントが誰のリクエストを対象にするかを識別します。ユーザーやロールに保存されるアイデンティティポリシーと比較してください。

二つの有効なセッションのアイデンティティと、最初は空であるレポート用ロールの権限ポリシー一覧を確認します。

cd /home/labex/project
aws sts get-caller-identity --profile report-role --query Arn --output text
aws sts get-caller-identity --profile other-role --query Arn --output text
aws iam list-role-policies --role-name ReportReader

assumed-role/ReportReader/report-run と assumed-role/OtherReader/other-run、および空の PolicyNames 一覧を想定します。ロールとして認証されること自体は、S3 アクセスを認可しません。現在の読み取りをテストします。

aws s3api get-object --profile report-role --bucket labex-iam04-reports --key reports/today.txt before.txt || true

AccessDenied を想定します。|| true は、想定した失敗で貼り付けたコマンド列が停止しないようにします。接続失敗では拒否を証明できません。

バケットポリシーを書きます。GetObject はオブジェクトの読み取りを許可し、Resource はこの一つのバケットの reports/ に限定します。ロールの Principal は OtherReader を除外し、公開アクセスは与えません。

cat > bucket-policy.json <<'JSON'
{
  "Version":"2012-10-17",
  "Statement":[
    {"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:role/ReportReader"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/reports/*"}
  ]
}
JSON
aws s3api put-bucket-policy \
  --bucket labex-iam04-reports \
  --policy file://bucket-policy.json
aws s3api get-bucket-policy --bucket labex-iam04-reports --query Policy --output text

バケットポリシーは、ロールに関連付けられるのではなく、バケットに保存されました。同じアカウントでは、関連する Deny が妨げない限り、この適用されるリソース Allow は、別のロールのアイデンティティ Allow がなくても、ロールにアクセスを与えられます。

aws s3api get-object \
  --profile report-role \
  --bucket labex-iam04-reports \
  --key reports/today.txt today.txt
cat today.txt
aws s3api get-object --profile other-role --bucket labex-iam04-reports --key reports/today.txt other-denied.txt || true
aws s3api get-object --profile report-role --bucket labex-iam04-reports --key private/payroll.txt private-denied.txt || true
aws s3api get-object --profile report-role --bucket labex-iam04-reference --key reference.txt reference-denied.txt || true

ReportReader は Daily orders: 145 を受け取り、他の三つのリクエストはすべて AccessDenied を受け取ります。バケットの許可は、別のロール、別のプレフィックス、別のバケットを対象にしません。AWS View も、同じ実際のロール読み取りを送ります。

追加のアイデンティティ Allow に対して非公開データを保護する

このステップでは、ロールのアイデンティティによる許可とバケットの許可が組み合わさる様子を観察し、バケットの Deny で非公開データを保護します。これらの同一アカウントのリクエストでは、適用される Allow は組み合わされます。二つのポリシーの供給源が自動的に共通部分だけに絞られるわけではありません。どちらかの適用されるポリシーの明示的な Deny は、Allow より優先されます。

この実験の同一アカウントのリクエストで使う二つのポリシー供給源では、一致する明示的な Deny が Allow より優先されます。

ReportReader のアイデンティティの読み取り範囲を、一時的にこの演習用バケットのオブジェクトへ広げます。この制御された比較は架空のデータを対象とし、他のバケットへのアクセスは与えません。

cat > role-read.json <<'JSON'
{"Version":"2012-10-17","Statement":[{"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/*"}]}
JSON
aws iam put-role-policy \
  --role-name ReportReader \
  --policy-name ReadAllOwned \
  --policy-document file://role-read.json
aws s3api get-object \
  --profile report-role \
  --bucket labex-iam04-reports \
  --key private/payroll.txt private-before-deny.txt
cat private-before-deny.txt

Synthetic payroll: restricted を想定します。バケットの Allow が reports/ だけを対象にしていても、アイデンティティ Allow が適用されます。レポートの Allow を保持しながら、このロールと private プレフィックスに限定したバケット Deny を追加します。

cat > bucket-policy.json <<'JSON'
{
  "Version":"2012-10-17",
  "Statement":[
    {"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:role/ReportReader"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/reports/*"},
    {"Effect":"Deny","Principal":{"AWS":"arn:aws:iam::123456789012:role/ReportReader"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/private/*"}
  ]
}
JSON
aws s3api put-bucket-policy \
  --bucket labex-iam04-reports \
  --policy file://bucket-policy.json
aws s3api get-object --profile report-role --bucket labex-iam04-reports --key private/payroll.txt private-denied.txt || true
aws s3api get-object \
  --profile report-role \
  --bucket labex-iam04-reports \
  --key reports/today.txt today.txt
cat today.txt

非公開データは、アイデンティティ Allow があっても AccessDenied を返すようになりました。レポートは引き続き 145 を返します。Deny は ReportReader を指定するため、操作担当者は準備用データを確認して保持できます。ステートメントの順序を変えても、Allow が一致する Deny を上書きすることはありません。

アイデンティティ Deny がバケット Allow より優先されることを確認する

このステップでは、逆方向をテストします。ロールのアイデンティティ Deny は、バケット Allow より優先されます。現在の読み取り許可を保持し、reports プレフィックスへの書き込みを拒否する Deny を追加します。

cat > role-read.json <<'JSON'
{"Version":"2012-10-17","Statement":[
  {"Effect":"Allow","Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/*"},
  {"Effect":"Deny","Action":"s3:PutObject","Resource":"arn:aws:s3:::labex-iam04-reports/reports/*"}
]}
JSON
aws iam put-role-policy \
  --role-name ReportReader \
  --policy-name ReadAllOwned \
  --policy-document file://role-read.json

制御された優先順位のテストとして、同じロールと書き込みプレフィックスに対するバケット Allow を一時的に追加します。レポートを保護したままにするため、先にアイデンティティ Deny を適用してください。

cat > bucket-write-test.json <<'JSON'
{
  "Version":"2012-10-17",
  "Statement":[
    {"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:role/ReportReader"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/reports/*"},
    {"Effect":"Deny","Principal":{"AWS":"arn:aws:iam::123456789012:role/ReportReader"},"Action":"s3:GetObject","Resource":"arn:aws:s3:::labex-iam04-reports/private/*"},
    {"Effect":"Allow","Principal":{"AWS":"arn:aws:iam::123456789012:role/ReportReader"},"Action":"s3:PutObject","Resource":"arn:aws:s3:::labex-iam04-reports/reports/*"}
  ]
}
JSON
aws s3api put-bucket-policy \
  --bucket labex-iam04-reports \
  --policy file://bucket-write-test.json
aws s3api put-object --profile report-role --bucket labex-iam04-reports --key reports/today.txt --body upload.txt || true

バケットが許可していても、PutObject の AccessDenied を想定します。アイデンティティ Deny が優先されます。前のステップで保存した二つのステートメントのポリシーに戻し、一時的な書き込み Allow をすぐに取り消します。

aws s3api put-bucket-policy \
  --bucket labex-iam04-reports \
  --policy file://bucket-policy.json
aws s3api get-object \
  --profile report-role \
  --bucket labex-iam04-reports \
  --key reports/today.txt today.txt
cat today.txt
aws s3api get-object --profile other-role --bucket labex-iam04-reports --key reports/today.txt other-denied.txt || true

レポートは Daily orders: 145 のままで、OtherReader は引き続き拒否される必要があります。一時的な書き込み許可はなくなりました。AWS View は、バケットポリシーとロールのアイデンティティポリシーを、実際の読み取り結果とともに表示します。

バケットとアイデンティティのポリシーがレポートを保護する. 例:ReportReader はレポートを読み取れますが、両方のロールは非公開オブジェクトと参照用オブジェクトを拒否されます。保存されたポリシーは、別々の許可の供給源と明示的な拒否を示し、展開されたレポートには実際に返されたバイト列が含まれます。

両方の許可の供給源を取り消して削除する

このステップでは、演習用データを削除する前に、両方のポリシーの供給源を取り消します。別のポリシーがまだ同じ操作を許可している場合、一つの Allow を削除するだけでは不十分です。

バケットポリシーを削除し、レポートの読み取りを繰り返します。ReadAllOwned が、ロールのアイデンティティポリシーからその読み取りをまだ許可しています。

aws s3api delete-bucket-policy --bucket labex-iam04-reports
aws s3api get-object \
  --profile report-role \
  --bucket labex-iam04-reports \
  --key reports/today.txt remaining-grant.txt
cat remaining-grant.txt

Daily orders: 145 を想定します。次に ReadAllOwned を削除し、レポートがまだ存在する間に再びテストします。

aws iam delete-role-policy --role-name ReportReader --policy-name ReadAllOwned
aws s3api get-object --profile report-role --bucket labex-iam04-reports --key reports/today.txt revoked.txt || true
aws iam list-role-policies --role-name ReportReader

AccessDenied と空のポリシー一覧を想定します。準備済みのロールと呼び出し元の信頼は、そのまま残します。この演習中に作成した S3 の許可を取り消しているのです。

aws s3api delete-object --bucket labex-iam04-reports --key reports/today.txt
aws s3api delete-object --bucket labex-iam04-reports --key private/payroll.txt
aws s3api list-objects-v2 --bucket labex-iam04-reports

この正常な応答で KeyCount: 0 を確認し、空のレポート用バケットを削除して、参照用リソースのバイト列を確認します。

aws s3api delete-bucket --bucket labex-iam04-reports
aws s3api list-buckets --query 'Buckets[].Name'
aws s3api get-object --bucket labex-iam04-reference --key reference.txt reference.txt
cat reference.txt

Platform reference: keep を持つ参照用バケットだけが残ります。ネットワークエラーは削除の証拠ではありません。AWS View は、バケットの権限ポリシーもロールの権限ポリシーもない状態と Reports bucket removed を表示します。準備済みアイデンティティ、データ、ローカルの一時キャッシュは、使い捨ての環境の終了時に回収されます。

まとめ

Principal を使い、バケットポリシーを通じて一つのロールにアクセスを与えました。アイデンティティとリソースの Allow が組み合わさる様子を観察し、両方向で明示的な Deny の優先をテストしました。禁止された書き込みは、レポートのバイト列を変更しませんでした。範囲を限定した削除の前に両方の許可の供給源を取り消し、準備済みアイデンティティと無関係なデータを保持しました。リクエストが認可されたままの場合や予想外に拒否される場合は、適用されるすべてのポリシー供給源を確認してください。

詳しくは、AWS 公式ドキュメントを参照してください:アイデンティティポリシーとリソースポリシーの評価.