feat: Terraform Foundation - AWS Landing Zone

Enterprise-grade multi-tenant AWS cloud foundation.

Modules:
- GitHub OIDC for keyless CI/CD authentication
- IAM account settings and security baseline
- AWS Config Rules for compliance
- ABAC (Attribute-Based Access Control)
- SCPs (Service Control Policies)

Features:
- Multi-account architecture
- Cost optimization patterns
- Security best practices
- Comprehensive documentation

Tech: Terraform, AWS Organizations, IAM Identity Center
This commit is contained in:
2026-02-01 20:06:28 +00:00
commit 6136cde9bb
145 changed files with 30832 additions and 0 deletions

View File

@@ -0,0 +1,51 @@
# shared-vpc
Shared VPC Module Single VPC shared across all tenants via AWS RAM Isolation via: Security Groups, ABAC (tags), optional subnet segmentation
## Usage
```hcl
module "shared_vpc" {
source = "../modules/shared-vpc"
# Required variables
workloads_ou_arn = ""
# Optional: see variables.tf for all options
}
```
## Requirements
| Name | Version |
|------|---------|
| terraform | >= 1.5.0 |
| aws | >= 5.0 |
## Inputs
| Name | Description | Type | Required |
|------|-------------|------|----------|
| vpc_cidr | CIDR block for the shared VPC | `string` | no |
| tenant_subnet_cidr | CIDR block for tenant-specific subnets (if enabled) | `string` | no |
| availability_zones | List of availability zones | `list(string)` | no |
| enable_nat_gateway | Enable NAT Gateway for private subnet internet access | `bool` | no |
| tenants | List of tenant names (for per-tenant subnets) | `list(string)` | no |
| create_tenant_subnets | Create separate subnets per tenant (stricter isolation) | `bool` | no |
| workloads_ou_arn | ARN of the Workloads OU to share subnets with | `string` | yes |
## Outputs
| Name | Description |
|------|-------------|
| vpc_id | |
| vpc_cidr | |
| public_subnet_ids | |
| private_shared_subnet_ids | |
| private_tenant_subnet_ids | |
| nat_gateway_ip | |
| ram_share_arn | |
## License
Apache 2.0 - See LICENSE for details.

View File

