2023 年 7 月 6 日の請求・コスト管理・アカウントのコンソールの権限廃止・変更のポリシー移行をアシストするために、一括更新スクリプトが提供されました

2023.06.12

いわさです。

半年ほど前の次のアナウンスでも紹介されていますが、aws-portal プレフィックスを始め、いくつかのアクションが 2023 年 7 月 6 日に廃止になります。

以前のアップデートで、既に新しいアクションを有効化して移行の準備を行うことが出来るようなったことを紹介しました。

あと 1 ヶ月弱で既存のアクションが使用できなくなりますが、このタイミングでポリシーの更新をアシストしてくれるスクリプトが提供されました。

先に軽くまとめると、このスクリプトを使うことで廃止予定のアクションを使っているポリシーを抽出し、対象ポリシーに対して新しいアクションへ置き換わったステートメントをサジェストしてくれます。
さらに一括更新機能で、サジェストされたステートメントを既存ポリシーへ追加をしてくれます。
更新されたポリシーの旧アクションは削除されずに新アクションと混在する形になるので、現環境への影響する可能性は低そうですが、7 月 6 日以降は不要なアクションが追加されたままという感じですね。

本日はこちらを実際に使ってみましたのでどんな感じなのか紹介します。

準備

スクリプトは次の GitHub リポジトリで公開されています。
AWS 公式なので安心出来る感じしますね。

使い方の手順は上記の README.md 次の公式ドキュメントに記載されています。

Python 製のスクリプトなので、Python の実行環境が必要です。
あとはクローンしてスクリプト実行するだけです。

% python3 --version
Python 3.9.8
% git clone https://github.com/aws-samples/bulk-policy-migrator-scripts-for-account-cost-billing-consoles.git
Cloning into 'bulk-policy-migrator-scripts-for-account-cost-billing-consoles'...
remote: Enumerating objects: 67, done.
remote: Counting objects: 100% (67/67), done.
remote: Compressing objects: 100% (45/45), done.
remote: Total 67 (delta 32), reused 53 (delta 21), pack-reused 0
Receiving objects: 100% (67/67), 32.24 KiB | 1.34 MiB/s, done.
Resolving deltas: 100% (32/32), done.
% cd bulk-policy-migrator-scripts-for-account-cost-billing-consoles
% python3 -m venv venv
% source venv/bin/activate
(venv) % pip install -r requirements.txt
Collecting boto3
  Downloading boto3-1.26.151-py3-none-any.whl (135 kB)
     |████████████████████████████████| 135 kB 2.6 MB/s 
Collecting botocore<1.30.0,>=1.29.151
  Downloading botocore-1.29.151-py3-none-any.whl (10.9 MB)
     |████████████████████████████████| 10.9 MB 15.9 MB/s 
Collecting s3transfer<0.7.0,>=0.6.0
  Downloading s3transfer-0.6.1-py3-none-any.whl (79 kB)
     |████████████████████████████████| 79 kB 13.0 MB/s 
Collecting jmespath<2.0.0,>=0.7.1
  Downloading jmespath-1.0.1-py3-none-any.whl (20 kB)
Collecting urllib3<1.27,>=1.25.4
  Downloading urllib3-1.26.16-py2.py3-none-any.whl (143 kB)
     |████████████████████████████████| 143 kB 51.2 MB/s 
Collecting python-dateutil<3.0.0,>=2.1
  Using cached python_dateutil-2.8.2-py2.py3-none-any.whl (247 kB)
Collecting six>=1.5
  Using cached six-1.16.0-py2.py3-none-any.whl (11 kB)
Installing collected packages: six, urllib3, python-dateutil, jmespath, botocore, s3transfer, boto3
Successfully installed boto3-1.26.151 botocore-1.29.151 jmespath-1.0.1 python-dateutil-2.8.2 s3transfer-0.6.1 six-1.16.0 urllib3-1.26.16
WARNING: You are using pip version 21.2.4; however, version 23.1.2 is available.
You should consider upgrading via the '/Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/venv/bin/python3 -m pip install --upgrade pip' command.
(venv) % cd policy_migration_scripts/scripts

