IAMポリシーの許可と拒否
要求に一致したStatementを示しながら、許可不足と明示的拒否、同一アカウントと別アカウントの違いを説明します。
説明
IAMの評価では、誰が、どの操作を、どの資源へ要求したかに対してポリシーを照合します。許可文が見つからない場合の暗黙的拒否と、Deny文に一致する明示的拒否は、調べるべき箇所が異なります。
IAMユーザーanalystとS3オブジェクトの固定ポリシーを使います。同一アカウント内でidentity-based policyとresource-based policyを照合し、読取り、書込み、private配下の拒否を確認します。最後に別アカウントの資源へ切り替え、双方の許可が必要なケースを調べます。この例ではboundaryや組織制限は設けていません。
要求に一致したStatementを示しながら、許可不足と明示的拒否、同一アカウントと別アカウントの違いを説明します。
1主体・操作・資源をそろえる
identity.jsonはユーザー側の許可、resource.jsonは対象側の許可です。Actionは操作、ResourceはARN、EffectはAllowまたはDeny、Sidは文を識別する名前です。
cat context.json主体とアカウント関係を読む
cat identity.jsonユーザー側の許可文を読む
cat resource.json対象側の許可文を読むユーザー側にはtraining-reports配下へのGetObjectがあり、対象側のStatementは空です。S3のオブジェクトARNにはregionやaccountの欄がなく、所有アカウントはこの演習のcontextで別に指定しています。
2読取りに一致する許可文
public/a.csvへのGetObjectを評価します。
python3 evaluate.py --action s3:GetObject --key public/a.csv公開用プレフィックス内の読取り要求を照合するidentityのReadReports:Allowに一致してallowedです。同一アカウントのこのケースでは、対象側の許可文がなくても、ユーザー側の許可が成立しています。
3許可されていない書込み
同じオブジェクトへのPutObjectを評価します。
python3 evaluate.py --action s3:PutObject同じ資源への書込み要求に替える --key public/a.csv両方ともmatches=noneでimplicitDenyです。Deny文が見つかったのではなく、書込みを許可する文がありません。読取りの許可を持つことは、書込みの許可を持つことではありません。
4リソースポリシーでユーザーに許可を与える
resource-write.jsonはPrincipalにanalystのARNを指定し、PutObjectを許可する案です。反映して再評価します。
cat resource-write.json主体を指定した対象側の許可を読む
cp resource-write.json resource.json書込み許可を対象側へ反映する
python3 evaluate.py --action s3:PutObject --key public/a.csv同じ書込みを再評価するユーザー側は一致なしでも、対象側のWriteByAnalyst:Allowでallowedになります。この例は同一アカウントのIAMユーザーに直接許可する条件であり、あらゆるロールや制限の組合せへそのまま当てはめるものではありません。
5private配下だけを明示的に拒否する
書込み許可に加えて、private/*へのPutObjectをDenyする文を反映します。
cat resource-deny.json許可と拒否が共存する案を読む
cp resource-deny.json resource.jsonprivate配下の拒否を加える
python3 evaluate.py --action s3:PutObject --key private/a.csv拒否対象のオブジェクトへ書込みを要求するWriteByAnalyst:AllowとProtectPrivate:Denyの両方に一致しますが、結果はexplicitDenyです。許可があることだけを確認せず、同じ要求へ一致する拒否文まで確認します。
6拒否条件の範囲を確認する
publicへの書込みとprivateからの読取りを評価します。
python3 evaluate.py --action s3:PutObject --key public/a.csv拒否対象外への書込みを確認する
python3 evaluate.py --action s3:GetObject --key private/a.csv同じprivate配下でも異なる操作を確認するどちらもallowedです。Deny文はprivate配下へのPutObjectにだけ一致します。「private」という名前自体が読取りを禁止するのではなく、ActionとResourceの条件が評価されています。
7別アカウントの対象側だけが許可した場合
partner-reportsは別アカウント所有のバケットです。対象側はanalystに読取りを許可していますが、ユーザー側の許可はtraining-reportsだけです。
cat partner-resource.json別アカウントの対象側の許可を読む
python3 evaluate.py --partner対象をpartner-reportsへ変更する --action s3:GetObject --key public/a.csvresourceにはPartnerRead:Allowがある一方、identityは一致せずimplicitDenyです。この別アカウントのケースでは、要求元と対象側の双方で許可が必要です。
8要求元にも対象資源への許可を加える
identity-partner.jsonはpartner-reportsへのGetObjectも許可する案です。対象側の許可はそのままで、要求元へ追加します。
cp identity-partner.json identity.json要求元にもpartnerの読取りを許可する
python3 evaluate.py --partner --action s3:GetObject同じ別アカウントの要求を再評価する --key public/a.csvReadPartner:AllowとPartnerRead:Allowがそろい、allowedになります。片側の変更だけで判断せず、要求が通るために必要な双方の文を照合しました。
9追加許可で既存の拒否が消えないことを確認
元のtraining-reportsのprivate配下へ書込みを要求します。
python3 evaluate.py --action s3:PutObject --key private/a.csv既存の拒否条件を同じ要求で再確認するProtectPrivate:DenyでexplicitDenyのままです。別の資源への許可を増やしても、この要求に一致する明示的拒否は消えません。
まとめ
ActionとResource、必要ならPrincipalをそろえて、一致する文を確認します。
許可文がない暗黙的拒否と、Deny文に一致する明示的拒否を分けて調べます。
別アカウントのこのケースでは双方の許可が必要で、明示的拒否は許可より優先されます。
操作履歴と解説を振り返れます。
シェル / Python 3
cat context.json
cat identity.json
cat resource.json{
"principal": "arn:aws:iam::111111111111:user/analyst",
"principal_account": "111111111111",
"resource_account": "111111111111",
"scope": "IAM user, no boundary/session/SCP/RCP restrictions in this case"
}
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "ReadReports",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::training-reports/*"
}
]
}
{
"Version": "2012-10-17",
"Statement": []
}python3 evaluate.py --action s3:GetObject --key public/a.csvidentity matches=ReadReports:Allow resource matches=none account_relation=same-account decision=allowed
python3 evaluate.py --action s3:PutObject --key public/a.csvidentity matches=none resource matches=none account_relation=same-account decision=implicitDeny
cat resource-write.json
cp resource-write.json resource.json
python3 evaluate.py --action s3:PutObject --key public/a.csv{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "WriteByAnalyst",
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::training-reports/*",
"Principal": {
"AWS": "arn:aws:iam::111111111111:user/analyst"
}
}
]
}
identity matches=none
resource matches=WriteByAnalyst:Allow
account_relation=same-account decision=allowedcat resource-deny.json
cp resource-deny.json resource.json
python3 evaluate.py --action s3:PutObject --key private/a.csv{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "WriteByAnalyst",
"Effect": "Allow",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::training-reports/*",
"Principal": {
"AWS": "arn:aws:iam::111111111111:user/analyst"
}
},
{
"Sid": "ProtectPrivate",
"Effect": "Deny",
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::training-reports/private/*",
"Principal": {
"AWS": "arn:aws:iam::111111111111:user/analyst"
}
}
]
}
identity matches=none
resource matches=WriteByAnalyst:Allow,ProtectPrivate:Deny
account_relation=same-account decision=explicitDenypython3 evaluate.py --action s3:PutObject --key public/a.csv
python3 evaluate.py --action s3:GetObject --key private/a.csvidentity matches=none resource matches=WriteByAnalyst:Allow account_relation=same-account decision=allowed identity matches=ReadReports:Allow resource matches=none account_relation=same-account decision=allowed
cat partner-resource.json
python3 evaluate.py --partner --action s3:GetObject --key public/a.csv{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "PartnerRead",
"Effect": "Allow",
"Action": "s3:GetObject",
"Resource": "arn:aws:s3:::partner-reports/*",
"Principal": {
"AWS": "arn:aws:iam::111111111111:user/analyst"
}
}
]
}
identity matches=none
resource matches=PartnerRead:Allow
account_relation=cross-account decision=implicitDenycp identity-partner.json identity.json
python3 evaluate.py --partner --action s3:GetObject --key public/a.csvidentity matches=ReadPartner:Allow resource matches=PartnerRead:Allow account_relation=cross-account decision=allowed
python3 evaluate.py --action s3:PutObject --key private/a.csvidentity matches=none resource matches=WriteByAnalyst:Allow,ProtectPrivate:Deny account_relation=same-account decision=explicitDeny
演習完了