最終確認: 2026年5月
SAP-C02 試験の対象となる AWS サービスを、プレーンな Terraform を使用して構築します。1 ブロックずつ、それぞれ試験ドメインに関連付けられています。同じコードが OpenTofu でも動作します。
このラボの終了までに、素のTerraformを使用して、SAP-C02のマルチアカウントに関するあらゆる質問が前提とするエンタープライズの足場をプロビジョニングします。具体的には、AWS OrganizationsのOU構造、許可されたリージョンを強制するサービスコントロールポリシー、共有サービスワークロードが引き受けることができるクロスアカウントIAMロール、そしてイミュータブルなS3バケットに書き込む集中型のCloudTrail組織トレイルです。これは、試験で30%以上の頻度で問われる「大規模なマルチアカウント管理」アーキテクチャです。
すべてのリソースは素のTerraformです。これらのスニペットを単一のmain.tfにドロップし、terraform initを実行し、その後terraform applyを段階的に実行してください。
>= 1.5 または OpenTofu >= 1.6。us-east-1でAWS CLIが認証されていること。すべてのOrganizationsおよびIAMリソースは常に無料です。有料となる可能性のある項目は以下の2点です:
スタック全体はアイドル状態で0ドルです。監査ログバケットに永続的に保持したくないコンプライアンス証拠が蓄積されるのを避けるため、完了したら破棄してください。
標準的な開始点です。Organizationsはグローバルサービスですが、そのAPIエンドポイントはus-east-1にあります。組織レベルのTerraformは常にus-east-1から実行してください — 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"
}管理アカウントがまだ組織マスターでない場合、このリソースがOrganizationを作成します。feature_set = "ALL"の設定はSCPを有効にします(「一括請求のみ」のオプションではSCPが完全に省略されます — SAP-C02では両方のモードがテストされます)。enabled_policy_typesリストは、このラボで使用する3つのポリシータイプを有効にします。これらのドメインにはBACKUP_POLICYとAISERVICES_OPT_OUT_POLICYを追加することになります。
私たちが作成する2つの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条件は、「代理問題」防御の第2の柱です — サードパーティアクセスに推奨されますが、内部のクロスアカウントでも一般的に見られます。
インライン権限ポリシーは、引き受けられたロールにワークロードが必要とするものへの読み取りアクセスを付与します。このラボでは、ステップ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のマルチアカウントガバナンスにおける集大成は、組織トレイルです。これは、管理アカウントで設定され、組織内のすべてのメンバーアカウントにわたる管理イベントをキャプチャする1つのCloudTrailトレイルです。SAP-C02では、この概念が「アカウントごとに1つのトレイル」というアンチパターン(運用が煩雑で、監査が不完全で、コストがかかる)と対比してテストされます。
S3バケットには、CloudTrailにs3:PutObject権限を付与する特定のバケットポリシーが必要です。その際、cloudtrail.amazonaws.comをサービスプリンシパルとし、aws:SourceArnがトレイルと一致する適切なパス規則を使用します。CloudTrailが一元化されたバケットに書き込めない理由に関するSAP-C02の質問は、ほとんどの場合このポリシーを指しています。
トレイルが設定されると、組織内のすべてのアカウントにおけるすべてのAPI呼び出しがこのバケットに記録されます。ステップ4のIAMロールは、共有サービスアカウントにこのバケットへの読み取りアクセス権を付与します。これは、集中監査チームが個々のメンバーアカウントへのアクセスを必要とせずに、組織全体の活動をレビューできることを意味します。これが、5つのブロックで構成される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のdestroyは失敗します。クリーンなラボのためには、メンバーアカウントが結合されていない新しいアカウントに対してのみこれを実行してください。force_destroy = falseに設定されています。destroyを実行するまでに、CloudTrailは少なくともいくつかのイベントを書き込んでいるでしょう。まずaws s3 rm s3://<bucket> --recursiveで空にしてください。SAP-C02は、このラボではカバーしきれない膨大なアーキテクチャ領域を扱います。例えば、Control Tower(Terraformでクリーンにプロビジョニングする方法がなく、ランディングゾーン設定にはAWS APIコンソール操作が必要)、Service Catalog(マルチアカウント製品)、組織全体のコンプライアンスのためのAWS Configアグリゲーター、アカウントをまたがるAWS Backupのボールトポリシー、AWS RAM(Resource Access Manager)、マルチアカウントIaCのためのCloudFormation StackSets、Direct Connect Gateway、Aurora Global Database、AWS Migration Hub、AWS Application Migration Service(AWS MGN)、Storage Gatewayファミリー、および様々なハイブリッドAWSサービス(Outposts、Local Zones、Wavelength)などです。
私たちは4つの核となるエンタープライズプリミティブに限定しています。なぜなら、これらがSAP-C02の他のすべてのパターンが依拠する基盤だからです。RAMはステップ2のOrganization内のアカウント間でリソースを共有します。Configアグリゲーターは、ステップ5のトレイルを所有する管理アカウントにコンプライアンスの検出結果を取り込みます。StackSetsは、ステップ4のクロスアカウントロールパターンを使用して、ステップ2のOU構造にIaCを展開します。まずは基盤を構築しましょう。
プロビジョニングされていない領域については、この認定ページにある閲覧、プレイブック、およびEditorialセクションで概念的なカバー範囲が説明されています。SAP-C02試験では、これらのパターンを実際にプロビジョニングすることよりも、それらの認識がはるかに重視されます — このラボは、4つの基礎的な形状を反射的に使えるようにすることを目的としています。