Última revisão: maio de 2026
Construa os serviços da AWS do exame SAP-C02 com Terraform puro — um bloco de cada vez, cada um vinculado a um domínio do exame. O mesmo código funciona no OpenTofu.
Até o final deste laboratório, você terá provisionado, com Terraform puro, o arcabouço empresarial que toda questão multi-conta do SAP-C02 pressupõe — uma estrutura de UOs do AWS Organizations, uma Política de Controle de Serviço (SCP) que impõe uma salvaguarda de regiões permitidas, uma função IAM de conta cruzada que as cargas de trabalho de serviços compartilhados podem assumir, e um trail de organização CloudTrail centralizado gravando em um bucket S3 imutável. Esta é a arquitetura multi-conta governada em escala que o exame testa mais de 30% do tempo.
Cada recurso é Terraform puro. Cole os trechos em um único main.tf, execute terraform init, depois terraform apply passo a passo.
>= 1.5 ou OpenTofu >= 1.6.us-east-1 contra a conta de gerenciamento.Todos os recursos do Organizations e IAM são sempre gratuitos. Os dois itens pagos:
Todo o stack fica ocioso a US$0. Destrua quando terminar para evitar que o bucket de logs de auditoria acumule evidências de conformidade que você pode não querer reter para sempre.
Abertura padrão. O Organizations é um serviço global, mas seus endpoints de API estão em us-east-1. Sempre execute o Terraform de nível de organização a partir de us-east-1 — o exame SAP-C02 testa este detalhe exato em Conectividade de Rede e Entrega de Conteúdo ao avaliar arquiteturas multi-região.
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"
}Se a conta de gerenciamento ainda não for uma conta mestre do Org, este recurso cria a Organization. A configuração feature_set = "ALL" habilita SCPs (a alternativa somente faturamento consolidado omite SCPs inteiramente — o SAP-C02 testa ambos os modos). A lista enabled_policy_types opta pelos três tipos de política que este laboratório usa; você adicionaria BACKUP_POLICY e AISERVICES_OPT_OUT_POLICY para esses domínios.
As duas UOs que criamos — Production e NonProduction — são o formato de referência do SAP-C02 para o escopo das salvaguardas. As SCPs se anexam às UOs; as UOs contêm contas. O posicionamento de conta em OU é a maior alavanca que um arquiteto multi-conta possui, porque toda SCP cascateia da OU para cada conta abaixo dela.
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
}As SCPs são o primitivo de governança do SAP-C02 — são o único mecanismo que pode impedir que os administradores de uma conta membro façam algo, ponto final. O padrão de SCP mais testado, de longe, é a restrição de regiões permitidas: mesmo que um administrador IAM de uma conta membro conceda *:* a todos, a salvaguarda de região imposta pela SCP ainda bloqueia operações fora do conjunto permitido.
A política abaixo nega todas as ações ec2:*, rds:* e lambda:* cuja aws:RequestedRegion não seja us-east-1 ou us-west-2. Serviços globais (IAM, Organizations, CloudFront) não são afetados porque não respeitam a condição RequestedRegion. O SAP-C02 testa essa exceção exata — alunos que negam *:* fora das regiões permitidas acidentalmente quebram o IAM e ficam bloqueados.
A política se anexa a ambas as UOs da Etapa 2. Contas dentro dessas UOs são governadas; a conta de gerenciamento não é afetada (uma pergunta de armadilha recorrente do SAP-C02: "por que a SCP não bloqueia a conta mestre da organização?" — porque, por design, ela não pode).
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
}O IAM de conta cruzada é o primitivo de serviços compartilhados do SAP-C02. O padrão: uma conta de carga de trabalho cria uma função com uma política de confiança nomeando a conta de serviços compartilhados como o principal confiável; pessoas ou serviços na conta de serviços compartilhados sts:AssumeRole para a conta de carga de trabalho para realizar suas tarefas. É assim que toda arquitetura de referência SAP-C02 lida com observabilidade centralizada, auditoria, implantação e plataforma de dados como serviço.
Incluímos uma condição de MFA (aws:MultiFactorAuthPresent = true) — o exame testa isso como a diferença entre uma política de confiança segura e uma apenas funcional. A condição ExternalId é a segunda parte da defesa contra o problema do deputado — recomendada para acesso de terceiros, mas também comumente vista em acessos internos entre contas.
A política de permissão em linha concede à função assumida acesso de leitura ao que a carga de trabalho precisa fazer; para o laboratório, concedemos acesso somente leitura ao bucket de logs de auditoria que criaremos na Etapa 5. Em produção, você restringiria isso ainda mais.
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.O ponto culminante de qualquer história de governança multi-conta do SAP-C02 é o trail de organização — um trail do CloudTrail, configurado na conta de gerenciamento, que captura eventos de gerenciamento em todas as contas membro da organização. O SAP-C02 testa isso contra o antipadrão de um trail por conta (operacionalmente ruidoso, auditoria incompleta, custa mais).
O bucket S3 precisa de uma política de bucket específica que conceda ao CloudTrail a permissão s3:PutObject com as convenções de caminho corretas — cloudtrail.amazonaws.com como o principal de serviço, o aws:SourceArn correspondendo ao trail. Perguntas do SAP-C02 sobre por que o CloudTrail não consegue gravar em um bucket centralizado quase sempre apontam para esta política.
Com o trail em vigor, cada chamada de API em todas as contas da organização chega a este bucket. A função IAM da Etapa 4 concede à conta de serviços compartilhados acesso de leitura ao bucket — o que significa que uma equipe de auditoria centralizada pode revisar a atividade em toda a organização sem nunca precisar de acesso a contas membro individuais. Essa é a arquitetura empresarial do SAP-C02 em cinco blocos.
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 derruba tudo neste laboratório, com ressalvas:
terraform destroy se existirem contas membro. Se você juntou contas à organização durante o laboratório, deve removê-las primeiro pelo console do AWS Organizations (ou via API). Uma conta de gerenciamento sem contas membro pode sair de sua própria organização, mas o comando destroy do Terraform falhará se a organização tiver filhas. Para um laboratório limpo, execute isso apenas contra uma conta nova sem contas membro associadas.force_destroy = false. O CloudTrail terá escrito pelo menos alguns eventos nele até o momento da destruição. Esvazie-o via aws s3 rm s3://<bucket> --recursive primeiro.O SAP-C02 cobre uma superfície arquitetural enorme que este laboratório não pode abranger — Control Tower (nenhuma maneira limpa de provisionar com Terraform; a API AWS requer interação no console para a configuração da landing zone), Service Catalog (produtos multi-conta), agregador do AWS Config para conformidade em toda a organização, políticas de vault do AWS Backup em contas, AWS RAM (Resource Access Manager), CloudFormation StackSets para IaC multi-conta, Direct Connect Gateway, Aurora Global Database, AWS Migration Hub, AWS Application Migration Service (AWS MGN), a família Storage Gateway, e os vários serviços híbridos da AWS (Outposts, Local Zones, Wavelength).
Nós nos limitamos aos quatro primitivos empresariais essenciais porque eles são a base à qual todos os outros padrões SAP-C02 se conectam. O RAM compartilha recursos entre contas na Organization da Etapa 2. O agregador do Config reúne descobertas de conformidade na conta de gerenciamento que possui o trail da Etapa 5. Os StackSets implantam IaC na estrutura de UOs da Etapa 2 usando o padrão de função de conta cruzada da Etapa 4. Construa a fundação primeiro.
Para as superfícies não provisionadas, as seções Navegar, Guia e Editorial desta página de certificação oferecem cobertura conceitual. O exame SAP-C02 testa o reconhecimento desses padrões muito mais do que o provisionamento prático de cada um — o laboratório é sobre internalizar as quatro formas fundamentais.