- AWS
S3バケットポリシーの書き方と例 IP制限・Condition早見表
S3 バケットポリシーとは、バケットに直接付ける JSON 形式のアクセス許可ルールで、「誰が(Principal)・何を(Action)・どこに(Resource)・どんな条件で(Condition)・許可か拒否か(Effect)」を書きます。 IAM ポリシーが「利用者の側」に付くのに対し、バケットポリシーは「バケットの側」に付きます。
この記事では、各要素の意味を表で整理したうえで、よく使う6つのパターンをコピーして使える JSON で並べます。CLI と boto3 での設定・確認・削除、パブリックアクセスブロックの4つの設定、つまずきやすい点(ARN の /*、Allow だけの IP 条件、明示的 Deny の優先)も、実行結果や公式ドキュメントの記載と合わせてまとめました。
確認環境:Ubuntu 24.04、AWS CLI 1.46.1、Python 3.11.15、boto3 1.43.103。AWS の API をローカルで再現するツール(moto 5.2.3)で実行しています。掲載するコマンドは接続先の指定を外してあり、実際の AWS でそのまま使える形です。
S3バケットポリシーの早見表
要素の意味
| 要素 | 書くこと | 例 |
|---|---|---|
Version |
ポリシー言語の版。"2012-10-17" と書く |
"Version": "2012-10-17" |
Statement |
ルールの配列。1つ以上のステートメントを並べる | "Statement": [ {…}, {…} ] |
Sid |
ステートメントの名前(任意)。あとで見分けるための目印 | "Sid": "DenyInsecureTransport" |
Effect |
許可か拒否か。Allow または Deny |
"Effect": "Deny" |
Principal |
だれに対するルールか | "*"、{"AWS": "arn:aws:iam::111122223333:root"}、{"Service": "cloudfront.amazonaws.com"} |
Action |
どの操作か。s3: で始まる名前 |
"s3:GetObject"、["s3:GetObject", "s3:PutObject"]、"s3:*" |
Resource |
どのバケット・オブジェクトか(ARN) | バケット:arn:aws:s3:::example-policy-demo、オブジェクト:arn:aws:s3:::example-policy-demo/* |
Condition |
条件(任意)。演算子・条件キー・値の組 | {"Bool": {"aws:SecureTransport": "false"}} |
やりたいこと別のパターン
| やりたいこと | Effect | Principal | Condition |
|---|---|---|---|
| 特定の IP 以外を拒否 | Deny | "*" |
NotIpAddress + aws:SourceIp |
| HTTP(暗号化なし)を拒否 | Deny | "*" |
Bool + aws:SecureTransport が false |
| 別アカウントに許可 | Allow | {"AWS": "相手アカウントの ARN"} |
なし |
| 特定の VPC エンドポイント以外を拒否 | Deny | "*" |
StringNotEquals + aws:SourceVpce |
| CloudFront(OAC)からの読み取りを許可 | Allow | {"Service": "cloudfront.amazonaws.com"} |
StringEquals + AWS:SourceArn |
| だれでも読み取り可(公開) | Allow | "*" |
なし |
コマンド
| 操作 | CLI | boto3 |
|---|---|---|
| 設定 | aws s3api put-bucket-policy --bucket 名前 --policy file://policy.json |
s3.put_bucket_policy(Bucket=…, Policy=json.dumps(…)) |
| 確認 | aws s3api get-bucket-policy --bucket 名前 |
s3.get_bucket_policy(Bucket=…) |
| 削除 | aws s3api delete-bucket-policy --bucket 名前 |
s3.delete_bucket_policy(Bucket=…) |
| 公開の防止設定 | aws s3api put-public-access-block --bucket 名前 --public-access-block-configuration … |
s3.put_public_access_block(Bucket=…, PublicAccessBlockConfiguration={…}) |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「S3バケットポリシーの書き方と例 IP制限・Condition早見表」
バケットポリシーの基本の形
最小の形は次のとおりです。Statement の中に、ルールを1つずつ書きます。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ルールの名前",
"Effect": "Allow または Deny",
"Principal": "だれに",
"Action": "どの操作を",
"Resource": "どのバケット・オブジェクトに",
"Condition": { "演算子": { "条件キー": "値" } }
}
]
}
Principal の書き方
| 対象 | 書き方 |
|---|---|
| すべて(匿名を含む) | "Principal": "*" |
| AWS アカウント全体 | "Principal": {"AWS": "arn:aws:iam::111122223333:root"} または {"AWS": "111122223333"} |
| IAM ユーザー | "Principal": {"AWS": "arn:aws:iam::111122223333:user/taro"} |
| IAM ロール | "Principal": {"AWS": "arn:aws:iam::111122223333:role/app-role"} |
| AWS サービス | "Principal": {"Service": "cloudfront.amazonaws.com"} |
| 複数 | "Principal": {"AWS": ["111122223333", "444455556666"]} |
公式ドキュメントでは、"Principal": "*" と "Effect": "Allow" の組み合わせは、公開や匿名アクセスを意図する場合に限って使うよう案内されています。それ以外では、Principal を具体的に書くか、Condition で絞ります。
Resource はバケットとオブジェクトで ARN が違う
| 操作の種類 | 例 | Resource に書く ARN |
|---|---|---|
| バケットに対する操作 | s3:ListBucket、s3:PutBucketPolicy |
arn:aws:s3:::example-policy-demo |
| オブジェクトに対する操作 | s3:GetObject、s3:PutObject、s3:DeleteObject |
arn:aws:s3:::example-policy-demo/* |
| 特定の接頭辞の下だけ | s3:GetObject |
arn:aws:s3:::example-policy-demo/public/* |
| 両方をまとめて対象にする | s3:* |
上の2つを配列で並べる |
オブジェクトの ARN は、バケット名のあとに / が必要です。この取り違えは MalformedPolicy の代表的な原因なので、後半で詳しく扱います。
Condition の書き方
Condition は「演算子 → 条件キー → 値」の3段で書きます。
| 演算子 | 条件キーの例 | 使いどころ |
|---|---|---|
IpAddress / NotIpAddress |
aws:SourceIp |
接続元の IP アドレス(CIDR)で判定 |
Bool |
aws:SecureTransport |
HTTPS かどうかで判定 |
StringEquals / StringNotEquals |
aws:SourceVpce、aws:SourceVpc、AWS:SourceArn |
VPC エンドポイント、VPC、呼び出し元リソースで判定 |
値を配列で書くと「どれかに一致」の意味になります("aws:SourceIp": ["192.0.2.0/24", "203.0.113.0/24"] は、どちらかの範囲なら一致)。
コピーして使えるバケットポリシー6例
バケット名 example-policy-demo、アカウント ID、IP アドレスなどは、自分の値に置き換えてください。
1. 特定の IP アドレス以外を拒否する(Deny + NotIpAddress)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyExceptAllowedIp",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::example-policy-demo",
"arn:aws:s3:::example-policy-demo/*"
],
"Condition": {
"NotIpAddress": {
"aws:SourceIp": ["192.0.2.0/24", "203.0.113.0/24"]
}
}
}
]
}
IAM の公式ドキュメントにある「接続元 IP で拒否する」例(Deny + NotIpAddress + aws:SourceIp)を、バケットポリシーの形(Principal と Resource を追加)にしたものです。公式の注意書きを2つ紹介します。
- このステートメントは何も許可しません。 許可は、IAM ポリシーや別の Allow ステートメントで与えます。
- Deny と否定形の条件(Not〜)を組み合わせると、条件に当てはまるもの以外がすべて拒否されます。 自分の IP を書き間違えると、自分もバケットを操作できなくなるので、適用前に値をよく確かめます。
2. HTTPS 以外を拒否する(aws:SecureTransport)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyInsecureTransport",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::example-policy-demo",
"arn:aws:s3:::example-policy-demo/*"
],
"Condition": {
"Bool": { "aws:SecureTransport": "false" }
}
}
]
}
S3 の公式ドキュメントに載っている形です。aws:SecureTransport が false(HTTP でのリクエスト)のときに拒否します。
3. 別アカウントに読み取りと一覧を許可する
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowOtherAccountList",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:root" },
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::example-policy-demo"
},
{
"Sid": "AllowOtherAccountRead",
"Effect": "Allow",
"Principal": { "AWS": "arn:aws:iam::111122223333:root" },
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-policy-demo/*"
}
]
}
一覧(ListBucket)はバケットの ARN、読み取り(GetObject)はオブジェクトの ARN と、ステートメントを分けています。相手アカウントの中の特定のユーザーやロールだけに絞るときは、Principal にその ARN を書きます。別アカウントからのアクセスでは、相手アカウント側の IAM ポリシーでも同じ操作が許可されている必要があります。
4. 特定の VPC エンドポイント以外を拒否する(aws:SourceVpce)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AccessToSpecificVpceOnly",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::example-policy-demo",
"arn:aws:s3:::example-policy-demo/*"
],
"Condition": {
"StringNotEquals": { "aws:SourceVpce": "vpce-0abcdef1234567890" }
}
}
]
}
S3 の公式ドキュメントに載っている形です。VPC 全体で絞るときは、条件キーを aws:SourceVpc、値を vpc-1a2b3c4d のような VPC ID にします。公式の注意書きでは、このポリシーを付けるとコンソールからのアクセスも拒否される(コンソールのリクエストは指定した VPC エンドポイントを通らないため)こと、エンドポイント ID を正しい値に置き換えないと自分もアクセスできなくなることが案内されています。このステートメントも許可は与えないので、Allow は別に用意します。
5. CloudFront の OAC からの読み取りを許可する
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowCloudFrontServicePrincipalReadOnly",
"Effect": "Allow",
"Principal": { "Service": "cloudfront.amazonaws.com" },
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-policy-demo/*",
"Condition": {
"StringEquals": {
"AWS:SourceArn": "arn:aws:cloudfront::123456789012:distribution/EDFDVBD6EXAMPLE"
}
}
}
]
}
CloudFront の公式ドキュメントに載っている形です。Principal は CloudFront のサービス、Condition でディストリビューションの ARN(arn:aws:cloudfront::アカウントID:distribution/ディストリビューションID)を指定します。Condition を付けることで、自分のディストリビューション経由のリクエストだけが許可されます。 オブジェクトを SSE-KMS で暗号化している場合は、KMS キーのポリシーにも CloudFront への許可を足します。
6. だれでも読み取れるようにする(公開)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicReadGetObject",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-policy-demo/*"
}
]
}
静的ウェブサイトのホスティング用として、S3 の公式ドキュメントに載っている形です。このポリシーを設定するには、先にパブリックアクセスブロックをバケットとアカウントの両方で外す必要があります。公式ドキュメントは、すべての公開アクセスをブロックしておくことを推奨しています。公開したい場合は、5 の CloudFront + OAC の形にして、バケット自体は非公開のままにする方法も検討できます。
CLI で設定・確認・削除する
HTTPS 強制のポリシー(例2)を policy.json に保存して、設定から削除まで実行します。
設定する(put-bucket-policy)
aws s3api put-bucket-policy --bucket example-policy-demo --policy file://policy.json
成功すると何も表示されません(終了コード 0)。put-bucket-policy は追記ではなく、ポリシー全体の置き換えです。ステートメントを足したいときは、いまのポリシーを取り出して編集し、全体を設定し直します。
確認する(get-bucket-policy)
aws s3api get-bucket-policy --bucket example-policy-demo
{
"Policy": "{\n \"Version\": \"2012-10-17\",\n \"Statement\": [\n {\n \"Sid\": \"DenyInsecureTransport\",\n \"Effect\": \"Deny\",\n …(省略)… }\n ]\n}\n"
}
Policy は「JSON を文字列にしたもの」で返るので、そのままでは読みにくい形です。--query Policy --output text で文字列を取り出し、jq に渡すと整形できます。
aws s3api get-bucket-policy --bucket example-policy-demo --query Policy --output text | jq .
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyInsecureTransport",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::example-policy-demo",
"arn:aws:s3:::example-policy-demo/*"
],
"Condition": {
"Bool": {
"aws:SecureTransport": "false"
}
}
}
]
}
末尾を > policy.json にすれば、編集用のファイルとして保存できます。
削除する(delete-bucket-policy)
aws s3api delete-bucket-policy --bucket example-policy-demo
aws s3api get-bucket-policy --bucket example-policy-demo
An error occurred (NoSuchBucketPolicy) when calling the GetBucketPolicy operation: The bucket policy does not exist
削除も成功時は無表示です。削除後に get-bucket-policy を実行すると、NoSuchBucketPolicy が返ります。ポリシーが1つも設定されていないバケットでも同じエラーになるので、「未設定」の判定に使えます。
boto3 で設定・確認・削除する
import json
import boto3
from botocore.exceptions import ClientError
s3 = boto3.client("s3")
bucket = "example-policy-demo"
policy = {
"Version": "2012-10-17",
"Statement": [
{
"Sid": "DenyInsecureTransport",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:*",
"Resource": [f"arn:aws:s3:::{bucket}", f"arn:aws:s3:::{bucket}/*"],
"Condition": {"Bool": {"aws:SecureTransport": "false"}},
}
],
}
# 設定する(Policy は JSON 文字列で渡す)
s3.put_bucket_policy(Bucket=bucket, Policy=json.dumps(policy))
# 読み出す(Policy は文字列で返るので json.loads で辞書に戻す)
res = s3.get_bucket_policy(Bucket=bucket)
print(type(res["Policy"]).__name__)
loaded = json.loads(res["Policy"])
print(loaded["Statement"][0]["Sid"], loaded["Statement"][0]["Effect"])
# 削除する
s3.delete_bucket_policy(Bucket=bucket)
try:
s3.get_bucket_policy(Bucket=bucket)
except ClientError as e:
print(e.response["Error"]["Code"])
# パブリックアクセスブロックを4つとも有効にする
s3.put_public_access_block(
Bucket=bucket,
PublicAccessBlockConfiguration={
"BlockPublicAcls": True,
"IgnorePublicAcls": True,
"BlockPublicPolicy": True,
"RestrictPublicBuckets": True,
},
)
print(s3.get_public_access_block(Bucket=bucket)["PublicAccessBlockConfiguration"])
str
DenyInsecureTransport Deny
NoSuchBucketPolicy
{'BlockPublicAcls': True, 'IgnorePublicAcls': True, 'BlockPublicPolicy': True, 'RestrictPublicBuckets': True}
Policy は辞書ではなく文字列で受け渡しします。 渡すときは json.dumps、受け取ったら json.loads です。Python の辞書で組み立てると、バケット名を変数で埋め込めるので、Resource のバケット名の書き間違いを減らせます。
パブリックアクセスブロックの4つの設定
パブリックアクセスブロックは、バケットポリシーや ACL による公開を、上から止める設定です。4つのフラグがあります。
aws s3api put-public-access-block \
--bucket example-policy-demo \
--public-access-block-configuration \
BlockPublicAcls=true,IgnorePublicAcls=true,BlockPublicPolicy=true,RestrictPublicBuckets=true
aws s3api get-public-access-block --bucket example-policy-demo
{
"PublicAccessBlockConfiguration": {
"BlockPublicAcls": true,
"IgnorePublicAcls": true,
"BlockPublicPolicy": true,
"RestrictPublicBuckets": true
}
}
| フラグ | 対象 | true にしたときの動き |
|---|---|---|
BlockPublicAcls |
ACL(これから設定するもの) | 公開の ACL を設定する呼び出し(PutBucketAcl、PutObjectAcl、公開 ACL つきの PutObject)を受け付けない |
IgnorePublicAcls |
ACL(すでにあるもの) | バケットとオブジェクトの公開 ACL を無視する |
BlockPublicPolicy |
バケットポリシー(これから設定するもの) | 公開を許可するバケットポリシーの PutBucketPolicy を受け付けない |
RestrictPublicBuckets |
バケットポリシー(すでにあるもの) | 公開ポリシーが付いたバケットへのアクセスを、AWS サービスとバケット所有アカウント内の許可された利用者に限る |
「Block」が付く2つは新しい設定を止め、残りの2つは既存の設定の効き目を止める、と覚えると整理しやすくなります。
一部のフラグだけを指定して実行すると、指定しなかったフラグは false になりました。
aws s3api put-public-access-block --bucket example-policy-demo \
--public-access-block-configuration BlockPublicAcls=true,IgnorePublicAcls=true
aws s3api get-public-access-block --bucket example-policy-demo
{
"PublicAccessBlockConfiguration": {
"BlockPublicAcls": true,
"IgnorePublicAcls": true,
"BlockPublicPolicy": false,
"RestrictPublicBuckets": false
}
}
この設定も全体の置き換えなので、4つとも書いて実行するのが確実です。設定を外すときは aws s3api delete-public-access-block --bucket example-policy-demo を使います。
「公開」と見なされるポリシー、見なされないポリシー
公式ドキュメントによると、次のような固定の値で絞っているポリシーは、Principal が "*" でも公開とは見なされません。
| 絞り方 | 条件キーの例 |
|---|---|
| 特定の AWS プリンシパル・サービス | Principal に ARN やサービス名を書く |
| IP アドレスの範囲(CIDR) | aws:SourceIp |
| 呼び出し元のリソースやアカウント | aws:SourceArn、aws:SourceAccount |
| VPC・VPC エンドポイント | aws:SourceVpc、aws:SourceVpce |
例6の公開読み取りは条件がないので公開と見なされ、BlockPublicPolicy が true のバケットでは設定が受け付けられません。例5の CloudFront OAC は、サービスプリンシパルと AWS:SourceArn で絞っているので、パブリックアクセスブロックを有効にしたまま使えます。
設定はバケット単位とアカウント単位の両方にあり、公式ドキュメントによると、違いがあるときは最も制限の強い組み合わせが適用されます。 バケット側で外しても公開できないときは、アカウント側の設定を確かめます。
つまずきやすい3つの点
バケット ARN とオブジェクト ARN の取り違え(MalformedPolicy)
次のポリシーは、オブジェクトの操作(GetObject)に対して、Resource がバケットの ARN になっています。
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-policy-demo"
}
この形で設定しようとした利用者の報告(Serverless Framework のフォーラム)では、次のエラーが返っています。
Action does not apply to any resource(s) in statement (Service: Amazon S3; Status Code: 400; Error Code: MalformedPolicy)
「このステートメントの Action は、書かれた Resource のどれにも当てはまらない」という意味です。直し方は、Action の種類に Resource を合わせることです。
| Action | 直す前の Resource | 直した後の Resource |
|---|---|---|
s3:GetObject |
arn:aws:s3:::example-policy-demo |
arn:aws:s3:::example-policy-demo/* |
s3:ListBucket |
arn:aws:s3:::example-policy-demo/* |
arn:aws:s3:::example-policy-demo |
| 両方をまとめて書く | どちらか片方だけ | 2つを配列で並べる |
MalformedPolicy には、ほかにも次のようなメッセージがあります。
| メッセージ | 原因 | 直し方 |
|---|---|---|
Action does not apply to any resource(s) in statement |
Action と Resource の種類(バケット/オブジェクト)が合っていない | 上の表のとおり ARN を合わせる |
Policy has invalid resource |
Resource のバケット名が、--bucket で指定したバケットと違う |
ARN のバケット名を合わせる |
Invalid principal in policy |
Principal の書式が合っていない(AWS キーがない、ARN の形でない など) |
「Principal の書き方」の表の形にする |
Allow だけでは IP 制限にならない
「特定の IP からだけ使えるようにしたい」とき、次のように Allow に IP の条件を付けるだけでは、制限になりません。
{
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-policy-demo/*",
"Condition": { "IpAddress": { "aws:SourceIp": "192.0.2.0/24" } }
}
理由は、アクセス許可の決まり方にあります。IAM の公式ドキュメントでは、同じアカウント内のリクエストについて、IAM ポリシー(利用者側)とバケットポリシー(リソース側)のどちらかが許可していれば許可されると説明されています。
| 利用者 | IAM ポリシー | 上の Allow(IP 条件つき) | 結果 |
|---|---|---|---|
| 同じアカウントの利用者(S3 の権限あり)、範囲外の IP | 許可 | 条件に合わず、何も決めない | IAM ポリシーの許可で通る |
| 匿名、範囲内の IP | なし | 許可 | 通る |
| 匿名、範囲外の IP | なし | 何も決めない | 通らない |
条件に合わない Allow は「拒否」ではなく「何も決めない」だけです。IAM ポリシーで S3 の権限を持つ利用者は、どの IP からでも操作できます。実際に、IAM ポリシーで s3:* を許可した利用者 taro は、バケットポリシーが1つもない状態でオブジェクトを取得できました。
aws s3 cp s3://example-policy-demo/private/secret.txt -
secret
IP で絞りたいときは、例1のように Deny + NotIpAddress で「範囲外を拒否」と書きます。 明示的な Deny は、どのポリシーの Allow よりも優先されるためです。
明示的な Deny は Allow より優先される
Deny の優先を、2つの実行で確かめました。まず、公開読み取りの Allow と、private/ の下だけを拒否する Deny を同じポリシーに並べます。
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PublicRead",
"Effect": "Allow",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-policy-demo/*"
},
{
"Sid": "DenyPrivatePrefix",
"Effect": "Deny",
"Principal": "*",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::example-policy-demo/private/*"
}
]
}
認証なしの curl で、2つのオブジェクトにアクセスした結果です(URL のホスト部分は環境に合わせて置き換えています)。
curl -s -o /dev/null -w "index.html HTTP %{http_code}\n" https://example-policy-demo.s3.amazonaws.com/index.html
curl -s -o /dev/null -w "private/secret.txt HTTP %{http_code}\n" https://example-policy-demo.s3.amazonaws.com/private/secret.txt
index.html HTTP 200
private/secret.txt HTTP 403
private/secret.txt は Allow(/*)にも当てはまりますが、Deny が優先されて 403 になりました。
次に、IAM ポリシーで s3:* を許可されている利用者 taro で、Deny のステートメントだけを付けたバケットにアクセスします。boto3 で HTTP ステータスを表示した結果です。
import boto3
from botocore.exceptions import ClientError
s3 = boto3.client("s3")
for key in ["index.html", "private/secret.txt"]:
try:
r = s3.get_object(Bucket="example-policy-demo", Key=key)
print(key, r["ResponseMetadata"]["HTTPStatusCode"])
except ClientError as e:
print(key, e.response["ResponseMetadata"]["HTTPStatusCode"])
index.html 200
private/secret.txt 403
ポリシーを付ける前は取得できていた private/secret.txt が、403 に変わりました。IAM ポリシーで許可されていても、バケットポリシーの Deny があれば拒否されます。
| 評価の順番 | 内容 |
|---|---|
| 1 | 何も書かれていなければ拒否(暗黙の拒否) |
| 2 | どこかに Allow があれば許可 |
| 3 | どこかに明示的な Deny があれば、Allow があっても拒否 |
エラーと対処の一覧
| エラー | 原因 | 対処 |
|---|---|---|
NoSuchBucketPolicy(GetBucketPolicy) |
バケットポリシーが設定されていない、または削除済み | 未設定として扱う。必要なら put-bucket-policy で設定する |
NoSuchBucket: The specified bucket does not exist |
--bucket のバケット名が違う |
バケット名とリージョンを確かめる |
MalformedPolicy |
ポリシーの内容が S3 の決まりに合っていない | 上の「MalformedPolicy」の表でメッセージ別に確かめる |
Error parsing parameter '--policy': Unable to load paramfile file://… |
file:// で指定したファイルが見つからない |
ファイル名と、コマンドを実行しているフォルダを確かめる |
| 公開ポリシーが保存できない | パブリックアクセスブロック(BlockPublicPolicy)が有効 | 公開が本当に必要か確かめたうえで、バケットとアカウントの設定を見直す |
| ポリシーを付けたら自分も操作できなくなった | Deny の条件(IP、VPC エンドポイント)に自分が当てはまっている | 条件の値を確かめる。適用前に小さな検証用バケットで試す |
NoSuchBucketPolicy、NoSuchBucket、paramfile の3つは、今回の実行で実際に表示されたメッセージです。
適用前のチェックリスト
| 確認 | 内容 |
|---|---|
| Version | "2012-10-17" になっているか |
| Resource | バケットの操作はバケット ARN、オブジェクトの操作は /* つきの ARN か |
| バケット名 | ARN のバケット名が、設定先のバケットと同じか |
| Principal | "*" と Allow の組み合わせは、公開を意図したものか |
| Deny の条件 | 自分の接続元(IP・VPC エンドポイント)が拒否の対象に入っていないか |
| 置き換え | put-bucket-policy は全体の置き換え。いまのポリシーを get-bucket-policy で保存したか |
| パブリックアクセスブロック | 4つのフラグの状態を get-public-access-block で確かめたか |
よくある質問
Q. バケットポリシーと IAM ポリシーは、どちらに書けばよいですか? A. 同じアカウント内の利用者への許可は、IAM ポリシーに書くのが基本です。バケットポリシーは、別アカウントや AWS サービスへの許可、IP・HTTPS・VPC エンドポイントなど「バケット側で一律に守りたい条件」に向いています。
Q. ステートメントを1つだけ追加できますか? A. put-bucket-policy は全体を置き換えるので、get-bucket-policy で取り出したポリシーに追記し、全体を設定し直します。
Q. 公開読み取りのポリシーが保存できません。 A. パブリックアクセスブロックの BlockPublicPolicy が有効だと、公開を許可するポリシーは受け付けられません。バケット単位とアカウント単位の両方の設定を確かめてください。CloudFront の OAC のように条件で絞ったポリシーなら、有効にしたまま設定できます。
Q. get-bucket-policy の結果が読みにくいです。
A. --query Policy --output text | jq . を付けると、整形された JSON で表示されます。
まとめ
- バケットポリシーは Effect・Principal・Action・Resource・Condition の組で、「だれに・何を・どこに・どんな条件で」を書きます。
- バケットの操作はバケット ARN、オブジェクトの操作は
/*つきの ARN です。取り違えると MalformedPolicy になります。 - IP 制限は Deny + NotIpAddress で書きます。Allow に条件を付けるだけでは、IAM ポリシーで許可された利用者を止められません。
- 明示的な Deny は、どの Allow よりも優先されます。 実行結果でも、Allow と Deny が重なったオブジェクトは 403 になりました。
- put-bucket-policy は全体の置き換えです。get-bucket-policy(
--query Policy --output text)で保存してから編集します。 - パブリックアクセスブロックは4つのフラグで、Block〜は新しい設定を、Ignore〜と Restrict〜は既存の設定の効き目を止めます。
- 公開が必要なときは、CloudFront + OAC でバケットを非公開のまま配信する形も選べます。
参考・出典
- Examples of Amazon S3 bucket policies(Amazon S3 ユーザーガイド)
- Controlling access from VPC endpoints with bucket policies(Amazon S3 ユーザーガイド)
- How Amazon S3 works with IAM(Amazon S3 ユーザーガイド)
- Blocking public access to your Amazon S3 storage(Amazon S3 ユーザーガイド)
- Setting permissions for website access(Amazon S3 ユーザーガイド)
- Restrict access to an Amazon S3 origin(Amazon CloudFront デベロッパーガイド)
- AWS: Denies access to AWS based on the source IP(IAM ユーザーガイド)
- Policy evaluation logic(IAM ユーザーガイド)
- AWS JSON policy elements: Principal(IAM ユーザーガイド)
- Error Code: MalformedPolicy(Serverless Framework フォーラム)
- MalformedPolicy: Policy has invalid resource(GitHub Issue)
- Fix: Error Putting S3 Bucket Policy - MalformedPolicy(Terraform Pilot)
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「S3バケットポリシーの書き方と例 IP制限・Condition早見表」
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。