@@ -0,0 +1,267 @@
################################################################################
# Shared VPC Module
# Single VPC shared across all tenants via AWS RAM
# Isolation via: Security Groups, ABAC (tags), optional subnet segmentation
################################################################################
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = ">= 5.0"
}
}
}
################################################################################
# VPC
################################################################################
resource "aws_vpc" "shared" {
cidr_block = var.vpc_cidr
enable_dns_hostnames = true
enable_dns_support = true
tags = {
Name = "shared-vpc"
Environment = "shared"
ManagedBy = "terraform"
}
}
################################################################################
# Internet Gateway
################################################################################
resource "aws_internet_gateway" "shared" {
vpc_id = aws_vpc.shared.id
tags = {
Name = "shared-igw"
}
}
################################################################################
# NAT Gateway (Single for cost savings)
################################################################################
resource "aws_eip" "nat" {
count = var.enable_nat_gateway ? 1 : 0
domain = "vpc"
tags = {
Name = "shared-nat-eip"
}
}
resource "aws_nat_gateway" "shared" {
count = var.enable_nat_gateway ? 1 : 0
allocation_id = aws_eip.nat[0].id
subnet_id = aws_subnet.public[0].id
tags = {
Name = "shared-nat"
}
depends_on = [aws_internet_gateway.shared]
}
################################################################################
# Subnets - Public (shared)
################################################################################
resource "aws_subnet" "public" {
count = length(var.availability_zones)
vpc_id = aws_vpc.shared.id
cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index)
availability_zone = var.availability_zones[count.index]
map_public_ip_on_launch = true
tags = {
Name = "shared-public-${var.availability_zones[count.index]}"
Type = "public"
Environment = "shared"
}
}
################################################################################
# Subnets - Private (shared across tenants)
################################################################################
resource "aws_subnet" "private_shared" {
count = length(var.availability_zones)
vpc_id = aws_vpc.shared.id
cidr_block = cidrsubnet(var.vpc_cidr, 4, count.index + length(var.availability_zones))
availability_zone = var.availability_zones[count.index]
tags = {
Name = "shared-private-${var.availability_zones[count.index]}"
Type = "private"
Environment = "shared"
}
}
################################################################################
# Subnets - Per-Tenant Private (optional, for stricter isolation)
################################################################################
resource "aws_subnet" "private_tenant" {
for_each = var.create_tenant_subnets ? {
for combo in setproduct(var.tenants, range(length(var.availability_zones))) :
"${combo[0]}-${combo[1]}" => {
tenant = combo[0]
az_idx = combo[1]
}
} : {}
vpc_id = aws_vpc.shared.id
cidr_block = cidrsubnet(var.tenant_subnet_cidr, 4, index(var.tenants, each.value.tenant) * length(var.availability_zones) + each.value.az_idx)
availability_zone = var.availability_zones[each.value.az_idx]
tags = {
Name = "tenant-${each.value.tenant}-private-${var.availability_zones[each.value.az_idx]}"
Type = "private"
Tenant = each.value.tenant
Environment = "shared"
}
}
################################################################################
# Route Tables
################################################################################
resource "aws_route_table" "public" {
vpc_id = aws_vpc.shared.id
route {
cidr_block = "0.0.0.0/0"
gateway_id = aws_internet_gateway.shared.id
}
tags = {
Name = "shared-public-rt"
}
}
resource "aws_route_table" "private" {
vpc_id = aws_vpc.shared.id
dynamic "route" {
for_each = var.enable_nat_gateway ? [1] : []
content {
cidr_block = "0.0.0.0/0"
nat_gateway_id = aws_nat_gateway.shared[0].id
}
}
tags = {
Name = "shared-private-rt"
}
}
resource "aws_route_table_association" "public" {
count = length(var.availability_zones)
subnet_id = aws_subnet.public[count.index].id
route_table_id = aws_route_table.public.id
}
resource "aws_route_table_association" "private_shared" {
count = length(var.availability_zones)
subnet_id = aws_subnet.private_shared[count.index].id
route_table_id = aws_route_table.private.id
}
resource "aws_route_table_association" "private_tenant" {
for_each = aws_subnet.private_tenant
subnet_id = each.value.id
route_table_id = aws_route_table.private.id
}
################################################################################
# AWS RAM - Share VPC Subnets with Organization
################################################################################
resource "aws_ram_resource_share" "vpc_subnets" {
name = "shared-vpc-subnets"
allow_external_principals = false
tags = {
Name = "Shared VPC Subnets"
}
}
# Share private subnets with the organization
resource "aws_ram_resource_association" "private_shared" {
count = length(var.availability_zones)
resource_arn = aws_subnet.private_shared[count.index].arn
resource_share_arn = aws_ram_resource_share.vpc_subnets.arn
}
# Share tenant-specific subnets (if created)
resource "aws_ram_resource_association" "private_tenant" {
for_each = aws_subnet.private_tenant
resource_arn = each.value.arn
resource_share_arn = aws_ram_resource_share.vpc_subnets.arn
}
# Share with specific OUs or entire org
resource "aws_ram_principal_association" "workloads_ou" {
principal = var.workloads_ou_arn
resource_share_arn = aws_ram_resource_share.vpc_subnets.arn
}
################################################################################
# Default Security Group - Deny All (force explicit SGs)
################################################################################
resource "aws_default_security_group" "default" {
vpc_id = aws_vpc.shared.id
# No ingress or egress rules = deny all
tags = {
Name = "default-deny-all"
Description = "Default SG - no access, use tenant-specific SGs"
}
}
################################################################################
# Outputs
################################################################################
output "vpc_id" {
value = aws_vpc.shared.id
}
output "vpc_cidr" {
value = aws_vpc.shared.cidr_block
}
output "public_subnet_ids" {
value = aws_subnet.public[*].id
}
output "private_shared_subnet_ids" {
value = aws_subnet.private_shared[*].id
}
output "private_tenant_subnet_ids" {
value = {
for k, v in aws_subnet.private_tenant : k => v.id
}
}
output "nat_gateway_ip" {
value = var.enable_nat_gateway ? aws_eip.nat[0].public_ip : null
}
output "ram_share_arn" {
value = aws_ram_resource_share.vpc_subnets.arn
}

View File

@@ -0,0 +1,40 @@
variable "vpc_cidr" {
description = "CIDR block for the shared VPC"
type = string
default = "10.0.0.0/16"
}
variable "tenant_subnet_cidr" {
description = "CIDR block for tenant-specific subnets (if enabled)"
type = string
default = "10.1.0.0/16"
}
variable "availability_zones" {
description = "List of availability zones"
type = list(string)
default = ["us-east-1a", "us-east-1b", "us-east-1c"]
}
variable "enable_nat_gateway" {
description = "Enable NAT Gateway for private subnet internet access"
type = bool
default = true
}
variable "tenants" {
description = "List of tenant names (for per-tenant subnets)"
type = list(string)
default = []
}
variable "create_tenant_subnets" {
description = "Create separate subnets per tenant (stricter isolation)"
type = bool
default = false
}
variable "workloads_ou_arn" {
description = "ARN of the Workloads OU to share subnets with"
type = string
}