Phase 1: Hands-On Job-Essential Lab Solutions
This module contains complete, production-grade Terraform manifests, AWS CLI commands, and architectural validation for the Phase 1 Job-Essential Exercises.
π οΈ Lab 1: The Multi-Account Organizational Vending Machine
Objective
Deploy an AWS Organization structure with root governance, an Infrastructure Organizational Unit (OU), and a Workloads OU with child member accounts using declarative Terraform.
Production Terraform Manifest (organizations.tf)
# 1. Enable AWS Organizations with all features enabled
resource "aws_organizations_organization" "org" {
aws_service_access_principals = [
"cloudtrail.amazonaws.com",
"config.amazonaws.com",
"sso.amazonaws.com",
"ram.amazonaws.com"
]
feature_set = "ALL"
}
# 2. Create Core Organizational Units
resource "aws_organizations_organizational_unit" "infrastructure" {
name = "Infrastructure"
parent_id = aws_organizations_organization.org.roots[0].id
}
resource "aws_organizations_organizational_unit" "workloads" {
name = "Workloads"
parent_id = aws_organizations_organization.org.roots[0].id
}
# 3. Provision Member Accounts directly into their respective OUs
resource "aws_organizations_account" "network_hub" {
name = "Network-Hub-Production"
email = "aws-network-hub@corp.internal"
parent_id = aws_organizations_organizational_unit.infrastructure.id
role_name = "OrganizationAccountAccessRole"
}
resource "aws_organizations_account" "workload_prod" {
name = "EKS-Workload-Production"
email = "aws-workload-prod@corp.internal"
parent_id = aws_organizations_organizational_unit.workloads.id
role_name = "OrganizationAccountAccessRole"
}
π‘οΈ Lab 2: The Region-Restriction Service Control Policy (SCP)
Objective
Write an SCP and attach it to the Workloads OU that strictly denies any resource creation outside of us-east-1 and us-west-2, while exempting global services (IAM, Route53, CloudFront). Test and prove that launching an EC2 instance in eu-west-1 fails.
1. The SCP Policy Manifest (region_restriction_scp.tf)
resource "aws_organizations_policy" "deny_unapproved_regions" {
name = "DenyUnapprovedRegions"
description = "Prevents any resource creation outside us-east-1 and us-west-2"
type = "SERVICE_CONTROL_POLICY"
content = jsonencode({
Version = "2012-10-17"
Statement = [
{
Sid = "DenyAllOutsideApprovedRegions"
Effect = "Deny"
NotAction = [
"iam:*",
"organizations:*",
"route53:*",
"budgets:*",
"cloudfront:*",
"support:*",
"waf:*"
]
Resource = "*"
Condition = {
StringNotEquals = {
"aws:RequestedRegion" = [
"us-east-1",
"us-west-2"
]
}
}
}
]
})
}
# Attach SCP directly to Workloads OU
resource "aws_organizations_policy_attachment" "workloads_scp_attach" {
policy_id = aws_organizations_policy.deny_unapproved_regions.id
target_id = aws_organizations_organizational_unit.workloads.id
}
2. Negative Verification Test (Proving Policy Enforcement)
Run the following AWS CLI command inside the member account targeting eu-west-1:
aws ec2 run-instances \
--image-id ami-0c55b159cbfafe1f0 \
--instance-type t3.nano \
--region eu-west-1
Expected Result (Access Denied):
An error occurred (Client.UnauthorizedOperation) when calling the RunInstances operation:
You are not authorized to perform this operation. User: arn:aws:sts::987654321098:assumed-role/Admin
is not authorized to perform: ec2:RunInstances on resource with an explicit deny in a service control policy.
π Lab 3: Centralized Egress with AWS Transit Gateway & RAM
Objective
Architect a Hub-and-Spoke network where Account A (Network Hub) contains the Transit Gateway and NAT Gateway, and Account B (Workload) routes all 0.0.0.0/0 outbound traffic over the TGW through Account A.
flowchart LR
subgraph SpokeAcc ["Account B (Workload)"]
SpokeEC2["Private EC2 / Pod (10.2.1.50)"]
SpokeRT["Route Table<br/>0.0.0.0/0 -> tgw-xxx"]
SpokeEC2 --> SpokeRT
end
subgraph HubAcc ["Account A (Central Networking)"]
TGW["AWS Transit Gateway"]
NAT["Central NAT Gateway"]
IGW["Internet Gateway"]
TGW --> NAT --> IGW
end
SpokeRT -->|"TGW Attachment (Shared via RAM)"| TGW
IGW --> Internet(("π Public Internet"))
1. In Network Hub Account: Share TGW via AWS RAM
# Create Transit Gateway
resource "aws_ec2_transit_gateway" "hub_tgw" {
description = "Central Enterprise Transit Gateway"
tags = { Name = "hub-tgw" }
}
# Share TGW with Organization
resource "aws_ram_resource_share" "tgw_share" {
name = "tgw-org-share"
allow_external_principals = false
}
resource "aws_ram_resource_association" "tgw_assoc" {
resource_arn = aws_ec2_transit_gateway.hub_tgw.arn
resource_share_arn = aws_ram_resource_share.tgw_share.arn
}
resource "aws_ram_principal_association" "org_principal" {
principal = aws_organizations_organization.org.arn
resource_share_arn = aws_ram_resource_share.tgw_share.arn
}
2. In Workload Account: Route 0.0.0.0/0 to TGW Attachment
# Workload VPC Attachment to the Shared TGW
resource "aws_ec2_transit_gateway_vpc_attachment" "workload_attach" {
transit_gateway_id = data.aws_ec2_transit_gateway.shared_tgw.id
vpc_id = aws_vpc.workload_vpc.id
subnet_ids = aws_subnet.tgw_subnets[*].id # Dedicated /28 subnets
}
# Private Route Table: Route all external internet traffic to TGW
resource "aws_route" "private_to_tgw" {
route_table_id = aws_route_table.workload_private.id
destination_cidr_block = "0.0.0.0/0"
transit_gateway_id = data.aws_ec2_transit_gateway.shared_tgw.id
}