mirror of
https://github.com/ghndrx/terraform-foundation.git
synced 2026-02-10 23:04:59 +00:00
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:
51
terraform/modules/shared-vpc/README.md
Normal file
51
terraform/modules/shared-vpc/README.md
Normal 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.
|
||||
267
terraform/modules/shared-vpc/main.tf
Normal file
267
terraform/modules/shared-vpc/main.tf
Normal 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
|
||||
}
|
||||
40
terraform/modules/shared-vpc/variables.tf
Normal file
40
terraform/modules/shared-vpc/variables.tf
Normal 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
|
||||
}
|
||||
Reference in New Issue
Block a user