S3のバケットポリシーで NotPrincipal を使った例外指定

特定のユーザー以外からの操作を弾く

S3のバケットポリシーを使って特定のユーザー以外からの操作を弾く場合、NotPrincipalを使って以下のように指定します。
前提としてユーザーにはS3FullAccess権限を付加しており、通常のバケットであれば読み書き可能な設定にしています。

例-ユーザーget-ok-user以外はS3からのGetObjectアクションを許さない
{
    "Version": "2008-10-17",
    "Id": "PolicyDemo",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root"
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::<BUCKET_NAME>",
                "arn:aws:s3:::<BUCKET_NAME>/*"
            ]
        },
        {
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": [
                    "arn:aws:iam::123456789012:user/get-ok-user"
                ]
            },
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::<BUCKET_NAME>",
                "arn:aws:s3:::<BUCKET_NAME>/*"
            ]
        }
    ]
}

上記のバケットポリシーによりこのバケットに対してアカウント内のすべてのユーザーにすべてのS3の動作を許可(Allow)したうえで、ユーザーget-ok-user以外にはGetObjectの動作を拒否(deny)しています。つまり、ユーザーget-ok-user以外は書き込みはできても読み込みができない設定です。

$ # get-ok-userによるPutObject - 成功
$ aws --profile get-ok-user s3api put-object --bucket <BUCKET_NAME> --key test.txt --body test.txt
{
    "ETag": "\"90466c2a198524f73a0e83ab23978d35\""
}

$ # get-ok-userによるGetObject - 成功
$ aws --profile get-ok-user s3api get-object --bucket <BUCKET_NAME> --key test.txt test.txt
{
    "AcceptRanges": "bytes",
    "ContentType": "binary/octet-stream",
    "LastModified": "Wed, 06 Dec 2017 06:27:46 GMT",
    "ContentLength": 17,
    "ETag": "\"90466c2a198524f73a0e83ab23978d35\"",
    "Metadata": {}
}

$ # get-unspecified-userによるGetObject - 成功
$ aws --profile get-unspecified-user s3api put-object --bucket <BUCKET_NAME> --key test.txt --body test.txt
{
    "ETag": "\"90466c2a198524f73a0e83ab23978d35\""
}

$ # get-unspecified-userによるGetObject - 失敗
$ aws --profile get-unspecified-user s3api get-object --bucket <BUCKET_NAME> --key test.txt test.txt

An error occurred (AccessDenied) when calling the GetObject operation: Access Denied

特定のEC2インスタンス以外からの操作を弾く

次に特定のIAMロールを付加したEC2インスタンス以外からの操作を弾く場合はどうするのでしょうか。
この場合、NotPrincipalにロール名を記載するだけでは正しく機能しません。ロールとロールを引き受けた(AssumedRole)ロールユーザーを指定する必要があります。EC2インスタンスの場合、インスタンスIDがロールユーザーとなります。尚、ここで指定するインスタンスIDにはワイルドカードは使えません。

例-特定のIAMロールを付加したEC2インスタンス以外はS3からのGetObjectアクションを許さない
{
    "Version": "2008-10-17",
    "Id": "PolicyDemo",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root"
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::<BUCKET_NAME>",
                "arn:aws:s3:::<BUCKET_NAME>/*"
            ]
        },
        {
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": [
                    "arn:aws:iam::123456789012:role/ec2-get-ok-role",
                    "arn:aws:sts::123456789012:assumed-role/ec2-get-ok-role/i-0123456789abcdef"
                ]
            },
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::<BUCKET_NAME>",
                "arn:aws:s3:::<BUCKET_NAME>/*"
            ]
        }
    ]
}

特定のLambdaファンクション以外からの操作を弾く

では、特定のLambdaファンクション以外からの操作を弾く場合はどうするのでしょうか。
この場合もEC2インスタンスと同様にNotPrincipalにロール名を記載するだけでは正しく機能しません。ロールとロールを引き受けた(AssumedRole)ロールユーザーを指定する必要があります。Lambdaファンクションの場合、ファンクション名がロールユーザーとなります。尚、ここで指定するファンクション名にもワイルドカードは使えません。

例-特定のLambdaファンクション以外はS3からのGetObjectアクションを許さない
{
    "Version": "2008-10-17",
    "Id": "PolicyDemo",
    "Statement": [
        {
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::123456789012:root"
            },
            "Action": "s3:*",
            "Resource": [
                "arn:aws:s3:::<BUCKET_NAME>",
                "arn:aws:s3:::<BUCKET_NAME>/*"
            ]
        },
        {
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": [
                    "arn:aws:iam::123456789012:role/lambda-get-ok-role",
                    "arn:aws:sts::123456789012:assumed-role/lambda-get-ok-role/<LambdaFunctionName>"
                ]
            },
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::<BUCKET_NAME>",
                "arn:aws:s3:::<BUCKET_NAME>/*"
            ]
        }
    ]
}

補足

異なるアカウントに対して例外を指定する場合は、そのアカウントも指定する必要があります。

        {
            "Effect": "Deny",
            "NotPrincipal": {
                "AWS": [
                    "arn:aws:iam::987654321098:root",
                    "arn:aws:iam::987654321098:role/lambda-get-ok-role",
                    "arn:aws:sts::987654321098:assumed-role/lambda-get-ok-role/<LambdaFunctionName>"
                ]
            },
            "Action": "s3:GetObject",
            "Resource": [
                "arn:aws:s3:::<BUCKET_NAME>",
                "arn:aws:s3:::<BUCKET_NAME>/*"
            ]
        }