S3のバケットポリシーで特定のユーザー・ロールを除いてDenyしたい【NotPrincipal・Condition】

f:id:hesma2:20210227152722p:plain

S3のバケットポリシーで特定のユーザー・ロールを除いてDenyしたい時の設定方法を、失敗例を添えてご紹介します。
スイッチロールをしている環境での設定方法も紹介しています。

【失敗例】自分がポリシーを変更できなくなった(アホ)

S3のバケットポリシーのベストプラクティスとしては、必要最低限のアクションを必要最低限のユーザー・ロールに設定することだと思います。
しかし、そこまでガチガチにやるのは面倒な場合、これだけはというアクションを拒否しておくというやり方もあります。

そこで私は、以下のように4つのアクションを拒否したバケットポリシーを設定しました。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "s3:DeleteBucketPolicy",
                "s3:PutBucketAcl",
                "s3:PutBucketPolicy",
                "s3:PutEncryptionConfiguration",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::test-bucket-policy-deny",
                "arn:aws:s3:::test-bucket-policy-deny/*"
            ]
        }
    ]
}

すると、自分もポリシーが変更できなくなってしまいました。
アホですね☆

f:id:hesma2:20210227154451p:plain
自分もポリシーを変更できなくなった(アホ)

こうなってしまったら、バケットを削除して作り直すか、ルートユーザーを管理している方に頭を下げて修正してもらいましょう。
(私は土下座して修正してもらいました)

NotPrincipalで特定のユーザー・ロールを除いて拒否する

先ほどは Principal: * に設定していたため、全てのユーザー・ロールで拒否されてしまっていました。
なので、 NotPrincipal を使って特定のユーザー・ロールを除いて拒否するようにしましょう。

docs.aws.amazon.com

ただ、公式では NotPrincipal を使うのはあまり推奨されていませんでした。
ご利用は計画的に。

f:id:hesma2:20210227155038p:plain

除きたいユーザーのARNをNotPrincipalに設定します。
公式によると、親アカウントを超える権限を持つことはできないため、ルートユーザーもNotPrincipalに設定する必要があるようです。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": [
                    "arn:aws:iam::444455556666:user/Bob",
                    "arn:aws:iam::444455556666:root"
                ]
            },
            "Action": [
                "s3:DeleteBucketPolicy",
                "s3:PutBucketAcl",
                "s3:PutBucketPolicy",
                "s3:PutEncryptionConfiguration",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::test-bucket-policy-deny",
                "arn:aws:s3:::test-bucket-policy-deny/*"
            ]
        }
    ]
}

これで設定ができたと思われます。

ただ私の環境ではスイッチロールでこのS3のあるアカウントにアクセスしていたため、この設定ではダメなようでした....

f:id:hesma2:20210227154451p:plain
悪夢再び

Conditionでスイッチロール先のロールを除いて拒否する

スイッチロール先にロールを除きたい場合、NotPrincipalではなくConditionを使うことで実現可能でした。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Deny",
            "Principal": "*",
            "Action": [
                "s3:DeleteBucketPolicy",
                "s3:PutBucketAcl",
                "s3:PutBucketPolicy",
                "s3:PutEncryptionConfiguration",
                "s3:PutObjectAcl"
            ],
            "Resource": [
                "arn:aws:s3:::test-bucket-policy-deny",
                "arn:aws:s3:::test-bucket-policy-deny/*"
            ],
            "Condition": {
                "StringNotLike": {
                    "aws:userid": "<role-id>:*"
                }
            }
        }
    ]
}

この設定でスイッチロール先のロールを除いてDenyを設定することができました!!

条件演算子(StringNotLikeなど)については ↓ こちら

docs.aws.amazon.com

ポリシー変数に使用可能なリクエスト情報(aws:useridなど)については ↓ こちら

docs.aws.amazon.com

ロールIDの取得はawsコマンドで可能です

$ aws iam get-role --role-name Test-Role

docs.aws.amazon.com

複数条件でConditionを使いたい場合は ↓ こちらを参照

docs.aws.amazon.com