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

359
scripts/new-workload.sh Executable file
View File

@@ -0,0 +1,359 @@
#!/bin/bash
################################################################################
# Create a new workload from template
# Usage: ./scripts/new-workload.sh <type> <tenant> <name>
#
# Types: ecs, lambda, rds
################################################################################
set -e
TYPE="$1"
TENANT="$2"
NAME="$3"
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
TF_DIR="$PROJECT_DIR/terraform"
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'
# Input validation - prevent command injection
# Only allow lowercase letters, numbers, and hyphens
validate_name() {
local value="$1"
local field="$2"
if [[ ! "$value" =~ ^[a-z0-9]([a-z0-9-]*[a-z0-9])?$ ]]; then
echo -e "${RED}Error: $field must contain only lowercase letters, numbers, and hyphens${NC}"
echo " Must start and end with a letter or number"
echo " Got: '$value'"
exit 1
fi
if [[ ${#value} -gt 63 ]]; then
echo -e "${RED}Error: $field must be 63 characters or less${NC}"
exit 1
fi
}
# Show usage
usage() {
echo "Usage: $0 <type> <tenant> <name>"
echo ""
echo "Compute:"
echo " ecs - ECS Fargate service with ALB"
echo " eks - EKS Kubernetes cluster"
echo " lambda - Lambda function with API Gateway"
echo ""
echo "Data:"
echo " rds - RDS database (PostgreSQL/MySQL)"
echo " aurora - Aurora Serverless v2 (auto-scaling)"
echo " dynamodb - DynamoDB NoSQL table"
echo " redis - ElastiCache Redis cluster"
echo " opensearch - OpenSearch (Elasticsearch)"
echo " s3 - S3 bucket (data lake, backups, media)"
echo " ecr - ECR container registry"
echo ""
echo "API & Messaging:"
echo " apigw - API Gateway REST API"
echo " sqs - SQS queue with DLQ"
echo " sns - SNS topic (pub/sub)"
echo " eventbus - EventBridge custom event bus"
echo " events - EventBridge rules (scheduled/pattern)"
echo " stepfn - Step Functions workflow"
echo ""
echo "Auth & Email:"
echo " cognito - Cognito User Pool (auth)"
echo " ses - SES email (transactional/marketing)"
echo ""
echo "Config & Security:"
echo " secrets - Secrets Manager (credentials, API keys)"
echo " params - SSM Parameter Store (config, cheaper)"
echo ""
echo "Web:"
echo " static - Static site (S3 + CloudFront)"
echo ""
echo "Examples:"
echo " $0 ecs acme api"
echo " $0 rds acme main"
echo " $0 dynamodb acme orders"
echo " $0 eventbus acme events"
echo " $0 stepfn acme order-processor"
exit 1
}
# Validate input
if [ -z "$TYPE" ] || [ -z "$TENANT" ] || [ -z "$NAME" ]; then
usage
fi
# Validate tenant and name format (security: prevent command injection)
validate_name "$TENANT" "tenant"
validate_name "$NAME" "name"
# Map type to template directory
case $TYPE in
ecs)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/ecs-fargate"
;;
events)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/eventbridge-rules"
;;
eks)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/eks-cluster"
;;
lambda)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/lambda-function"
;;
rds)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/rds-database"
;;
aurora)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/aurora-serverless"
;;
dynamodb)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/dynamodb-table"
;;
redis)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/elasticache-redis"
;;
opensearch)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/opensearch"
;;
s3)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/s3-bucket"
;;
ecr)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/ecr-repository"
;;
sns)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/sns-topic"
;;
params)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/ssm-parameters"
;;
cognito)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/cognito-auth"
;;
ses)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/ses-email"
;;
secrets)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/secrets-manager"
;;
apigw)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/api-gateway"
;;
sqs)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/sqs-queue"
;;
eventbus)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/eventbridge-bus"
;;
stepfn)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/step-function"
;;
static)
TEMPLATE_DIR="$TF_DIR/05-workloads/_template/static-site"
;;
*)
echo -e "${RED}Unknown type: $TYPE${NC}"
usage
;;
esac
WORKLOAD_NAME="${TENANT}-${NAME}"
WORKLOAD_DIR="$TF_DIR/05-workloads/$WORKLOAD_NAME"
# Check if workload already exists
if [ -d "$WORKLOAD_DIR" ]; then
echo -e "${RED}Workload '$WORKLOAD_NAME' already exists at: $WORKLOAD_DIR${NC}"
exit 1
fi
# Check template exists
if [ ! -f "$TEMPLATE_DIR/main.tf" ]; then
echo -e "${RED}Template not found at: $TEMPLATE_DIR${NC}"
exit 1
fi
# Check tenant exists
if [ ! -d "$TF_DIR/04-tenants/$TENANT" ] && [ "$TENANT" != "_template" ]; then
echo -e "${YELLOW}Warning: Tenant '$TENANT' doesn't exist yet.${NC}"
echo "Create it first: ./scripts/new-tenant.sh $TENANT"
echo ""
read -p "Continue anyway? [y/N] " -n 1 -r
echo
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
exit 1
fi
fi
echo -e "${GREEN}Creating workload: $WORKLOAD_NAME (type: $TYPE)${NC}"
# Copy template
cp -r "$TEMPLATE_DIR" "$WORKLOAD_DIR"
# Replace placeholders
find "$WORKLOAD_DIR" -type f -name "*.tf" -exec sed -i "s/<TENANT>/$TENANT/g" {} \;
find "$WORKLOAD_DIR" -type f -name "*.tf" -exec sed -i "s/<APP>/$NAME/g" {} \;
echo -e "${GREEN}✓ Created workload directory: $WORKLOAD_DIR${NC}"
# Type-specific instructions
echo ""
echo -e "${YELLOW}Next steps:${NC}"
echo ""
echo "1. Edit the configuration:"
echo " ${GREEN}vim $WORKLOAD_DIR/main.tf${NC}"
echo ""
case $TYPE in
ecs)
echo " Update these values:"
echo " - container_image (ECR URL)"
echo " - container_port"
echo " - cpu, memory"
echo " - desired_count, min_count, max_count"
echo " - environment variables"
echo " - secrets (ARNs)"
;;
eks)
echo " Update these values:"
echo " - cluster_version (1.29, 1.30, etc.)"
echo " - node_groups (instance types, scaling config)"
echo " - enable_fargate (for serverless pods)"
echo " - admin_arns (IAM principals for cluster access)"
echo " - cluster_endpoint_public (false for private-only)"
echo ""
echo " After apply, configure kubectl:"
echo " aws eks update-kubeconfig --name ${TENANT}-prod"
;;
lambda)
echo " Update these values:"
echo " - runtime (python3.12, nodejs20.x, etc.)"
echo " - handler"
echo " - source_dir OR s3_bucket/s3_key OR image_uri"
echo " - enable_vpc (true for database access)"
echo " - enable_api (true for HTTP endpoint)"
echo " - schedule_expression (for cron jobs)"
;;
rds)
echo " Update these values:"
echo " - engine (postgres, mysql, aurora-postgresql)"
echo " - engine_version"
echo " - instance_class"
echo " - storage_gb"
echo " - multi_az (true for prod)"
;;
redis)
echo " Update these values:"
echo " - engine_version (7.1, 7.0, etc.)"
echo " - node_type (cache.t3.micro, cache.r6g.large)"
echo " - num_cache_clusters (2 for Multi-AZ)"
echo " - maxmemory_policy (volatile-lru, allkeys-lru)"
;;
s3)
echo " Update these values:"
echo " - lifecycle_rules (tiering, expiration)"
echo " - enable_replication (cross-region DR)"
echo " - lambda_notifications (event triggers)"
echo " - cors_enabled (for web access)"
;;
ecr)
echo " Update these values:"
echo " - repositories (map of repo names)"
echo " - lifecycle_policy (cleanup rules)"
echo " - pull_access_accounts (cross-account)"
echo " - replication_regions (multi-region)"
;;
sns)
echo " Update these values:"
echo " - subscriptions (Lambda, SQS, Email, HTTP)"
echo " - filter_policy (message filtering)"
echo " - fifo_topic (ordered delivery)"
echo " - aws_service_principals (EventBridge, S3)"
;;
params)
echo " Update these values:"
echo " - parameters map (path -> value)"
echo " - SecureString for sensitive values"
echo " - Free for standard tier (4KB limit)"
echo " - Cheaper than Secrets Manager"
;;
cognito)
echo " Update these values:"
echo " - app_clients (web, mobile, m2m)"
echo " - password policy, MFA settings"
echo " - social_providers (Google, Facebook)"
echo " - custom_domain, lambda_triggers"
;;
ses)
echo " Update these values:"
echo " - domain, hosted_zone_id"
echo " - email_identities (sender addresses)"
echo " - tracking_options (open/click tracking)"
echo " - DMARC policy"
;;
secrets)
echo " Update these values:"
echo " - secrets map (name -> config)"
echo " - generate_password for auto-generated creds"
echo " - rotation settings for RDS"
echo " - allowed_accounts for cross-account"
;;
apigw)
echo " Update these values:"
echo " - lambda_integrations (path -> Lambda ARN)"
echo " - domain_name, hosted_zone_id (custom domain)"
echo " - usage_plans (quota/throttle)"
echo " - cors_origins (CORS allowed origins)"
;;
sqs)
echo " Update these values:"
echo " - fifo_queue (true for exactly-once processing)"
echo " - visibility_timeout_seconds"
echo " - max_receive_count (DLQ threshold)"
echo " - message_retention_seconds"
;;
dynamodb)
echo " Update these values:"
echo " - hash_key, range_key (primary key)"
echo " - billing_mode (PAY_PER_REQUEST or PROVISIONED)"
echo " - global_secondary_indexes"
echo " - ttl_attribute (for auto-expiry)"
;;
eventbus)
echo " Update these values:"
echo " - event_rules (pattern matching and targets)"
echo " - enable_archive (for event replay)"
echo " - allowed_source_accounts (cross-account)"
;;
stepfn)
echo " Update these values:"
echo " - state_machine_definition (workflow JSON)"
echo " - type (STANDARD or EXPRESS)"
echo " - lambda_arns, dynamodb_arns, etc. (permissions)"
echo " - schedule_expression (for scheduled runs)"
;;
static)
echo " Update these values:"
echo " - domain_name (e.g., www.example.com)"
echo " - hosted_zone_id (Route53 zone)"
echo " - price_class (PriceClass_100 cheapest)"
echo ""
echo " Deploy content:"
echo " aws s3 sync ./dist s3://BUCKET --delete"
;;
esac
echo ""
echo "2. Initialize and apply:"
echo " ${GREEN}cd $WORKLOAD_DIR${NC}"
echo " ${GREEN}terraform init -backend-config=../../00-bootstrap/backend.hcl${NC}"
echo " ${GREEN}terraform plan -var=\"state_bucket=YOUR_BUCKET\"${NC}"
echo " ${GREEN}terraform apply -var=\"state_bucket=YOUR_BUCKET\"${NC}"
echo ""