# Storage Module - EBS, EFS, S3 # RFC 0039: ADR-Compliant Foundation Infrastructure # # Architecture: # - EFS for shared persistent storage (git repos, files) # - S3 for backups and blob storage # - KMS for encryption (FIPS compliance) # KMS Key for Storage Encryption resource "aws_kms_key" "storage" { description = "Storage encryption key" deletion_window_in_days = 30 enable_key_rotation = true tags = merge(var.tags, { Name = "${var.name}-storage" }) } resource "aws_kms_alias" "storage" { name = "alias/${var.name}-storage" target_key_id = aws_kms_key.storage.key_id } # EFS File System resource "aws_efs_file_system" "main" { creation_token = var.name encrypted = var.enable_encryption kms_key_id = var.enable_encryption ? aws_kms_key.storage.arn : null performance_mode = "generalPurpose" throughput_mode = "bursting" lifecycle_policy { transition_to_ia = "AFTER_30_DAYS" } lifecycle_policy { transition_to_primary_storage_class = "AFTER_1_ACCESS" } tags = merge(var.tags, { Name = var.name }) } # EFS Mount Targets (one per AZ) resource "aws_efs_mount_target" "main" { count = length(var.private_subnet_ids) file_system_id = aws_efs_file_system.main.id subnet_id = var.private_subnet_ids[count.index] security_groups = [aws_security_group.efs.id] } # EFS Security Group resource "aws_security_group" "efs" { name = "${var.name}-efs" description = "EFS security group" vpc_id = var.vpc_id ingress { description = "NFS from VPC" from_port = 2049 to_port = 2049 protocol = "tcp" cidr_blocks = [data.aws_vpc.main.cidr_block] } egress { description = "All outbound" from_port = 0 to_port = 0 protocol = "-1" cidr_blocks = ["0.0.0.0/0"] } tags = merge(var.tags, { Name = "${var.name}-efs" }) } # EFS Access Point for CSI driver resource "aws_efs_access_point" "main" { file_system_id = aws_efs_file_system.main.id posix_user { gid = 1000 uid = 1000 } root_directory { path = "/data" creation_info { owner_gid = 1000 owner_uid = 1000 permissions = "0755" } } tags = merge(var.tags, { Name = "${var.name}-data" }) } # S3 Bucket for Backups resource "aws_s3_bucket" "backups" { bucket = "${var.name}-backups-${data.aws_caller_identity.current.account_id}" tags = merge(var.tags, { Name = "${var.name}-backups" Purpose = "CockroachDB and service backups" }) } resource "aws_s3_bucket_versioning" "backups" { bucket = aws_s3_bucket.backups.id versioning_configuration { status = "Enabled" } } resource "aws_s3_bucket_server_side_encryption_configuration" "backups" { bucket = aws_s3_bucket.backups.id rule { apply_server_side_encryption_by_default { sse_algorithm = var.enable_encryption ? "aws:kms" : "AES256" kms_master_key_id = var.enable_encryption ? aws_kms_key.storage.arn : null } bucket_key_enabled = true } } resource "aws_s3_bucket_public_access_block" "backups" { bucket = aws_s3_bucket.backups.id block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true } resource "aws_s3_bucket_lifecycle_configuration" "backups" { bucket = aws_s3_bucket.backups.id rule { id = "transition-to-ia" status = "Enabled" transition { days = 30 storage_class = "STANDARD_IA" } transition { days = 90 storage_class = "GLACIER" } noncurrent_version_transition { noncurrent_days = 30 storage_class = "STANDARD_IA" } noncurrent_version_expiration { noncurrent_days = 365 } } } # S3 Bucket for Blob Storage resource "aws_s3_bucket" "blobs" { bucket = "${var.name}-blobs-${data.aws_caller_identity.current.account_id}" tags = merge(var.tags, { Name = "${var.name}-blobs" Purpose = "Application blob storage" }) } resource "aws_s3_bucket_versioning" "blobs" { bucket = aws_s3_bucket.blobs.id versioning_configuration { status = "Enabled" } } resource "aws_s3_bucket_server_side_encryption_configuration" "blobs" { bucket = aws_s3_bucket.blobs.id rule { apply_server_side_encryption_by_default { sse_algorithm = var.enable_encryption ? "aws:kms" : "AES256" kms_master_key_id = var.enable_encryption ? aws_kms_key.storage.arn : null } bucket_key_enabled = true } } resource "aws_s3_bucket_public_access_block" "blobs" { bucket = aws_s3_bucket.blobs.id block_public_acls = true block_public_policy = true ignore_public_acls = true restrict_public_buckets = true } resource "aws_s3_bucket_cors_configuration" "blobs" { bucket = aws_s3_bucket.blobs.id cors_rule { allowed_headers = ["*"] allowed_methods = ["GET", "PUT", "POST", "DELETE", "HEAD"] allowed_origins = ["*"] # Restrict in production expose_headers = ["ETag"] max_age_seconds = 3000 } } resource "aws_s3_bucket_lifecycle_configuration" "blobs" { bucket = aws_s3_bucket.blobs.id rule { id = "intelligent-tiering" status = "Enabled" transition { days = 30 storage_class = "INTELLIGENT_TIERING" } noncurrent_version_expiration { noncurrent_days = 90 } } } # Data sources data "aws_vpc" "main" { id = var.vpc_id } data "aws_caller_identity" "current" {}