このスクリプトはマルチアカウントに対応していて、管理アカウントからメンバーアカウントへ AssumeRole してポリシーの検査や更新を行います。
そのため、CloudFormation StackSets などでcfn_templateディレクトリに格納されている次のポリシーをスクリプトのターゲットとなる AWS アカウントへデプロイしておく必要があります。
スクリプトではこのポリシーに AssumeRole する作りになっています。

デプロイ前に Principal のアカウント ID を管理アカウントのものにする必要があります。

cfn_template/billing_console_policy_migrator_role.json

{
  "AWSTemplateFormatVersion": "2010-09-09",
  "Resources": {
    "BillingConsolePolicyMigratorRoleTemplate": {
      "Type": "AWS::IAM::Role",
      "Properties": {
        "AssumeRolePolicyDocument": {
          "Version": "2012-10-17",
          "Statement": [
            {
              "Effect": "Allow",
              "Principal": {
                "AWS": "arn:aws:iam::123456789012:root"
              },
              "Action": "sts:AssumeRole"
            }
          ]
        },
        "Description": "IAM role in member account for bulk policy migrator scripts",
        "Policies": [
          {
            "PolicyName": "BillingConsolePolicyMigratorRolePolicy",
            "PolicyDocument": {
              "Statement": [
                {
                  "Action": [
                    "iam:GetAccountAuthorizationDetails",
                    "iam:GetPolicy",
                    "iam:GetPolicyVersion",
                    "iam:GetUserPolicy",
                    "iam:GetGroupPolicy",
                    "iam:GetRolePolicy",
                    "iam:CreatePolicyVersion",
                    "iam:DeletePolicyVersion",
                    "iam:PutUserPolicy",
                    "iam:PutGroupPolicy",
                    "iam:PutRolePolicy",
                    "iam:SetDefaultPolicyVersion",
                    "iam:ListPolicyVersions"
                  ],
                  "Effect": "Allow",
                  "Resource": "*"
                }
              ],
              "Version": "2012-10-17"
            }
          }
        ],
        "RoleName": "BillingConsolePolicyMigratorRole"
      }
    }
  }
}

影響ポリシーの検査

ではまずはスキャンをしてみます。
ちなみに、マネジメントコンソールでは今回の廃止に伴って影響を受けるポリシーを次の画面から確認することが出来ます。

ここでは次のカスタムポリシーが検出されました。
このポリシーではaws-portal:アクションを使用しています。

ではスクリプトを実行してみましょう。
対象アカウントを指定して実行します。全アカウントを対象にするオプション(all)もあります。

全アカウントを指定した場合は boto3 のlist_accountsをトークンを確認して繰り返しているので、おそらくアカウント数の上限はなくて全件取得してくれそうです。

(venv) % python3 identify_affected_policies.py --accounts 123456789012
2023-06-12 15:51:00,948 - INFO - Caller account: 123456789012
2023-06-12 15:51:00,948 - INFO - Using default action mapping config file
2023-06-12 15:51:00,949 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 15:51:01,275 - INFO - Running in LINKED ACCOUNT mode with accounts: ['123456789012']
2023-06-12 15:51:01,275 - INFO - Running with account: 123456789012
2023-06-12 15:51:01,275 - INFO - Identifying affected policies...
2023-06-12 15:51:02,665 - INFO - Scanning 10 customer managed policies
2023-06-12 15:51:03,358 - INFO - Scanning 10 customer managed policies
2023-06-12 15:51:04,120 - INFO - Scanning 10 customer managed policies
2023-06-12 15:51:04,388 - INFO - Scanning 7 customer managed policies
2023-06-12 15:51:04,388 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 15:51:05,205 - INFO - Scanning 2 users
2023-06-12 15:51:06,041 - INFO - Scanning 0 groups
2023-06-12 15:51:07,158 - INFO - Scanning 10 roles
2023-06-12 15:51:07,687 - INFO - Scanning 10 roles
2023-06-12 15:51:08,174 - INFO - Scanning 10 roles
2023-06-12 15:51:08,485 - INFO - Scanning 10 roles
2023-06-12 15:51:08,967 - INFO - Scanning 10 roles
2023-06-12 15:51:09,296 - INFO - Scanning 10 roles
2023-06-12 15:51:09,830 - INFO - Scanning 10 roles
2023-06-12 15:51:10,205 - INFO - Scanning 6 roles
2023-06-12 15:51:11,479 - INFO - Scanning 10 SCPs
2023-06-12 15:51:12,040 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 15:51:13,909 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 15:51:14,442 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 15:51:15,629 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 15:51:17,980 - INFO - Scanning 2 SCPs
2023-06-12 15:51:18,237 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 15:51:18,519 - INFO - Affected policy report written to Affected_Policies_20230612-15-51-18-517960/affected_policies_and_suggestions.json
2023-06-12 15:51:18,520 - INFO - Detailed policy report written to Affected_Policies_20230612-15-51-18-517960/detailed_affected_policies.json
2023-06-12 15:51:18,520 - INFO - Done

