IAMで副作用なくリージョン縛りをする方法


やりたいこと

IAMでリージョン縛りをする(特定のリージョンから来たリクエスト以外は弾く)ポリシーを書く方法を確認する。
素でやるとCloudFrontやIAM自身のようなグローバルサービスも「東京以外」扱いで弾かれてしまうので、それを回避する必要がある。

NGパターン

  • 以下のようなポリシーを書きたくなるが、これは失敗する(正確には、リージョン制限は利くのだがIAM、CloudFront、Route53といったグローバルサービスも共倒れになる)。グローバルサービスのエンドポイントが北バージニア(us-east-1)に存在することが原因。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyAllActionsNotFromTokyo",
            "Effect": "Deny",
            "Action": "*",
            "Resource": "*",
            "Condition": {
                "StringNotEquals": {
                    "aws:RequestedRegion": [
                        "ap-norhteast-1"
                    ]
                }
            }
        },
        {
            "Sid": "AllowAllActios",
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}

OKパターン

  • 以下のように改修すればOK。
    • ここではS3、CloudFront、IAM、Route53、サポートの5つのサービスを"東京縛り"の除外対象としている。
    • NotActionがポイント。「以下のアクションはコンディション句を経た結果としての明示的なDenyから除外する」という意味となり、これによって後続の明示的なAllowで許可される余地が生まれる(明示的なDenyはそれ以外の全てに優先するので、これをしてしまうと、どう頑張ってもAllowはできなくなる点に注意)。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyAllActionsNotFromTokyo",
            "Effect": "Deny",
            "NotAction": [
                "s3:*",
                "cloudfront:*",
                "iam:*",
                "route53:*",
                "support:*"
            ],
            "Resource": "*",
            "Condition": {
                "StringNotEquals": {
                    "aws:RequestedRegion": [
                        "ap-northeast-1"
                    ]
                }
            }
        },
        {
            "Sid": "AllowAllActios",
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}

裏技パターン

  • グローバルサービスのエンドポイントが北バージニア(us-east-1)にあることを逆手に取ると、最初のポリシーでも動くようになる。
    • グローバルサービス触るときは北バージニア用のIAMユーザーないしIAMロールでやる、というルール決めができるなら、多分これでも運用に乗る。
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "DenyAllActionsNotFromTokyo",
            "Effect": "Deny",
            "Action": "*",
            "Resource": "*",
            "Condition": {
                "StringNotEquals": {
                    "aws:RequestedRegion": [
                        "us-east-1"
                    ]
                }
            }
        },
        {
            "Sid": "AllowAllActios",
            "Effect": "Allow",
            "Action": "*",
            "Resource": "*"
        }
    ]
}

おまけ

S3はグローバルサービスだと思っていたが、バケットごとにエンドポイントが分かれる(言われてみれば・・・)ので、最初のポリシーで試すと以下のような状態になる(北米のバケットが「エラー」として表示される。バケットの中身も勿論閲覧不可)。