🧩 背景
Amazon S3では、バケット単位のアクセス制御が一般的ですが、「同じバケット内でもオブジェクトごとにアクセスを分けたい」 というケースも少なくありません。
例えば:
- 機密ファイル(Confidential)だけ特定ロールに限定したい
- タグのないオブジェクトはアップロードも禁止したい
- データ分類(Public / Confidential)をタグで管理したい
といった要件です。
この記事では、S3のオブジェクトタグを使ってアクセスを制御するIAMポリシーの実装例を紹介します。
🎯 ポリシー概要
このポリシーは、以下のルールでS3を制御します。
# | 内容 | 効果 |
---|---|---|
1 | 全バケット一覧取得を許可 | s3:ListAllMyBuckets |
2 | 各バケットの中身を一覧表示可能 | s3:ListBucket |
3 | DataClass=Confidential のタグを持つオブジェクトのみ全操作許可 | s3:*Object + タグ条件 |
4 | アップロード(PutObject)時には必ず DataClass=Confidential タグが必要 | s3:RequestObjectTag 条件付きで許可 |
5 | タグを付けずにアップロードを試みた場合は拒否 | Deny ルール |
🧠 実装ポリシー全文
Policy(S3ConfidentialObjectTagAccess)
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ListAllBuckets",
"Effect": "Allow",
"Action": "s3:ListAllMyBuckets",
"Resource": "*"
},
{
"Sid": "ListEachBucket",
"Effect": "Allow",
"Action": "s3:ListBucket",
"Resource": "arn:aws:s3:::*"
},
{
"Sid": "AllowAllOpsOnTaggedObjects",
"Effect": "Allow",
"Action": "s3:*Object",
"Resource": "arn:aws:s3:::*/*",
"Condition": {
"StringEquals": {
"s3:ExistingObjectTag/DataClass": "Confidential"
}
}
},
{
"Sid": "RequireTagOnPut",
"Effect": "Allow",
"Action": [
"s3:PutObject",
"s3:PutObjectTagging"
],
"Resource": "arn:aws:s3:::*/*",
"Condition": {
"StringEquals": {
"s3:RequestObjectTag/DataClass": "Confidential"
}
}
},
{
"Sid": "DenyPutWithoutRequiredTag",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::*/*",
"Condition": {
"Null": {
"s3:RequestObjectTag/DataClass": "true"
}
}
},
{
"Sid": "DenyTagMutationAfterSet",
"Effect": "Deny",
"Action": [
"s3:PutObjectTagging",
"s3:DeleteObjectTagging"
],
"Resource": "arn:aws:s3:::*/*",
"Condition": {
"Null": {
"s3:ExistingObjectTag/DataClass": "false"
}
}
}
]
}
🖼️ 図で理解する:タグベース制御の流れ
1️⃣ オブジェクト操作時(Get / Delete / Tagging など)
🔹 評価ポイント
- アップロード時には必ず DataClass=Confidential をタグとして同梱する必要がある
- 値は "Confidential" に完全一致している必要あり(大文字小文字も含む)
- タグを省略したアップロードは Deny により拒否される
2️⃣ アップロード(PutObject)時のタグ強制フロー
🔹 評価ポイント
- アップロード時には必ず DataClass=Confidential をタグとして付与する必要がある
- 値は "Confidential" に完全一致している必要あり(大文字小文字も含む)
- タグを省略したアップロードは Deny により拒否される
✅ アクション整理
操作 | タグ条件評価 | 制御方法 |
---|---|---|
GetObject | ✅ 可能 (s3:ExistingObjectTag/DataClass) | タグ Confidential のみ許可 |
PutObject | ✅ 可能 (s3:RequestObjectTag/DataClass) | タグを付与しないアップロードを拒否 |
DeleteObject | ❌ 不可 | MFA・ロール・プレフィックスなどで別制御 |
PutObjectTagging / DeleteObjectTagging | ✅ 初回付与のみ許可、以降拒否 | DenyTagMutationAfterSet で後付け変更禁止 |
💻 CLIでのアップロード例
高レベルコマンド aws s3 cp には --tagging オプションがありません。
そのため s3api put-object を使用する必要があります。
✅ タグ付きでアップロード(許可される)
アップロード(OK)
aws s3api put-object \
--bucket my-secure-bucket \
--key uploads/sample.txt \
--body ./sample.txt \
--tagging "DataClass=Confidential"
❌ タグなしでアップロード(拒否される)
アップロード(NG)
aws s3api put-object \
--bucket my-secure-bucket \
--key uploads/untagged.txt \
--body ./untagged.txt
出力例:
output
An error occurred (AccessDenied) when calling the PutObject operation: Access Denied
🧩 既存オブジェクトへのタグ付与
後からタグを設定したい場合は以下のようにします。
タグ付与
aws s3api put-object-tagging \
--bucket my-secure-bucket \
--key uploads/sample.txt \
--tagging 'TagSet=[{Key=DataClass,Value=Confidential}]'
🧩 動作イメージ
- オブジェクトに
DataClass=Confidential
タグがある場合のみアクセス可能 - タグがないオブジェクトは
GetObject
/PutObject
/DeleteObject
全て拒否 - 新規アップロード時もタグ必須
⚠️ 注意点
項目 | 説明 |
---|---|
評価対象 | ポリシーはIAMポリシー用(バケットポリシーではない) |
タグの単位 | 判定はオブジェクトタグのみでバケットタグは不可 |
既存オブジェクト | タグがない場合はアクセスが拒否される |
暗号化バケット | SSE-KMS利用時はkms:Decrypt権限も必要 |
アップロード運用 | 原則「アップロード時にタグ付与」がおすすめ |
🧪 応用例
📘 複数タグ値を許可
複数タグ
"Condition": {
"StringEquals": {
"s3:ExistingObjectTag/DataClass": ["Confidential", "Secret"]
}
}
🧾 まとめ
目的 | 方法 |
---|---|
タグベースでアクセス制御 | s3:ExistingObjectTag / s3:RequestObjectTag を利用 |
タグなしアップロードを禁止 | Deny + Null 条件で強制 |
データ分類を明確化 | タグ値を「Public」「Confidential」などに統一 |
運用のコツ | アップロード時に必ず --tagging 付きで実行 |
🧰 おわりに
S3タグを 「データ分類ラベル」 として活用することで、バケットを分けなくても 機密・公開を明確に区別できる柔軟な権限設計 が可能になります。
また、S3タグは、単なるメタデータではなく 「ポリシーのキー」 として活用できる強力な仕組みです。
組織的な情報管理・機密区分にもおすすめです。
🔍 参考ドキュメント