最后审核时间:2026年5月
使用原生 Terraform 构建 SAP-C02 考试中的 AWS 服务——每次构建一个代码块,并紧扣考试领域。相同的代码可在 OpenTofu 上运行。
通过本实验,您将使用纯 Terraform 预置企业级支架,这是每个 SAP-C02 多账户问题都假设的架构——一个 AWS Organizations 组织单元(OU)结构、一个强制执行允许区域护栏的服务控制策略(SCP)、一个共享服务工作负载可以承担的跨账户 IAM 角色,以及一个写入不可变 S3 桶的集中式 CloudTrail 组织跟踪。这正是考试中超过 30% 的时间会考察的大规模治理多账户架构。
每个资源都是纯 Terraform。将代码片段放入一个 main.tf 文件中,运行 terraform init,然后逐步运行 terraform apply。
>= 1.5 或 OpenTofu >= 1.6。us-east-1 区域对 AWS CLI 进行身份验证。所有 Organizations 和 IAM 资源始终免费。两个付费项目:
整个堆栈闲置时费用为 $0。完成后销毁,以避免审计日志桶积累您可能不想永久保留的合规证据。
标准开场。Organizations 是一个全球服务,但其 API 端点位于 us-east-1。始终从 us-east-1 运行组织级别的 Terraform——SAP-C02 考试在评估多区域架构时,会在网络连接和内容交付部分考察这一具体细节。
terraform {
required_version = ">= 1.5"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.60"
}
}
}
provider "aws" {
region = "us-east-1"
default_tags {
tags = {
Project = "certlabpro-sap-c02"
ManagedBy = "terraform"
}
}
}
data "aws_caller_identity" "current" {}
# Replace with the 12-digit account ID of the *shared-services* account
# we are wiring cross-account trust to in Step 4.
locals {
shared_services_account_id = "111122223333"
}如果管理账户尚未成为组织主账户,此资源将创建组织。feature_set = "ALL" 设置启用 SCP(仅合并账单选项会完全省略 SCP——SAP-C02 两种模式都会考察)。enabled_policy_types 列表选择了本实验使用的三种策略类型;对于其他领域,您将添加 BACKUP_POLICY 和 AISERVICES_OPT_OUT_POLICY。
我们创建的两个 OU——Production 和 NonProduction——是 SAP-C02 护栏范围划分的参考形状。SCP 附加到 OU;OU 包含账户。账户到 OU 的放置是多账户架构师拥有的最大杠杆,因为每个 SCP 都会从 OU 级联到其下的每个账户。
resource "aws_organizations_organization" "main" {
feature_set = "ALL"
enabled_policy_types = [
"SERVICE_CONTROL_POLICY",
"TAG_POLICY",
]
aws_service_access_principals = [
"cloudtrail.amazonaws.com",
]
}
resource "aws_organizations_organizational_unit" "production" {
name = "Production"
parent_id = aws_organizations_organization.main.roots[0].id
}
resource "aws_organizations_organizational_unit" "non_production" {
name = "NonProduction"
parent_id = aws_organizations_organization.main.roots[0].id
}SCP 是 SAP-C02 的治理原语——它们是唯一可以完全阻止成员账户管理员执行某些操作的机制。迄今为止,最常测试的 SCP 模式是允许区域限制:即使成员账户的 IAM 管理员授予所有人 *:* 权限,SCP 施加的区域护栏仍然会阻止在允许范围之外的操作。
下面的策略拒绝所有 aws:RequestedRegion 不在 us-east-1 或 us-west-2 之列的 ec2:*、rds:* 和 lambda:* 操作。全球服务(IAM、Organizations、CloudFront)不受影响,因为它们不遵守 RequestedRegion 条件。SAP-C02 考试会考查这一具体例外——那些在允许区域之外拒绝 *:* 的考生会意外破坏 IAM 并将自己锁定在外。
该策略附加到步骤 2 中的两个 OU。这些 OU 内部的账户受此策略管理;管理账户不受影响(一个反复出现的 SAP-C02 陷阱问题是:“为什么 SCP 不阻止组织主账户?”——因为根据设计,它不能这样做)。
resource "aws_organizations_policy" "allowed_regions" {
name = "certlabpro-sap-c02-allowed-regions"
description = "Deny ec2/rds/lambda outside the allowed regions."
type = "SERVICE_CONTROL_POLICY"
content = jsonencode({
Version = "2012-10-17"
Statement = [{
Sid = "DenyNonAllowedRegions"
Effect = "Deny"
NotAction = [
"iam:*",
"organizations:*",
"cloudfront:*",
"route53:*",
"support:*",
"sts:*",
"waf:*",
]
Resource = "*"
Condition = {
StringNotEquals = {
"aws:RequestedRegion" = ["us-east-1", "us-west-2"]
}
}
}]
})
}
resource "aws_organizations_policy_attachment" "production" {
policy_id = aws_organizations_policy.allowed_regions.id
target_id = aws_organizations_organizational_unit.production.id
}
resource "aws_organizations_policy_attachment" "non_production" {
policy_id = aws_organizations_policy.allowed_regions.id
target_id = aws_organizations_organizational_unit.non_production.id
}跨账户 IAM 是 SAP-C02 的共享服务原语。其模式是:一个工作负载账户创建一个带有信任策略的角色,将共享服务账户命名为受信任主体;共享服务账户中的人员或服务通过 sts:AssumeRole 进入工作负载账户以执行其任务。这是每个 SAP-C02 参考架构处理集中式可观测性、审计、部署和数据平台即服务的方式。
我们包含一个 MFA 条件(aws:MultiFactorAuthPresent = true)——考试会测试安全信任策略与仅功能性信任策略之间的区别。ExternalId 条件是代理问题防御的第二部分——建议用于第三方访问,但也常用于内部跨账户访问。
内联权限策略授予假定角色对工作负载所需执行的任何操作的读取访问权限;对于本实验,我们授予对步骤 5 中将创建的审计日志桶的只读访问权限。在生产环境中,您会进一步缩小此权限范围。
resource "aws_iam_role" "shared_services_reader" {
name = "certlabpro-sap-c02-shared-services-reader"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Principal = {
AWS = "arn:aws:iam::${local.shared_services_account_id}:root"
}
Action = "sts:AssumeRole"
Condition = {
Bool = {
"aws:MultiFactorAuthPresent" = "true"
}
StringEquals = {
"sts:ExternalId" = "certlabpro-sap-c02-external-id"
}
}
}]
})
max_session_duration = 3600
}
# The reader-policy is wired in Step 5 once the audit bucket exists.任何 SAP-C02 多账户治理故事的基石都是组织跟踪——一个在管理账户中配置的 CloudTrail 跟踪,它捕获组织中所有成员账户的管理事件。SAP-C02 考试会将其与每个账户一个跟踪的反模式(操作噪音大、审计不完整、成本更高)进行对比。
S3 桶需要一个特定的桶策略,该策略授予 CloudTrail s3:PutObject 权限,并遵循正确的路径约定——cloudtrail.amazonaws.com 作为服务主体,aws:SourceArn 与跟踪匹配。关于为什么 CloudTrail 无法写入集中式桶的 SAP-C02 问题几乎总是指向此策略。
有了这个跟踪,组织中所有账户的所有 API 调用都将记录到这个桶中。步骤 4 中的 IAM 角色授予共享服务账户对该桶的读取访问权限——这意味着集中式审计团队可以审查整个组织内的活动,而无需访问单个成员账户。这就是 SAP-C02 企业架构的五个模块。
resource "aws_s3_bucket" "audit_logs" {
bucket_prefix = "certlabpro-sap-c02-audit-"
}
resource "aws_s3_bucket_public_access_block" "audit_logs" {
bucket = aws_s3_bucket.audit_logs.id
block_public_acls = true
block_public_policy = true
ignore_public_acls = true
restrict_public_buckets = true
}
resource "aws_s3_bucket_versioning" "audit_logs" {
bucket = aws_s3_bucket.audit_logs.id
versioning_configuration {
status = "Enabled"
}
}
resource "aws_s3_bucket_policy" "audit_logs_cloudtrail" {
bucket = aws_s3_bucket.audit_logs.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "AWSCloudTrailAclCheck"
Effect = "Allow"
Principal = { Service = "cloudtrail.amazonaws.com" }
Action = "s3:GetBucketAcl"
Resource = aws_s3_bucket.audit_logs.arn
},
{
Sid = "AWSCloudTrailWrite"
Effect = "Allow"
Principal = { Service = "cloudtrail.amazonaws.com" }
Action = "s3:PutObject"
Resource = "${aws_s3_bucket.audit_logs.arn}/AWSLogs/*"
Condition = {
StringEquals = {
"s3:x-amz-acl" = "bucket-owner-full-control"
}
}
},
]
})
}
resource "aws_cloudtrail" "org_trail" {
name = "certlabpro-sap-c02-org-trail"
s3_bucket_name = aws_s3_bucket.audit_logs.bucket
is_multi_region_trail = true
is_organization_trail = true
include_global_service_events = true
enable_log_file_validation = true
depends_on = [
aws_s3_bucket_policy.audit_logs_cloudtrail,
aws_organizations_organization.main,
]
}
# Cross-account IAM permissions (continued from Step 4): the role we
# created earlier now gets read access to the audit bucket so a
# shared-services audit team can query CloudTrail across the org.
resource "aws_iam_role_policy" "shared_services_audit_read" {
name = "read-audit-logs"
role = aws_iam_role.shared_services_reader.id
policy = jsonencode({
Version = "2012-10-17"
Statement = [{
Effect = "Allow"
Action = ["s3:GetObject", "s3:ListBucket"]
Resource = [aws_s3_bucket.audit_logs.arn, "${aws_s3_bucket.audit_logs.arn}/*"]
}]
})
}terraform destroy 会销毁本实验中的所有内容,但有以下注意事项:
terraform destroy 删除。如果您在实验期间将账户加入到组织中,则必须先通过 AWS Organizations 控制台(或通过 API)将其删除。没有成员账户的管理账户可以退出自己的组织,但如果组织有子账户,Terraform 的销毁将失败。为了一个干净的实验,请仅在未加入任何成员账户的全新账户上运行此操作。force_destroy = false。在您销毁之前,CloudTrail 将至少写入一些事件。请先通过 aws s3 rm s3://<bucket> --recursive 清空它。SAP-C02 涵盖了本实验无法涵盖的巨大架构范围——Control Tower(没有通过 Terraform 干净预置的方法;AWS API 需要控制台交互才能设置着陆区)、Service Catalog(多账户产品)、用于全组织合规性的 AWS Config 聚合器、跨账户的 AWS Backup 存储库策略、AWS RAM(资源访问管理器)、用于多账户 IaC 的 CloudFormation StackSets、Direct Connect Gateway、Aurora Global Database、AWS Migration Hub、AWS Application Migration Service (AWS MGN)、存储网关系列以及各种混合 AWS 服务(Outposts、Local Zones、Wavelength)。
我们坚持使用四个核心企业原语,因为它们是其他所有 SAP-C02 模式的基础。RAM 在步骤 2 的组织中的账户之间共享资源。Config 聚合器将合规性调查结果拉入拥有步骤 5 中跟踪的管理账户。StackSets 使用步骤 4 中的跨账户角色模式将 IaC 推广到步骤 2 的 OU 结构中。首先构建基础。
对于未预置的方面,此认证页面的浏览、手册和 Editorial 部分提供了概念性覆盖。SAP-C02 考试更多地测试对这些模式的识别,而不是每个模式的动手预置——本实验旨在将这四个基础形态融入到您的肌肉记忆中。