mirror of
https://github.com/ghndrx/terraform-foundation.git
synced 2026-02-10 06:45:06 +00:00
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
268 lines
7.3 KiB
HCL
268 lines
7.3 KiB
HCL
################################################################################
|
|
# 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
|
|
}
|