AWS Control Tower における OU に対してリージョン制限を実施するコントロールの例外設定を試してみた

2023.11.30

先日の AWS Control Tower のアップデートにより、ランディングゾーン設定のリージョン制限とは別に OU に対するリージョン制限ができるコントロールが追加されました。このブログでは、本コントロールにおけるオプション設定である、追加で許可するアクションの設定と Exempted (免除される) IAM プリンシパルの設定をした場合の動作を確認してみたいと思います。

OU に対するリージョン制限の設定

OU に対するリージョン制限を実現するのは次のコントロールです。

CT.MULTISERVICE.PV.1: Deny access to AWS based on the requested AWS Region for an organizational unit


本コントロールの設定では単純にリージョン制限をするだけではなく、追加で許可するアクションと Exempted (免除される) IAM プリンシパルの設定ができます。以降、本ブログ内に限り、追加で許可するアクションと Exempted (免除される) IAM プリンシパルを「例外アクション」と「例外 IAM プリンシパル」と呼ぶことにします。


検証環境の前提条件

今回、検証する AWS Control Tower 環境は、ランディングゾーン設定として次の 3 つのリージョンを管理対象としており、かつ管理対象以外のリージョンは拒否設定にしています。

  • 東京リージョン
  • バージニア北部リージョン
  • オレゴンリージョン

また、テスト用に Sandbox OU を Root 直下に作成している環境です。この Sandbox OU にリージョン制限コントロールを適用します。


コントロールの設定

管理アカウントの AWS Control Tower におけるコントロールライブラリから「CT.MULTISERVICE.PV.1」を探して「コントロールを有効にする」を選択します。

ステップ 1 では、リージョン制限を適用する OU を選択します。

ステップ 2 では、利用するリージョン(制限しないリージョン)を選択します。今回は東京リージョンのみを選択します。

ステップ 3 では、例外アクションを選択します。SCP における Action (NotAction) に該当する部分を指定することに相当します。今回はテスト目的のため、分かりやすく EC2 の全てのアクションを許可するec2:*を指定してみます。

ステップ 4 では、例外 IAM プリンシパル(IAM ユーザーや IAM ロールなど)を設定します。今回は、AWS IAM Identity Center のアクセス許可セットで作成済みの ReadOnlyAccess を対象としてみます。なお、アクセス許可セットの ReadOnlyAccess には AWS 管理ポリシーの ReadOnlyAccess を権限としてアタッチしています。

AWS IAM Identity Center においてアクセス許可セットをアカウントを割り当てると、アクセス先アカウントに IAM ロールが作成されるため、そのロールを指定します。例えば、次のようなロール名で作成されます。

arn:aws:iam::111122223333:role/aws-reserved/sso.amazonaws.com/ap-northeast-1/AWSReservedSSO_ReadOnlyAccess_cae8a24ccaa80a9a

このうち、AWS アカウント名と最後の乱数部分はアカウント毎に異なるため、ワイルドカード指定として次の内容をコントロールに設定します。パスに含まれるリージョン名は IAM Identity Center を構築しているリージョン名となっているため、そのままでも問題ありません。

arn:aws:iam::*:role/aws-reserved/sso.amazonaws.com/ap-northeast-1/AWSReservedSSO_ReadOnlyAccess_*


最後に、設定内容を確認して「コントロールを有効にする」をクリックすれば設定完了です。