実行すると、何やらレポートが出力されているようなログが出力されています。
上記コマンドを実行すると 2 つのレポートファイル(JSON 形式)にスキャン結果が出力されています。

affected_policies_and_suggestions.jsondetailed_affected_policies.jsonが出力されていますね。

前者は影響を受けるポリシーと推奨される新しいアクションをリスト化したものです。
後者は影響を受けるすべてのポリシー定義です。

前者で概要を把握しつつ、もし詳細なポリシー定義を確認したい場合は各アカウントへアクセスしなくても後者のレポートで確認することが出来ます。
ちょっと長いので折りたたみますが次のような形式で出力されます。

Affected_Policies_20230612-15-51-18-517960/affected_policies_and_suggestions.json

[
    {
        "AccountsScanned": [
            "123456789012"
        ],
        "TotalAffectedAccounts": 1,
        "TotalAffectedPolicies": 6,
        "TotalSimilarPolicyGroups": 2
    },
    {
        "GroupName": "Group1",
        "ImpactedPolicies": [
            {
                "Account": "123456789012",
                "PolicyType": "CustomerManagedPolicy",
                "PolicyName": "before-deny-billing",
                "PolicyIdentifier": "arn:aws:iam::123456789012:policy/before-deny-billing"
            }
        ],
        "ImpactedPolicyStatements": [
            {
                "Effect": "Deny",
                "Action": [
                    "aws-portal:ViewBilling"
                ],
                "Resource": "*"
            }
        ],
        "SuggestedPolicyStatementsToAppend": [
            {
                "Sid": "BillingConsolePolicyMigrator0",
                "Effect": "Deny",
                "Action": [
                    "account:GetAccountInformation",
                    "billing:GetBillingData",
                    "billing:GetBillingDetails",
                    "billing:GetBillingNotifications",
                    "billing:GetBillingPreferences",
                    "billing:GetContractInformation",
                    "billing:GetCredits",
                    "billing:GetIAMAccessPreference",
                    "billing:GetSellerOfRecord",
                    "billing:ListBillingViews",
                    "ce:DescribeNotificationSubscription",
                    "ce:DescribeReport",
                    "ce:GetAnomalies",
                    "ce:GetAnomalyMonitors",
                    "ce:GetAnomalySubscriptions",
                    "ce:GetCostAndUsage",
                    "ce:GetCostAndUsageWithResources",
                    "ce:GetCostCategories",
                    "ce:GetCostForecast",
                    "ce:GetDimensionValues",
                    "ce:GetPreferences",
                    "ce:GetReservationCoverage",
                    "ce:GetReservationPurchaseRecommendation",
                    "ce:GetReservationUtilization",
                    "ce:GetRightsizingRecommendation",
                    "ce:GetSavingsPlansCoverage",
                    "ce:GetSavingsPlansPurchaseRecommendation",
                    "ce:GetSavingsPlansUtilization",
                    "ce:GetSavingsPlansUtilizationDetails",
                    "ce:GetTags",
                    "ce:GetUsageForecast",
                    "ce:ListCostAllocationTags",
                    "ce:ListSavingsPlansPurchaseRecommendationGeneration",
                    "consolidatedbilling:GetAccountBillingRole",
                    "consolidatedbilling:ListLinkedAccounts",
                    "cur:GetClassicReport",
                    "cur:GetClassicReportPreferences",
                    "cur:ValidateReportDestination",
                    "freetier:GetFreeTierAlertPreference",
                    "freetier:GetFreeTierUsage",
                    "invoicing:GetInvoiceEmailDeliveryPreferences",
                    "invoicing:GetInvoicePDF",
                    "invoicing:ListInvoiceSummaries",
                    "payments:GetPaymentInstrument",
                    "payments:GetPaymentStatus",
                    "payments:ListPaymentPreferences",
                    "tax:GetTaxInheritance",
                    "tax:GetTaxRegistrationDocument",
                    "tax:ListTaxRegistrations"
                ],
                "Resource": "*"
            }
        ]
    },
    {
        "GroupName": "Group2",
        "ImpactedPolicies": [
            {
                "Account": "123456789012",
                "PolicyType": "SCP",
                "PolicyName": "aws-guardrails-YBopKh",
                "PolicyIdentifier": "p-krbcbp4z"
            },
            {
                "Account": "123456789012",
                "PolicyType": "SCP",
                "PolicyName": "aws-guardrails-YmqaSS",
                "PolicyIdentifier": "p-g5n3sm0v"
            },
            {
                "Account": "123456789012",
                "PolicyType": "SCP",
                "PolicyName": "aws-guardrails-bqMDcH",
                "PolicyIdentifier": "p-sg2grqs9"
            },
            {
                "Account": "123456789012",
                "PolicyType": "SCP",
                "PolicyName": "aws-guardrails-ojadBN",
                "PolicyIdentifier": "p-prpup0t9"
            },
            {
                "Account": "123456789012",
                "PolicyType": "SCP",
                "PolicyName": "aws-guardrails-GjlytP",
                "PolicyIdentifier": "p-bfz7licy"
            }
        ],
        "ImpactedPolicyStatements": [
            {
                "Effect": "Deny",
                "NotAction": [
                    "aws-portal:*"
                ],
                "Condition": {
                    "StringNotEquals": {
                        "aws:RequestedRegion": [
                            "ap-northeast-3",
                            "ap-northeast-1"
                        ]
                    },
                    "ArnNotLike": {
                        "aws:PrincipalARN": [
                            "arn:aws:iam::*:role/AWSControlTowerExecution"
                        ]
                    }
                },
                "Resource": "*"
            }
        ],
        "SuggestedPolicyStatementsToAppend": [
            {
                "Condition": {
                    "StringNotEquals": {
                        "aws:RequestedRegion": [
                            "ap-northeast-3",
                            "ap-northeast-1"
                        ]
                    },
                    "ArnNotLike": {
                        "aws:PrincipalARN": [
                            "arn:aws:iam::*:role/AWSControlTowerExecution"
                        ]
                    }
                },
                "Resource": "*",
                "Effect": "Deny",
                "NotAction": [
                    "account:CloseAccount",
                    "account:DeleteAlternateContact",
                    "account:GetAccountInformation",
                    "account:GetAlternateContact",
                    "account:GetChallengeQuestions",
                    "account:GetContactInformation",
                    "account:PutAlternateContact",
                    "account:PutChallengeQuestions",
                    "account:PutContactInformation",
                    "billing:GetBillingData",
                    "billing:GetBillingDetails",
                    "billing:GetBillingNotifications",
                    "billing:GetBillingPreferences",
                    "billing:GetContractInformation",
                    "billing:GetCredits",
                    "billing:GetIAMAccessPreference",
                    "billing:GetSellerOfRecord",
                    "billing:ListBillingViews",
                    "billing:PutContractInformation",
                    "billing:RedeemCredits",
                    "billing:UpdateBillingPreferences",
                    "billing:UpdateIAMAccessPreference",
                    "ce:CreateAnomalyMonitor",
                    "ce:CreateAnomalySubscription",
                    "ce:CreateNotificationSubscription",
                    "ce:CreateReport",
                    "ce:DeleteAnomalyMonitor",
                    "ce:DeleteAnomalySubscription",
                    "ce:DeleteNotificationSubscription",
                    "ce:DeleteReport",
                    "ce:DescribeNotificationSubscription",
                    "ce:DescribeReport",
                    "ce:GetAnomalies",
                    "ce:GetAnomalyMonitors",
                    "ce:GetAnomalySubscriptions",
                    "ce:GetCostAndUsage",
                    "ce:GetCostAndUsageWithResources",
                    "ce:GetCostCategories",
                    "ce:GetCostForecast",
                    "ce:GetDimensionValues",
                    "ce:GetPreferences",
                    "ce:GetReservationCoverage",
                    "ce:GetReservationPurchaseRecommendation",
                    "ce:GetReservationUtilization",
                    "ce:GetRightsizingRecommendation",
                    "ce:GetSavingsPlansCoverage",
                    "ce:GetSavingsPlansPurchaseRecommendation",
                    "ce:GetSavingsPlansUtilization",
                    "ce:GetSavingsPlansUtilizationDetails",
                    "ce:GetTags",
                    "ce:GetUsageForecast",
                    "ce:ListCostAllocationTags",
                    "ce:ListSavingsPlansPurchaseRecommendationGeneration",
                    "ce:ProvideAnomalyFeedback",
                    "ce:StartSavingsPlansPurchaseRecommendationGeneration",
                    "ce:UpdateAnomalyMonitor",
                    "ce:UpdateAnomalySubscription",
                    "ce:UpdateCostAllocationTagsStatus",
                    "ce:UpdateNotificationSubscription",
                    "ce:UpdatePreferences",
                    "consolidatedbilling:GetAccountBillingRole",
                    "consolidatedbilling:ListLinkedAccounts",
                    "cur:GetClassicReport",
                    "cur:GetClassicReportPreferences",
                    "cur:GetUsageReport",
                    "cur:PutClassicReportPreferences",
                    "cur:ValidateReportDestination",
                    "freetier:GetFreeTierAlertPreference",
                    "freetier:GetFreeTierUsage",
                    "freetier:PutFreeTierAlertPreference",
                    "invoicing:GetInvoiceEmailDeliveryPreferences",
                    "invoicing:GetInvoicePDF",
                    "invoicing:ListInvoiceSummaries",
                    "invoicing:PutInvoiceEmailDeliveryPreferences",
                    "payments:CreatePaymentInstrument",
                    "payments:DeletePaymentInstrument",
                    "payments:GetPaymentInstrument",
                    "payments:GetPaymentStatus",
                    "payments:ListPaymentPreferences",
                    "payments:MakePayment",
                    "payments:UpdatePaymentPreferences",
                    "tax:BatchPutTaxRegistration",
                    "tax:DeleteTaxRegistration",
                    "tax:GetTaxInheritance",
                    "tax:GetTaxRegistrationDocument",
                    "tax:ListTaxRegistrations",
                    "tax:PutTaxInheritance"
                ],
                "Sid": "BillingConsolePolicyMigrator0"
            }
        ]
    }
]

