基本的な使い方
--bucketにバケット名を指定する。
$ aws s3api get-bucket-policy --bucket <bucket-name>
実行例
$ aws s3api get-bucket-policy --bucket example-bucket
{
"Policy": "{\"Version\":\"2012-10-17\",\"Statement\":[{\"Sid\":\"\",\"Effect\":\"Allow\",\"Principal\":{\"Service\":\"cloudfront.amazonaws.com\"},\"Action\":\"s3:GetObject\",\"Resource\":\"arn:aws:s3:::example-bucket/*\",\"Condition\":{\"StringEquals\":{\"aws:SourceArn\":\"arn:aws:cloudfront::123456789012:distribution/E1EXAMPLE123ABC\"}}}]}"
}
Policyの値はJSONオブジェクトではなく、エスケープされた文字列である。
そのままでは読みづらいため、次のように整形する。
整形して表示する
--query Policy --output textでポリシー本体の文字列だけを取り出し、jqに渡す。
$ aws s3api get-bucket-policy --bucket example-bucket --query Policy --output text | jq .
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "",
"Effect": "Allow",
"Principal": {
"Service": "cloudfront.amazonaws.com"
},
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-bucket/*",
"Condition": {
"StringEquals": {
"aws:SourceArn": "arn:aws:cloudfront::123456789012:distribution/E1EXAMPLE123ABC"
}
}
}
]
}
エスケープはJSON出力時に付くだけであり、--output textでは付かない。get-bucket-policyのレスポンスはPolicyのみのため--queryを省いても同じ結果になるが、複数のフィールドを返すコマンドではタブ区切りで並ぶため、取り出したいフィールドを--queryで指定する習慣にしておくとよい。
jqを使わない場合はPythonでも整形できる。
$ aws s3api get-bucket-policy --bucket example-bucket --query Policy --output text | python3 -m json.tool
ポリシーが設定されていない場合
バケットポリシーを設定していないバケットではNoSuchBucketPolicyのエラーになる。
$ aws s3api get-bucket-policy --bucket example-no-policy-bucket
aws: [ERROR]: An error occurred (NoSuchBucketPolicy) when calling the GetBucketPolicy operation: The bucket policy does not exist
空のポリシーが返るのではなくエラーで終了するため、スクリプトで扱う際はエラーを前提にした分岐が必要である。
バケット自体が存在しない場合はNoSuchBucketになる。
aws: [ERROR]: An error occurred (NoSuchBucket) when calling the GetBucketPolicy operation: The specified bucket does not exist
バケット名が正しくても、他アカウントが所有するバケットに対してはAccessDeniedが返る。
S3はバケットの存在自体を秘匿するため、エラーコードだけでは名前の誤りか権限不足かを判別できない。
すべてのバケットをまとめて確認する
aws s3api list-bucketsと組み合わせると、ポリシーが設定されているバケットだけを一覧できる。
$ for bucket in $(aws s3api list-buckets --query 'Buckets[].Name' --output text); do
policy=$(aws s3api get-bucket-policy --bucket "$bucket" --query Policy --output text 2>/dev/null)
if [ -n "$policy" ]; then
echo "=== $bucket"
echo "$policy" | jq -c '[.Statement] | flatten | .[] | {Effect, Principal, Action}'
fi
done
=== example-bucket
{"Effect":"Allow","Principal":{"Service":"cloudfront.amazonaws.com"},"Action":"s3:GetObject"}
=== example-deploy-bucket
{"Effect":"Deny","Principal":"*","Action":"s3:*"}
=== example-public-bucket
{"Effect":"Allow","Principal":"*","Action":"s3:GetObject"}
ポリシーのないバケットは2>/dev/nullでエラーを捨て、変数が空かどうかで判定する。
ただし2>/dev/nullは権限不足のAccessDeniedも同時に捨てるため、読めなかったバケットもポリシーなしとして扱われる。監査目的で棚卸しする場合はエラー内容も出力する。
StatementはIAMポリシーの文法上、配列と単一オブジェクトのどちらも書ける。[.Statement] | flattenで配列に揃えておくと、どちらの形式でも同じように処理できる。
Principalが*のAllowを含むバケットは意図せず公開している可能性があるため、優先して中身を確認する。
なおs3:*をDenyしているポリシーでも、aws:SecureTransportがfalseのときだけHTTPアクセスを拒否する条件付きのDenyは多い。
Effectだけで判断せず、Conditionまで含めて読む。
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::example-deploy-bucket/*",
"arn:aws:s3:::example-deploy-bucket"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
ファイルに保存する
取り出したポリシーはそのままJSONファイルとして保存できる。
$ aws s3api get-bucket-policy --bucket example-bucket --query Policy --output text | jq . > bucket-policy.json
保存したファイルはput-bucket-policyの入力にそのまま使えるため、変更前のバックアップとして残しておくと復旧しやすい。
$ aws s3api put-bucket-policy --bucket example-bucket --policy file://bucket-policy.json
put-bucket-policyはポリシー全体を置き換える。差分をマージするのではないため、取得したJSONを編集してから渡す。
ポリシーごと削除する場合はaws s3api delete-bucket-policy --bucket example-bucketを使う。
Gitで管理しておけば、ポリシーの変更差分も追跡できる。
バケットの取り違えを防ぐ
--expected-bucket-ownerにアカウントIDを指定すると、所有者が一致しない場合にリクエストが失敗する。
$ aws s3api get-bucket-policy --bucket example-bucket --expected-bucket-owner 123456789012
所有者が異なる場合はAccessDeniedが返る。
aws: [ERROR]: An error occurred (AccessDenied) when calling the GetBucketPolicy operation: Access Denied
複数アカウントを扱う場合、プロファイルの指定ミスに気付きやすくなる。
必要な権限
コマンドの実行にはそれぞれ次の権限が必要である。
| コマンド | 必要なアクション |
|---|---|
| get-bucket-policy | s3:GetBucketPolicy |
| list-buckets | s3:ListAllMyBuckets |
権限が不足している場合はAccessDeniedが返る。ReadOnlyAccessやAmazonS3ReadOnlyAccessにはどちらのアクションも含まれるため、閲覧目的であればマネージドポリシーで足りる。
参考
- get-bucket-policy - AWS CLI Command Reference
- Bucket policies for Amazon S3 - Amazon S3
- 【AWS】他アカウントのS3へアクセスできるようにする
- 【AWS CLI】aws s3 presignで署名付きURLを生成してS3のファイルを一時的に共有する