設定されている SCP を確認してみます。他のコントロールと合わせて一つの SCP として存在していたため、OU に対するリージョン制限部分のみを抽出しています。ハイライトしている 2 行が例外アクションと例外 IAM プリンシパルとして反映された部分です。

    {
      "Condition": {
        "StringNotEquals": {
          "aws:RequestedRegion": [
            "ap-northeast-1"
          ]
        },
        "ArnNotLike": {
          "aws:PrincipalARN": [
            "arn:aws:iam::*:role/aws-reserved/sso.amazonaws.com/ap-northeast-1/AWSReservedSSO_ReadOnlyAccess_*",
            "arn:*:iam::*:role/AWSControlTowerExecution",
            "arn:*:iam::*:role/aws-controltower-ConfigRecorderRole",
            "arn:*:iam::*:role/aws-controltower-ForwardSnsNotificationRole",
            "arn:*:iam::*:role/AWSControlTower_VPCFlowLogsRole"
          ]
        }
      },
      "Resource": "*",
      "Effect": "Deny",
      "NotAction": [
        "ec2:*",
        "a4b:*",
        "access-analyzer:*",
        "account:*",
        "acm:*",
        "activate:*",
        "artifact:*",
        "aws-marketplace-management:*",
        "aws-marketplace:*",
        "aws-portal:*",
        "billing:*",
        "billingconductor:*",
        "budgets:*",
        "ce:*",
        "chatbot:*",
        "chime:*",
        "cloudfront:*",
        "cloudtrail:LookupEvents",
        "compute-optimizer:*",
        "config:*",
        "consoleapp:*",
        "consolidatedbilling:*",
        "cur:*",
        "datapipeline:GetAccountLimits",
        "devicefarm:*",
        "directconnect:*",
        "ec2:DescribeRegions",
        "ec2:DescribeTransitGateways",
        "ec2:DescribeVpnGateways",
        "ecr-public:*",
        "fms:*",
        "freetier:*",
        "globalaccelerator:*",
        "health:*",
        "iam:*",
        "importexport:*",
        "invoicing:*",
        "iq:*",
        "kms:*",
        "license-manager:ListReceivedLicenses",
        "lightsail:Get*",
        "mobileanalytics:*",
        "networkmanager:*",
        "notifications-contacts:*",
        "notifications:*",
        "organizations:*",
        "payments:*",
        "pricing:*",
        "quicksight:DescribeAccountSubscription",
        "resource-explorer-2:*",
        "route53-recovery-cluster:*",
        "route53-recovery-control-config:*",
        "route53-recovery-readiness:*",
        "route53:*",
        "route53domains:*",
        "s3:CreateMultiRegionAccessPoint",
        "s3:DeleteMultiRegionAccessPoint",
        "s3:DescribeMultiRegionAccessPointOperation",
        "s3:GetAccountPublicAccessBlock",
        "s3:GetBucketLocation",
        "s3:GetBucketPolicyStatus",
        "s3:GetBucketPublicAccessBlock",
        "s3:GetMultiRegionAccessPoint",
        "s3:GetMultiRegionAccessPointPolicy",
        "s3:GetMultiRegionAccessPointPolicyStatus",
        "s3:GetStorageLensConfiguration",
        "s3:GetStorageLensDashboard",
        "s3:ListAllMyBuckets",
        "s3:ListMultiRegionAccessPoints",
        "s3:ListStorageLensConfigurations",
        "s3:PutAccountPublicAccessBlock",
        "s3:PutMultiRegionAccessPointPolicy",
        "savingsplans:*",
        "shield:*",
        "sso:*",
        "sts:*",
        "support:*",
        "supportapp:*",
        "supportplans:*",
        "sustainability:*",
        "tag:GetResources",
        "tax:*",
        "trustedadvisor:*",
        "vendor-insights:ListEntitledSecurityProfiles",
        "waf-regional:*",
        "waf:*",
        "wafv2:*"
      ],
      "Sid": "CTMULTISERVICEPV1"
    }


上記とは別にランディングゾーン設定のリージョン拒否設定も同じ SCP 内に設定されていました。