こちらを見て気がついたのですが、どうやら SCP でも該当アクションが使われているようだということがわかりました。
たしかに検出された SCP を確認してみると次のように廃止予定のアクションが含まれています。

このアカウントは Control Tower を有効化していたのですが、どうやらその際に自動作成されているようですね。
ということは今回のこのアクション廃止って Control Tower 有効化している全ユーザーに影響ありか?

更新

このスクリプトでは検出だけでなく、ポリシーの一括更新を行うことも出来ます。
先程レポートが出力されたディレクトリ指定して更新コマンドを実行することが出来ます。

今回はそのまま更新しますが、事前に手動でaffected_policies_and_suggestions.jsonを修正することで、サジェストされた内容に手を加えた形でポリシーを変更することも出来ます。

(venv) % python3 update_affected_policies.py --affected-policies-directory Affected_Policies_20230612-15-51-18-517960 
2023-06-12 16:06:05,416 - INFO - Running update script with argument: Affected_Policies_20230612-15-51-18-517960
2023-06-12 16:06:06,266 - INFO - Caller account: 123456789012
2023-06-12 16:06:07,148 - INFO - Validating input directory: Affected_Policies_20230612-15-51-18-517960
2023-06-12 16:06:07,151 - INFO - Fetching all accounts in the organization...
2023-06-12 16:06:07,509 - INFO - Validating input data...
2023-06-12 16:06:07,510 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 16:06:07,512 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 16:06:07,512 - INFO - Finished validating input data
2023-06-12 16:06:07,512 - INFO - Number of worker threads used: 3
2023-06-12 16:06:07,513 - INFO - Starting to update policies in Group Group1
2023-06-12 16:06:07,513 - INFO - Starting to update policies in Group Group2
2023-06-12 16:06:07,818 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 16:06:08,602 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 16:06:08,698 - INFO - Successfully updated policy. PolicyName = aws-guardrails-YBopKh, PolicyType = SCP, PolicyIdentifier = p-krbcbp4z, Account = 123456789012
2023-06-12 16:06:08,980 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 16:06:09,241 - INFO - Successfully updated policy. PolicyName = before-deny-billing, PolicyType = CustomerManagedPolicy, PolicyIdentifier = arn:aws:iam::123456789012:policy/before-deny-billing, Account = 123456789012
2023-06-12 16:06:09,242 - INFO - Finished updating policies in Group Group1
2023-06-12 16:06:09,830 - INFO - Successfully updated policy. PolicyName = aws-guardrails-YmqaSS, PolicyType = SCP, PolicyIdentifier = p-g5n3sm0v, Account = 123456789012
2023-06-12 16:06:10,106 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 16:06:10,768 - INFO - Successfully updated policy. PolicyName = aws-guardrails-bqMDcH, PolicyType = SCP, PolicyIdentifier = p-sg2grqs9, Account = 123456789012
2023-06-12 16:06:12,347 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 16:06:12,971 - INFO - Successfully updated policy. PolicyName = aws-guardrails-ojadBN, PolicyType = SCP, PolicyIdentifier = p-prpup0t9, Account = 123456789012
2023-06-12 16:06:14,008 - INFO - Loading default old to new action mapping file from /Users/iwasa.takahito/work/hoge0612iam/bulk-policy-migrator-scripts-for-account-cost-billing-consoles/policy_migration_scripts/config/action_mapping_config.json
2023-06-12 16:06:14,567 - ERROR - Failed updating policy. PolicyName = aws-guardrails-GjlytP, PolicyType = SCP, PolicyIdentifier = p-bfz7licy, Account = 123456789012, Error = An error occurred (ConstraintViolationException) when calling the UpdatePolicy operation: You have exceeded the maximum policy size.
2023-06-12 16:06:14,568 - INFO - Finished updating policies in Group Group2
2023-06-12 16:06:14,568 - ERROR - Encountered errors when updating affected policies
2023-06-12 16:06:14,569 - ERROR - Error report written to file UpdateAffectedPolicies-ErrorReport-20230612-16-06-14-568859.json. Please review the errors and refer to FAQ on next steps
2023-06-12 16:06:14,569 - INFO - Done

