aws-samples/sample-ControlTower-Organization-ReRegistration
GitHub: aws-samples/sample-ControlTower-Organization-ReRegistration
自动化解决 AWS Control Tower Landing Zone 更新后组织单位与账户之间混合治理问题的事件驱动解决方案。
Stars: 3 | Forks: 1
# ControlTower 组织重新注册自动化





## 目录
* [概述](#overview)
* [理解混合治理问题](#understanding-the-mixed-governance-problem)
* [理解大规模下的问题](#why-this-becomes-challenging-at-scale)
* [自动化策略](#the-automation-strategy)
* [ResetEnabledBaseline 行为](#resetenabledbaseline-behavior)
* [控制台与 API 行为对比](#console-vs-api-behavior)
* [前提条件](#prerequisites)
* [架构概述](#architecture-overview)
* [服务](#services)
* [架构](#architecture)
* [组织单位](#organizational-units)
* [组织单位引擎行为深入解析](#organizational-units-engine-deployment-behavior-deep-dive)
* [组织单位引擎部署配置](#ou-engine-deployment-configuration)
* [账户](#accounts)
* [账户引擎行为深入解析](#accounts-engine-deployment-behavior-deep-dive)
* [账户引擎部署配置](#accounts-engine-deployment-configuration)
* [关闭账户哨兵](#closed-account-sentinel)
* [关闭账户哨兵部署配置](#closed-account-sentinel-deployment-configuration)
* [关闭账户哨兵模式](#cas-parameter-4)
* [扫描模式](#scanning-mode)
* [SC ( Service Catalog ) 清理模式](#sc-clean-up-mode)
* [常见问题解答](#faqs)
* [清理](#cleanup)
* [原则](#tenets)
* [修订版本](#revisions)
* [声明](#notices)
* [作者](#authors)
* [安全](#security)
* [许可证](#license)
# 概述
## 自动化 OU 重新注册以解决 AWS Control Tower 中的混合治理问题
更新您的 Control Tower Landing Zone 应该是一项常规操作。然而,当之后出现问题时,特别是在大型组织中,体验很快就会变得令人沮丧。
修改 Landing Zone 区域设置(无论是添加还是删除区域)最常见的副作用之一是,在启用了额外控制的组织单位 (OU) 中引入了**混合治理**。
让我们来看看为什么会发生这种情况,为什么它在规模化时会成为运维挑战,以及我们如何安全有效地自动化修复过程。
## 理解混合治理问题
当您更新 Landing Zone 并修改区域设置时:
* OU 配置会被更新。
* 这些 OU 下的子账户不会自动收到相同的更新。
这会在以下两者之间造成配置漂移:
* OU 基线
* 已注册的账户
这种差异正是导致**混合治理**的原因。
[文档化解决方案](https://docs.aws.amazon.com/controltower/latest/userguide/mixed-governance.html)很简单:
重新注册会强制 Control Tower 同步 OU 及其所有子账户。
## 为什么在规模化时这会变得具有挑战性
在较小的环境中,这很简单。
在拥有以下特征的较大型组织中:
* 数百个组织单位
* 数千个账户
这会变得极其复杂。
一次只能重新注册一个组织单位,这使得该过程在大型环境中极具运维挑战性。
此外,当组织单位处于混合治理状态时,Control Tower 不允许启用控制。此限制可能会引入合规性问题,特别是当必须快速部署新控制以满足治理或监管要求时。
您可以想象每次 Landing Zone 更新后的运维开销,如果每个 OU 都必须手动逐一重新注册的话。
显然,自动化不仅是有帮助的,而且是必不可少的。
# 自动化策略
为了解决这个问题,该解决方案有助于自动化重新注册过程。
[文章](https://docs.aws.amazon.com/controltower/latest/userguide/walkthrough-baseline-steps.html)出色地解释了如何使用 API 重新注册 OU。我们在此基础上进行构建,并将其扩展为一个完全自动化的、事件驱动的解决方案,以更新所有 Control Tower 托管账户。
然而,有一个经常被忽视的重要细节。
## ResetEnabledBaseline 行为
当 `ResetEnabledBaseline` 执行时,它仅处理**基线更新**。它不会重置或重新应用组织单位上可能已启用的可选控制。
这种区分至关重要。
## 理解基线和控制之间的区别
现在我们知道 `ResetEnabledBaseline` 仅处理基线,让我们看看为什么这很重要。
对于绿地组织而言,这可能不会引入问题。如果未启用可选的区域控制,重置基线通常就足够了。
然而,在已经启用了多个可选的区域控制的棕地环境中,仅仅重置基线可能会重新引入混合治理。发生这种情况是因为:
* 基线被重置。
* 可选控制未被重置。
* 账户级别的配置可能保持不一致。
这是 API 驱动自动化后持续出现混合治理的最常见原因之一。
## 控制台与 API 行为对比
| 操作 | 控制台 | API |
| --------------------- | ------- | --- |
| 基线更新 | ✅ | ✅ |
| 控制重新评估 | ✅ | ❌ |
此解决方案通过自动化弥补了这一差距。
当您通过 **Control Tower 控制台**重新注册组织单位时,以下两项:
* 基线更新
* 控制重新评估
会被自动处理。
使用 API 时,行为会有所不同。基线和控制操作是分开的,而 `ResetEnabledBaseline` 并不同时涵盖两者。
如前所述,我们的目标是构建一个端到端的完全自动化解决方案,确保在 Landing Zone 变更后整个组织得到妥善更新。
我们从账户级别的自动化开始,然后转向组织单位自动化。
# 前提条件
在部署此解决方案之前,请确保:
1. 拥有一个正常运行的 Control Tower 环境。
2. **所有账户必须**处于非错误状态,以确保自动化工作流程顺畅。如果您希望从自动化中排除特定的 OU 或账户,请参阅 **[常见问题解答](#faqs-7)**。
3. 具备足够的权限以部署 CloudFormation 堆栈及所有相关资源。
4. 具备足够的权限以创建模板中定义的 IAM 角色。
# 架构概述
## 服务
该解决方案利用了:
* Control Tower [生命周期事件](https://docs.aws.amazon.com/controltower/latest/userguide/lifecycle-events.html)
* Amazon EventBridge
* AWS Lambda
* AWS Organizations
* AWS Service Catalog
* CloudWatch Logs
* IAM
* CloudFormation
## 架构
### 组织单位
让我们看一下组织单位自动化工作流程。下图说明了我们将深入探讨的组件。

## 组织单位引擎部署行为深入解析
1. CloudFormation 首先部署一组强制性资源。无论参数配置如何,这些资源都会被创建。
1. CloudWatch 日志组
1. OrganizationalUnitsTagsCleanupLogGroup
2. OUBaselineAutomationLogGroup
2. Lambda 函数
1. OUBaselineAutomationFunction
2. OrganizationalUnitsTagsCleanupFunction
3. IAM 角色
1. OrganizationalUnitsTagsCleanupRole
2. OUBaselineAutomationRole
4. Lambda 权限集
1. PermissionForRegisterRuleToInvokeLambda
2. 堆栈根据提供的配置部署额外资源。让我们仔细看看可用的参数。
## OU 引擎部署配置

1. 激活或停用 EventBridge 规则
1. 此参数控制 EventBridge 规则 (`RegisterOrganizationalUnitRule`) 的状态。
2. 默认值设置为 `false`。当设置为 `true` 时,在 CloudTrail 中捕获的下一个 `RegisterOrganizationalUnit` 生命周期事件将触发 Lambda 函数 `OUBaselineAutomationFunction`,其日志将存储在 `OUBaselineAutomationLogGroup` 中。
2. 操作已开始标签
1. 这是 Lambda 函数 `OUBaselineAutomationFunction` 用来标记其处理的每个 OU 的标签键。该值包含调用 Update API 时的时间戳。
2. Lambda 会检查 OU 是否已有此标签。如果标签不存在,则将该 OU 视为尚未更新,并在处理完毕后对其进行标记。如果标签已存在,则不会再次处理该 OU。
3. 操作已完成标签
1. 当 Lambda 函数 `OUBaselineAutomationFunction` 被 EventBridge 规则 `RegisterOrganizationalUnitRule` 调用,且仅当生命周期状态为 `SUCCEEDED` 时,规则提供的负载中会包含 OU ID,如下例所示。
"serviceEventDetails": {
"registerOrganizationalUnitStatus": {
"organizationalUnit": {
"organizationalUnitName": "OU_NAME",
"organizationalUnitId": "ou-XXX-xntt4uap"
},
"state": "SUCCEEDED",
"message": "AWS Control Tower successfully registered an organizational unit.",
"requestedTimestamp": "2026-04-14T21:55:36+0000",
"completedTimestamp": "2026-04-14T22:03:27+0000"
}
}
2. 函数 `OUBaselineAutomationFunction` 使用您定义的标签键对事件中的 OU 进行标记。标签值设置为生命周期事件中捕获的时间戳。
4. 自动关联 Lambda 角色与 Account Factory 产品组合
1. 此参数控制堆栈是否应创建额外资源,以自动将 `OUBaselineAutomationFunction` 的执行角色与 Account Factory 产品组合关联。
2. 如果设置为 `yes`,CloudFormation 将创建以下额外资源:
* CloudWatch 日志组:`PortfolioAccessLogGroup`
* IAM 角色:`PortfolioAccessRole`
* Lambda 函数:`PortfolioAccessFunction`
* Lambda 权限集:`AllowCloudFormationInvokePortfolioAccess`
* 自定义资源:`AutoAddOUEngineRoleToAccountFactoryPortfolio`
3. 自定义资源触发 Lambda 函数 `PortfolioAccessFunction`,将 `OUBaselineAutomationFunction` 的执行角色添加到 Account Factory 产品组合中。这使该角色能够执行已启用基线的重置和更新操作。
5. 自动更新不兼容的基线
1. 当 Landing Zone 版本更新时,除 `core` 和 `root` 之外的所有 OU 的当前基线可能不再兼容更新后的 Landing Zone 版本。如果在此时调用 `ResetEnabledBaseline`,将使用过时的基线并且操作会失败。
2. 在这种情况下,必须使用 `UpdateEnabledBaseline` 而不是 `ResetEnabledBaseline`。如果此参数设置为 `true`,Lambda 函数 `OUBaselineAutomationFunction` 会检查已启用的基线是否[兼容 Landing Zone](https://docs.aws.amazon.com/controltower/latest/userguide/table-of-baselines.html)。如果不兼容,函数将执行更新。否则,它将继续执行重置。
6. 要跳过的 OU 列表
1. 逗号分隔的 OU ID 列表,自动化将完全忽略这些 OU,直到它们从参数值中被移除。
2. 此参数可用于排除仍在进行修复或调查的 OU,从而允许自动化继续不受中断地处理其余 OU。
7. 优先重置的组织单位 ID
1. 如果提供了值,Lambda 函数将被更新以相应地传递 OU ID。
2. CloudFormation 还将创建自定义资源 `StartAutomationCustomResourceWithPortfolioAccess` 来触发 `OUBaselineAutomationFunction`,并提供在此参数中指定的 OU ID。
3. 如果提供的 OU ID 存在于 **[要跳过的 OU 列表](#ou-parameters-6)** 中,操作将被跳过,并且不会重新注册任何 OU。您必须更新参数值,并提供一个未包含在 **[要跳过的 OU 列表](#ou-parameters-6)** 中的 OU ID。
### 账户
让我们看一下账户自动化工作流程。下图说明了我们将深入探讨的组件。

## 账户引擎部署行为深入解析
## 账户引擎部署行为深入解析
1. CloudFormation 首先部署一组强制性资源。无论参数配置如何,这些资源都会被创建。
1. CloudWatch 日志组
1. AccountsTagsCleanupLogGroup
2. AccountsEngineLogGroup
2. Lambda 函数
1. AccountsEngineFunction
2. AccountsTagsCleanupFunction
3. IAM 角色
1. AccountsEngineRole
2. AccountsTagsCleanupRole
4. Lambda 权限集
1. AllowEventBridgeInvokeEngine
2. EventBridge 规则
3. AccountsUpdateSucceededRule
2. 堆栈创建的所有日志组均配置了**保留**策略。这意味着在删除堆栈时不会删除它们,允许您保留日志以用于故障排除和审计目的。
3. 堆栈根据提供的配置部署额外资源。让我们仔细看看可用的参数。
账户引擎部署配置

1. 激活或停用 EventBridge 规则
1. 此参数控制 EventBridge 规则 (`AccountsEngine-accounts-update-succeeded`) 的状态。
2. 默认值设置为 `false`。当设置为 `true` 时,在 CloudTrail 中捕获的下一个 `UpdateManagedAccount` 生命周期事件将触发 Lambda 函数 `EngineFunction`,其日志将存储在 `AccountsEngineLogGroup` 中。
2. 并发账户操作
1. 此参数定义可以同时更新多少个账户。默认值为 5,这与文档中记录的 Control Tower 限制一致。此值最大可增加至 10,但需获得批准的配额提升。
2. Lambda 函数 `AccountsEngineFunction` 使用此值来确保在任何给定时间处于“正在更改”状态的账户不超过配置的数量。
3. 更新操作已开始标签
1. 这是 Lambda 函数 `AccountsEngineFunction` 用来标记其处理的每个账户的标签键。标签值包括调用 Update API 时的时间戳以及 Service Catalog 预置产品事件记录 ID。
2. Lambda 会检查账户是否已有此标签。如果标签不存在,则将该账户视为尚未更新,并在调用更新 API 后对其进行标记。如果标签已存在,则不会再次处理该账户。
4. 更新操作已完成标签
1. 当 Lambda 函数 `AccountsEngineFunction` 被 EventBridge 规则 `AccountsUpdateSucceededRule` 调用,且仅当生命周期状态为 `SUCCEEDED` 时,负载会包含账户 ID 和更新详细信息,如下所示。
"serviceEventDetails": {
"updateManagedAccountStatus": {
"organizationalUnit":{
"organizationalUnitName":"OU_NAME",
"organizationalUnitId":"ou-XXXX-l3zc8b3h"
},
"account":{
"accountName":"ACCOUNT_NAME",
"accountId":"ACCOUNT_ID"
},
"state":"SUCCEEDED",
"message":"AWS Control Tower successfully updated a managed account.",
"requestedTimestamp": "2026-04-14T21:55:36+0000",
"completedTimestamp": "2026-04-14T22:03:27+0000"
}
}
2. 然后,函数 `AccountsEngineFunction` 使用定义的标签键标记该账户。标签值设置为生命周期事件中捕获的时间戳。
5. Identity Center 区域
1. 此参数指定 Control Tower 使用的 IAM Identity Center 实例部署所在的区域。对于 Control Tower 托管实例,这通常是主区域。
2. 如果使用的是自托管 Identity Center 实例,它可能位于不同的区域。在这种情况下,请提供相应的区域。
3. Lambda 函数 `AccountsEngineFunction` 使用此值来检索用户详细信息,例如 `SSOUserEmail`、`SSOUserFirstName` 和 `SSOUserLastName`。
6. 要跳过的账户列表
1. 逗号分隔的账户 ID 列表,自动化将完全忽略这些账户,直到它们从参数值中被移除。
2. 此参数可用于排除仍在进行修复或调查的账户,从而允许自动化继续不受中断地处理其余账户。
7. 优先更新的账户 ID
1. 如果提供的账户 ID 存在于 **[要跳过的账户列表](#accounts-parameters-6)** 中,操作将被跳过并且账户将被更新。您必须更新参数值,并提供未包含在 **[要跳过的账户列表](#accounts-parameters-6)** 中的 ID。
2. 该值必须对应于处于活动状态的 Control Tower 托管账户。
3. 如果设置为 `false`,您必须手动更新至少一个托管账户以启动自动化。
4. 如果提供了有效的账户 ID,堆栈将创建以下额外资源:
1. Lambda 函数:`AccountsStarterFunction`
2. CloudWatch 日志组:`AccountsStarterLogGroup`
3. Lambda 权限集:`AllowCloudFormationInvokeStarter`
4. 自定义资源:`StartAutomationCustomResourceWithPortfolioAccess`
8. 自动关联 Lambda 角色与 Account Factory 产品组合
1. 此参数决定堆栈是否自动将 IAM 角色 `AccountsEngineRole` 与 Account Factory 产品组合关联。这使 `AccountsEngineFunction` 能够调用 `UpdateProvisionedProduct` API。
2. 如果设置为 `true`,堆栈将创建以下额外资源:
1. CloudWatch 日志组:`PortfolioAccessLogGroup`
2. IAM 角色:`PortfolioAccessRole`
3. Lambda 函数:`PortfolioAccessFunction`
4. 自定义资源:`AutoAddEngineRoleToAccountFactoryPortfolio`
## Lambda 函数逻辑深入解析
1. AccountsEngineFunction
1. 如 **[3.1.2](#deep-dive-312)** 和 **[3.4.1](#deep-dive-341)** 中所述,此 Lambda 仅当 EventBridge 规则启用且生命周期更新状态为 `SUCCEEDED` 时才会被自动调用。
2. Lambda 函数首先检查该账户是否包含在 **[要跳过的账户列表](#accounts-parameters-6)** 参数中。如果该账户存在于列表中,则跳过操作,您必须提供一个不包含在 **[要跳过的账户列表](#accounts-parameters-6)** 参数中的不同账户 ID。
3. 函数首先从传入的负载中检索账户 ID,然后使用为 `TagCompletedKey` 参数定义的值标记该账户。标签值设置为负载中包含的时间戳。
4. 接着,它会评估当前有多少账户处于 `UNDER_CHANGE` 状态,并将此数量与配置的最大值 (`MaxInChange`) 进行比较。如果数量低于限制,则继续处理。否则,函数将优雅退出并记录当前没有可用的更新槽位。
5. 函数检索组织中的所有账户,按 OU 顺序对它们进行排序,并确定第一个未应用 `TagStartedKey` 的 Control Tower 托管账户。
6. 一旦确定了下一个符合条件的账户,函数将检索关联的预置产品并找到最近的成功事件。失败的事件将被跳过,直到找到成功的事件。
7. 然后从成功预置产品事件的输出中提取 `AccountEmail` 和 `SSOUserEmail`。
8. 函数在由 `IdentityCenterRegion` 参数指定的区域中查询 IAM Identity Center,以检索 `SSOUserFirstName` 和 `SSOUserLastName`。
9. 执行反向查找以使用账户 ID 检索 `AccountName`。
10. 函数还检索当前注册该账户的组织单位 ID 和名称。
11. 收集完所有必需的详细信息后,函数构建参数列表:
* AccountEmail
* AccountName
* ManagedOrganizationalUnit
* SSOUserEmail
* SSOUserFirstName
* SSOUserLastName
12. 最终验证确保该账户当前未在进行中。如果符合条件,函数将使用准备好的参数调用 `UpdateProvisionedProduct`。
13. 最后,函数使用 `TagStartedKey` 标记该账户。标签值结合了当前时间戳和预置产品事件记录 ID,以提高可追溯性。
2. AccountsTagsCleanupFunction
1. 函数列出组织中的所有账户并评估其标签。
2. 如果账户包含 `TagStartedKey`,则将其移除。
3. 如果存在 `TagCompletedKey`,也会被移除。
4. 调用此函数不需要负载。一个简单的 `{ }` 负载就足够了。
5. 输出示例:
[INFO] 2026-03-02T19:14:36.696Z ec0fa79f-1ab3-4be2-811c-7d943004d5d8 Removed ['UpdateStarted', 'UpdateCompleted'] from 111222333444
[INFO] 2026-03-02T19:14:36.987Z ec0fa79f-1ab3-4be2-811c-7d943004d5d8 Removed ['UpdateStarted', 'UpdateCompleted'] from 555666777888
[INFO] 2026-03-02T19:14:37.299Z ec0fa79f-1ab3-4be2-811c-7d943004d5d8 Removed ['UpdateStarted', 'UpdateCompleted'] from 111333444222
[INFO] 2026-03-02T19:14:37.598Z ec0fa79f-1ab3-4be2-811c-7d943004d5d8 Removed ['UpdateStarted', 'UpdateCompleted'] from 999666444111
[INFO] 2026-03-02T19:14:38.036Z ec0fa79f-1ab3-4be2-811c-7d943004d5d8 Removed ['UpdateStarted', 'UpdateCompleted'] from 777999888666
3. PortfolioAccessFunction
1. 函数检索 IAM 角色 `AccountsEngineRole` 的 ARN。
2. 它支持三种方法来发现 Account Factory 产品组合:
1. 直接使用提供的 `PortfolioId`,这需要修改函数以传递该参数。
2. 如果提供了 `AutomationTargetAccountId`,则检索该账户的预置产品并从其启动路径中提取产品组合。
3. 搜索名称中包含 **account factory** 的所有产品组合(默认行为)。
3. 在创建或更新时:
1. 函数发现产品组合 ID。
2. 它调用 `associate_principal_with_portfolio()` 以授予对 IAM 角色 `AccountsEngineRole` 的访问权限。
3. 为帮助避免竞态条件,Lambda 函数中引入了延迟。默认情况下,此延迟设置为 60 秒,由 `StartupDelaySeconds` 属性控制。此行为适用于账户引擎和 OU 引擎。
4. 在删除时:
1. 函数从 `PhysicalResourceId` 中提取产品组合 ID 和主体 ARN。
2. 它调用 `disassociate_principal_from_portfolio()` 以撤销该 IAM 角色的访问权限。
4. AccountsStarterFunction
1. Lambda 函数首先检查在 **[优先更新的账户 ID](#accounts-parameters-7)** 中提供的账户是否包含在 **[要跳过的账户列表](#accounts-parameters-6)** 参数中。如果该账户存在于跳过列表中,则跳过操作并且不会更新任何账户,您必须为 **[优先更新的账户 ID](#accounts-parameters-7)** 提供一个未包含在 **[要跳过的账户列表](#accounts-parameters-6)** 中的不同账户 ID。
2. 该函数遵循与 **[AccountsEngineFunction](#lambda-logic-1)** 相同的逻辑,但仅在指定账户上运行。
3. 它只处理单个账户,不执行组织范围的发现。
4. 仅应用 `TagStartedKey`,因为该函数对单个账户只运行一次。未使用 `TagCompletedKey`。
5. 该函数不会被自动化重新调用。
6. 它使用 `AccountsEngineRole`,确保了一致的权限,而无需引入额外的角色。
### 关闭账户哨兵
让我们看一下关闭账户哨兵的工作流程。下图说明了相关组件。

## 关闭账户哨兵部署配置

CloudFormation 首先部署一组强制性资源。
1. **现有存储桶**
* 此参数指定将存储自动化在两种模式下生成的所有 CSV 文件的现有 S3 存储桶。
2. **扫描版本**
* 在堆栈部署后更新此值时,堆栈将使用所选模式触发新的扫描。
3. **清理 CSV S3 对象 URL**
1. 此参数仅在堆栈参数 **模式** 设置为 `ExecutionMode` 时使用。
2. 它指定自动化将处理的 CSV 文件。
3. CSV 文件不需要位于 **[现有存储桶](#cas-parameter-1)** 中定义的同一存储桶中。
4. **模式**
* **扫描模式**
当选择此模式时,将按顺序执行以下步骤。如果任何步骤失败,则跳过该账户:
1. 自动化使用 AWS Organizations API 识别所有已挂起的账户。
2. 自动化检查每个账户是否启用了 Control Tower 基线。
3. 如果该账户已启用 Control Tower 基线,则会将其记录在 CSV 文件中。未启用基线的账户将被忽略。
4. 自动化扫描所有 Control Tower StackSets,并识别每个账户的所有堆栈实例和关联区域。
5. 自动化生成两个 CSV 文件:
* `full-report-{timestamp}.csv`
* `clean-up-{timestamp}.csv`
6. `full-report-{timestamp}.csv` 包含有关每个账户的详细信息。`clean-up-{timestamp}.csv` 仅包含与 [CloudFormation-Stacksets-Cleanup](https://github.com/aws-samples/sample-CloudFormation-Stacksets-Cleanup) 解决方案兼容的最低要求 CSV 结构,用于清理已挂起账户的 StackSet 实例并妥善移除 Control Tower StackSet 引用。
7. 所有报告都存储在 **现有存储桶](#cas-parameter-1)** 中定义的存储桶中,使用堆栈名称作为前缀。
* **SC 清理模式**
当选择此模式时,将按顺序执行以下步骤。如果任何步骤失败,则跳过该账户:
1. 必须提供 **[清理 CSV S3 对象 URL](#cas-parameter-3)**。该对象不需要位于 **[现有存储桶](#cas-parameter-1)** 中定义的同一存储桶中。
2. 此模式下可以使用 `full-report-{timestamp}.csv` 或 `clean-up-{timestamp}.csv`。但是,只有 `clean-up-{timestamp}.csv` 与 [CloudFormation-Stacksets-Cleanup](https://github.com/aws-samples/sample-CloudFormation-Stacksets-Cleanup) 解决方案兼容,用于 StackSet 实例清理。
3. 自动化验证该账户是否存在于 AWS Organizations 中并且处于挂起状态。
4. 自动化验证该账户是否启用了 Control Tower 基线。
5. 自动化检查该账户是否存在预置产品。
6. 如果预置产品存在,则在 ignore 标志设置为 `true` 的情况下将其删除。
7. 生成名为 `sc-cleanup-report-{timestamp}.csv` 的 CSV 文件,其中包含所有操作详细信息、发现和结果。
## 常见问题解答
1. 使用此解决方案我需要具备什么?
* 请参阅 [前提条件](#prerequisites) 以获取完整的要求列表。
2. 如果账户未能成功更新,我该如何重启自动化?
* 此解决方案主要依赖于生命周期事件,如 **[自动化策略](#automation-strategy)** 中所述。`MaxInChange` 参数默认设置为 5。这意味着最多可能有 4 个账户失败,而一次成功的更新就足以再次触发自动化。`AccountsEngineFunction` 将继续处理账户,直到达到 `MaxInChange` 限制。
* 如果所有账户都失败,建议查看 Control Tower 仪表板以获取错误信息,并首先解决任何潜在问题。
* 问题解决后,您可以手动更新一个托管账户,或者更新提供给堆栈的 `AutomationTargetAccountId`。这将生成一个生命周期事件,从而再次触发自动化并允许其恢复正常处理。
3. 如果 OU 未能成功更新,我该如何重启自动化?
* OU 重新注册一次仅限于一个 OU,这是当前的服务限制,无法更改。建议查看 Control Tower 仪表板以获取错误信息,并首先解决任何潜在问题。
* 问题解决后,您可以手动重新注册一个托管 OU,或者更新 `AutomationTargetOrganizationalUnitId` 参数中提供的 OU ID。这将生成一个生命周期事件,从而再次触发自动化并允许其恢复正常处理。
4. 如果我不希望堆栈管理对 Account Factory 产品组合的访问权限怎么办?
* 该解决方案设计灵活。如果您倾向于手动管理 Account Factory 产品组合访问权限,请确保在触发任何自动化之前配置了必要的访问权限。除非主体与产品组合关联,否则无法更新预置产品。
* 您可以在 EventBridge 规则设置为 `false` 的情况下部署该解决方案。这可以防止自动化自动触发。此外,不要为 `AutomationTargetAccountId` 或 `AutomationTargetOrganizationalUnitId` 参数提供值,因为这样做会立即触发对指定账户或 OU 的更新。
* 手动将 `AccountsEngineRole` 或 `OUBaselineAutomationRole` 与 Account Factory 产品组合关联后,更新堆栈并将 EventBridge 规则设置为 `true` 以启用自动化。
* 然后,您可以提供 Control Tower 托管账户 ID 作为 `AutomationTargetAccountId`,或者手动更新任何托管账户以触发自动化。同样,您可以为 `AutomationTargetOrganizationalUnitId` 提供 OU ID,或者手动重新注册 Control Tower 托管 OU。
5. 我如何停止自动化?
* 将 EventBridge 规则设置为 `false`。这可以防止自动化自动触发。如果您希望稍后恢复操作,请将该值重新设置为 `true`,然后手动更新一个账户或 OU,或者更新提供给堆栈的账户 ID 或 OU ID。
6. 账户或 OU 注册失败。为什么,我该如何恢复自动化?
* 账户或 OU 失败可能由多种原因引起。建议首先查看错误代码和日志,或者如果需要更多帮助,请联系 AWS Support。
* 问题解决后,可以通过手动更新一个账户或 OU,或者更新 `AutomationTargetAccountId` 或 `AutomationTargetOrganizationalUnitId` 参数的值来恢复自动化。
7. 我有失败的 OU,我仍在进行修复。我可以故意跳过 OU/账户吗?
* 可以。请参阅 **[要跳过的 OU 列表](#ou-parameters-6)** 以从自动化中排除特定的 OU。
* 您还可以根据需要使用 **[要跳过的账户列表](#accounts-parameters-6)** 来排除单个账户。
8. 我如何清理仍由 Control Tower 管理的已挂起账户?
1. 请参阅 **[关闭账户哨兵](#closed-account-sentinel)**,通过使用 **[扫描模式](#scanning-mode)** 帮助汇编所有仍由 Control Tower 管理的已挂起账户列表。
2. 要清理与这些账户关联的 Service Catalog 预置产品,请参阅 **[SC 清理模式](#sc-clean-up-mode)**。
3. 随后可以使用 [CloudFormation-Stacksets-Cleanup](https://github.com/aws-samples/sample-CloudFormation-Stacksets-Cleanup) 解决方案来清理 Control Tower StackSet 实例。请确保在执行 StackSet 实例清理时仅使用 **[clean-up-{timestamp}.csv](#cas-46)**。
## 清理
* 首先调用 `AccountsTagsCleanupFunction` 或 `OrganizationalUnitsTagsCleanupFunction` 以移除自动化创建的所有标签,如 **[2.4](#deep-dive-24)** 中所述,调用此函数不需要负载。一个简单的 `{ }` 负载就足够了。
可以通过 AWS 控制台调用 Lambda 函数

或者直接通过以下命令
aws lambda invoke --function-name OrganizationalUnitsTagsCleanupFunction --payload '{}' response.json
cat response.json
* 清理完标签后,请继续删除 CloudFormation 堆栈。这将移除解决方案部署的所有资源。
* 如果部署了 `PortfolioAccessFunction`,作为清理过程的一部分,相关 IAM 角色对 Account Factory 产品组合的访问权限将被撤销。
## 原则
* **适用于任何规模:** 旨在通过利用生命周期事件作为主要自动化触发器来支持任何规模的组织。
* **灵活:** 该解决方案经过专门设计,具有高度可配置性,允许您调整参数以符合您的治理模型和运维要求,同时保持合规性。
* **无破坏性:** 不会对工作负载执行任何破坏性操作。该解决方案执行的唯一删除操作仅限于移除自动化标签和撤销对 Account Factory 产品组合的访问权限。
* **无假设:** 该解决方案不假设特定的配置。提前审查您的内部限制、服务配额和治理策略以确保妥善对齐非常重要。
## 修订版本
- 2026-04-15 - 初始发布
- 2026-05-1 - 缓解产品组合访问设置中的 IAM 传播竞态问题
- 2026-05-6 - V2 支持跳过 OU/账户
- 2026-05-8 - V3 关闭账户哨兵支持
## 声明
客户有责任对本指南中的信息进行独立评估。本指南: 为信息目的而提供, 代表 AWS 当前的产品供应和实践,这些内容可能会在不另行通知的情况下发生变化,且 不会产生来自 AWS 及其关联公司、供应商或许可方的任何承诺或保证。AWS 产品或服务“按原样”提供,不附带任何形式的明示或暗示的保证、陈述或条件。AWS 对其客户的责任和 liabilities 受 AWS 协议控制,本指南不属于也不修改 AWS 与其客户之间的任何协议。
本库基于 MIT-0 许可证授权。详见 [LICENSE](LICENSE) 文件。
## 作者
- Karim Omar,云支持工程师
## 安全
详见 [贡献](CONTRIBUTING.md#security-issue-notifications) 获取更多信息。
## 许可证
本库基于 MIT-0 许可证授权。详见 LICENSE 文件。
标签:AWS, Control Tower, DPI, Landing Zone, Serverless, 事件驱动架构, 云架构, 云治理, 云计算, 企业级扩展, 合规性管理, 基础设施自动化, 数字取证, 混合治理问题, 组织单元治理, 自动化脚本, 自动化运维, 规则引擎, 账号重新注册, 账户生命周期管理