OU に対するリージョン制限と比べて、アクションと IAM プリンシパルに違いがあります。こちらも SCP から一部抜粋して記載しています。例外アクションや例外 IAM プリンシパルとして指定した内容がないのは当たり前ですが、AWS Control Tower 関連の IAM プリンシパルの免除も一部異なって異なります。OU に対するリージョン制限コントロールの方では、AWS Config や VPC フローログに関する Control Tower のロールも免除されていました。

    {
      "Condition": {
        "StringNotEquals": {
          "aws:RequestedRegion": [
            "ap-northeast-1",
            "us-east-1",
            "us-west-2"
          ]
        },
        "ArnNotLike": {
          "aws:PrincipalARN": [
            "arn:aws:iam::*:role/AWSControlTowerExecution"
          ]
        }
      },
      "Resource": "*",
      "Effect": "Deny",
      "NotAction": [
        "a4b:*",
        "access-analyzer:*",
        "account:*",
        "acm:*",
        "activate:*",
        "artifact:*",
        "aws-marketplace-management:*",
        "aws-marketplace:*",
        "aws-portal:*",
        "billing:*",
        "billingconductor:*",
        "budgets:*",
        "ce:*",
        "chatbot:*",
        "chime:*",
        "cloudfront:*",
        "cloudtrail:LookupEvents",
        "compute-optimizer:*",
        "config:*",
        "consoleapp:*",
        "consolidatedbilling:*",
        "cur:*",
        "datapipeline:GetAccountLimits",
        "devicefarm:*",
        "directconnect:*",
        "discovery-marketplace:*",
        "ec2:DescribeRegions",
        "ec2:DescribeTransitGateways",
        "ec2:DescribeVpnGateways",
        "ecr-public:*",
        "fms:*",
        "freetier:*",
        "globalaccelerator:*",
        "health:*",
        "iam:*",
        "importexport:*",
        "invoicing:*",
        "iq:*",
        "kms:*",
        "license-manager:ListReceivedLicenses",
        "lightsail:Get*",
        "mobileanalytics:*",
        "networkmanager:*",
        "notifications-contacts:*",
        "notifications:*",
        "organizations:*",
        "payments:*",
        "pricing:*",
        "resource-explorer-2:*",
        "route53-recovery-cluster:*",
        "route53-recovery-control-config:*",
        "route53-recovery-readiness:*",
        "route53:*",
        "route53domains:*",
        "s3:CreateMultiRegionAccessPoint",
        "s3:DeleteMultiRegionAccessPoint",
        "s3:DescribeMultiRegionAccessPointOperation",
        "s3:GetAccountPublicAccessBlock",
        "s3:GetBucketLocation",
        "s3:GetBucketPolicyStatus",
        "s3:GetBucketPublicAccessBlock",
        "s3:GetMultiRegionAccessPoint",
        "s3:GetMultiRegionAccessPointPolicy",
        "s3:GetMultiRegionAccessPointPolicyStatus",
        "s3:GetStorageLensConfiguration",
        "s3:GetStorageLensDashboard",
        "s3:ListAllMyBuckets",
        "s3:ListMultiRegionAccessPoints",
        "s3:ListStorageLensConfigurations",
        "s3:PutAccountPublicAccessBlock",
        "s3:PutMultiRegionAccessPointPolicy",
        "savingsplans:*",
        "shield:*",
        "sso:*",
        "sts:*",
        "support:*",
        "supportapp:*",
        "supportplans:*",
        "sustainability:*",
        "tag:GetResources",
        "tax:*",
        "trustedadvisor:*",
        "vendor-insights:ListEntitledSecurityProfiles",
        "waf-regional:*",
        "waf:*",
        "wafv2:*"
      ],
      "Sid": "GRREGIONDENY"
    },


コントロールの動作確認

OU に対するリージョン制限を適用した AWS アカウントに対して、次の確認を行いました。権限でとなっている項目は閲覧もしくは操作できることを示します。OU に対するリージョン制限では東京リージョンのみを利用可能として設定しており、EC2 に関するアクションと ReadOnlyAccess のアクセス許可セットを利用しているユーザーを制限の例外としており、意図通り動作していました。

アクセス許可セット リージョン EC2 の権限 EC2 以外のリージョナルサービスの権限(ELB など)
AdministratorAccess 東京
バージニア北部
例外サービスのため
-
ReadOnlyAccess 東京
バージニア北部
例外 IAM プリンシパルのため

例外 IAM プリンシパルのため


以降は、各パターンをマネジメントコンソールで確認した結果です。

AdministratorAccess 権限で東京リージョンの EC2 ダッシュボードにアクセスした結果です。問題ありません。

AdministratorAccess 権限でバージニア北部リージョンの EC2 ダッシュボードにアクセスした結果です。例外アクションとして EC2 関連のアクションを設定していたことから、読み取りに成功しています。例外として設定されていない ELB 関連のロードバランサーや Auto Scaling グループは読み取りに失敗しています。

ReadOnlyAccess 権限で東京リージョンの EC2 ダッシュボードにアクセスした結果です。問題ありません。

ReadOnlyAccess 権限でバージニア北部リージョンの EC2 ダッシュボードにアクセスした結果です。問題ありません。

以上で、OU に対するリージョン制限を実施するコントロールの設定お試しは終わりです。

さいごに

新たに追加された OU に対するリージョン制限を実施するコントロールにおける、追加で許可するアクションと Exempted (免除される) IAM プリンシパルの設定を試してみました。

ランディングゾーン設定における管理対象外リージョンの拒否設定では、アクションの追加や IAM プリンシパルの例外を設定することができないため、ランディングゾーン設定の管理対象リージョンは全てのリージョンとしておき、例外を設定した OU に対するリージョン制限コントロールをすべての OU に展開する、といった活用方法も考えられそうです。

以上、このブログがどなかたのご参考になれば幸いです。