どうやら更新処理中にエラーが発生したようです。
UpdateAffectedPolicies-ErrorReport-20230612-16-06-14-568859.jsonを確認することでエラー原因を特定することが出来ます。

UpdateAffectedPolicies-ErrorReport-20230612-16-06-14-568859.json

[
    {
        "GroupName": "Group2",
        "Account": "123456789012",
        "PolicyType": "SCP",
        "PolicyName": "aws-guardrails-GjlytP",
        "UserOrGroupOrRoleName": "p-bfz7licy",
        "Status": "FAILURE",
        "ErrorMessage": "ConstraintViolationException: You have exceeded the maximum policy size."
    }
]

ポリシーのサイズ上限に達したたためにエラーが発生したとのこと。なるほど。
ステートメントを追加する形なのでこのエラーが発生するリスクはありますね。

一つのポリシー更新に失敗したようですが、他のポリシーについては次のように更新されていました。

先程サジェストされていたステートメントが追加されていますね。
また、どれか一つでエラーが発生したとしても全てのポリシー更新に失敗するわけではないということがわかりました。

ちなみに、SCP もサジェストされたステートメントが追加される形で更新されていました。

ただし、更新後に「AWS Control Tower drift warning: A managed service control policy was modified.」という件名で次の内容のエラー通知メールを受信するようになりました。

{
"Message" : "AWS Control Tower has detected that the managed service control policy 'aws-guardrails-YBopKh (p-krbcbp4z)', attached to the registered organizational unit 'Sandbox (ou-s4h9-a17cffj6)', has been modified. For more information, including steps to resolve this issue, see https://docs.aws.amazon.com/controltower/latest/userguide/drift.html#drift-scp-update",
"MasterAccountId" : "123456789012",
"ManagementAccountId" : "123456789012",
"OrganizationId" : "o-8j81brsjuj",
"DriftType" : "SCP_UPDATED",
"RemediationStep" : "Re-register this organizational unit (OU), or if the OU has more than 300 accounts, you must update your landing zone.",
"OrganizationalUnitId" : "ou-s4h9-a17cffj6",
"PolicyId" : "p-krbcbp4z"
}

Control Tower のドリフト検出機能で検出されたようです。
廃止に伴ってこれらの SCP をどのように更新すべきかは検討が必要ですね。

ロールバック

先程ポリシーを一括更新しましたが、更新をロールバックする機能もあります。
次のコマンドで、アカウントを指定してロールバックすることが出来ます。

(venv) % python3 rollback_affected_policies.py --accounts 123456789012
2023-06-12 16:12:46,437 - INFO - {'include_all': False, 'accounts': ['123456789012'], 'excluded_accounts': []}
2023-06-12 16:12:48,630 - INFO - Running in LINKED ACCOUNT mode with accounts: ['123456789012']
2023-06-12 16:12:50,606 - INFO - Successfully rolled back policy. PolicyName = aws-guardrails-YBopKh, PolicyType = Service_Control_Policy, PolicyId = p-krbcbp4z, Account = 123456789012.
2023-06-12 16:12:51,765 - INFO - Successfully rolled back policy. PolicyName = aws-guardrails-YmqaSS, PolicyType = Service_Control_Policy, PolicyId = p-g5n3sm0v, Account = 123456789012.
2023-06-12 16:12:52,736 - INFO - Successfully rolled back policy. PolicyName = aws-guardrails-bqMDcH, PolicyType = Service_Control_Policy, PolicyId = p-sg2grqs9, Account = 123456789012.
2023-06-12 16:12:54,830 - INFO - Successfully rolled back policy. PolicyName = aws-guardrails-ojadBN, PolicyType = Service_Control_Policy, PolicyId = p-prpup0t9, Account = 123456789012.
2023-06-12 16:13:02,755 - INFO - Successfully rolled back policy. PolicyName = before-deny-billing, PolicyType = Customer_Managed_Policy, PolicyId = ANPA24V6CVCVO4UASL2OB, Account = 123456789012.
2023-06-12 16:13:05,788 - INFO - Successfully rolled back all policies
2023-06-12 16:13:05,788 - INFO - Rollback summary report written to file RollBack-Report-20230612-16-13-05-787631.json.

ロールバック後、ポリシーに先程追加されていたステートメントが削除されていました。

さいごに

本日は 2023 年 7 月 6 日の請求・コスト管理・アカウントのコンソールの権限廃止・変更のポリシー移行をアシストするために、一括更新スクリプトが提供されたので使ってみました。

まず、検出についてはアカウント一括でスキャン出来るのでこれはかなり良いですね。是非つかっていきたい。
一括更新も使えるとは思うのですが、今回発生したポリシーのサイズ制限のようにエラーが発生するのでスムーズにいかない場合がある点については覚えておきたいです。

Control Tower の SCP どうするかな?これは別途考えてみたいです。