diff --git a/README.md b/README.md index 35cd4f5..6da452c 100644 --- a/README.md +++ b/README.md @@ -25,9 +25,14 @@ Terraform modules that provide a consistent interface for provisioning AWS cloud - **Lambda** - Serverless functions with container support and VPC integration - **Fargate** - Container orchestration with ECS and load balancer integration +### Database +- **RDS Instance** - Managed PostgreSQL database instances with automated backups +- **RDS Database** - PostgreSQL database and role provisioning within RDS instances + ### Networking - **VPC** - Virtual private clouds with public/private subnets and NAT gateways - **Load Balancer** - Application and network load balancers for traffic distribution +- **Security Group Rule** - Firewall rules for controlling inbound and outbound traffic ### Identity - **IAM Role** - Identity and access management roles with trust policies diff --git a/rds-database/icon.svg b/rds-database/icon.svg new file mode 100644 index 0000000..1b5712b --- /dev/null +++ b/rds-database/icon.svg @@ -0,0 +1,17 @@ + + + Icon-Architecture/64/Arch_Amazon-RDS_64 + Created with Sketch. + + + + + + + + + + + + + diff --git a/rds-database/manifest.yaml b/rds-database/manifest.yaml new file mode 100644 index 0000000..6d5ee1a --- /dev/null +++ b/rds-database/manifest.yaml @@ -0,0 +1,45 @@ +name: rds-database +display_name: RDS PostgreSQL Database +type: database +description: "Creates a PostgreSQL database on an existing RDS instance with automatic credential generation and service injection" +icon: ./icon.svg +deployment: + terraform: ./module + +inputs: + rds_instance_endpoint: + type: string + required: true + description: "Connection endpoint of the RDS instance in format hostname:port (e.g. `mydb.abc123.us-east-1.rds.amazonaws.com:5432`)" + + codebuild_project_name: + type: string + required: true + description: "Name of the CodeBuild project for database operations (from RDS instance)" + + database_name: + type: string + required: false + description: "Name of the database to create. If not specified, uses stack_id and resource name (e.g. `myapp_db`)" + + database_owner: + type: string + required: false + description: "Username for the database owner role. If not specified, a unique role is created (e.g. `myapp_user`)" + +outputs: + database_name: + type: string + description: "Name of the created database" + + database_owner: + type: string + description: "Username of the database owner" + + database_password: + type: string + description: "Password for the database owner (sensitive)" + + connection_string: + type: string + description: "PostgreSQL connection string for the database" diff --git a/rds-database/module/main.tf b/rds-database/module/main.tf new file mode 100644 index 0000000..b6beec8 --- /dev/null +++ b/rds-database/module/main.tf @@ -0,0 +1,70 @@ +# Get the current AWS region +data "aws_region" "current" { +} + +# Local variables +locals { + database_name = var.database_name != null ? var.database_name : replace("${var.suga.stack_id}_${var.suga.name}", "-", "_") + database_owner = var.database_owner != null ? var.database_owner : replace("${var.suga.stack_id}_${var.suga.name}_user", "-", "_") + + # Build PostgreSQL connection string + connection_string = "postgresql://${local.database_owner}:${random_password.db_password.result}@${var.rds_instance_endpoint}/${local.database_name}?sslmode=require" + + # Output service export map + service_outputs = { + for name, service in var.suga.services : name => { + env = { + (var.suga.env_var_key) = local.connection_string + } + } + } +} + +# Generate a random password for the database owner role +resource "random_password" "db_password" { + length = 32 + special = false +} + +# Trigger CodeBuild to create the database and role +resource "null_resource" "create_database" { + triggers = { + database_name = local.database_name + database_owner = local.database_owner + rds_endpoint = var.rds_instance_endpoint + codebuild_project = var.codebuild_project_name + } + + provisioner "local-exec" { + interpreter = ["bash", "-c"] + command = < + + Icon-Architecture/64/Arch_Amazon-RDS_64 + Created with Sketch. + + + + + + + + + + + + + diff --git a/rds-instance/manifest.yaml b/rds-instance/manifest.yaml new file mode 100644 index 0000000..b570902 --- /dev/null +++ b/rds-instance/manifest.yaml @@ -0,0 +1,224 @@ +name: rds-instance +display_name: RDS PostgreSQL Instance +type: infra +description: "Provisions an AWS RDS PostgreSQL instance with optional automated backups, encryption, and multi-AZ support. Use with rds-database plugin to create individual databases." +icon: ./icon.svg +deployment: + terraform: ./module + +inputs: + identifier: + type: string + required: true + description: "Unique identifier for the RDS instance (e.g. `myapp-db`)" + + engine_version: + type: string + required: false + description: "PostgreSQL engine version (e.g. `15.4`, `16.1`). If not specified, uses the latest version" + + instance_class: + type: string + description: "Compute and memory capacity - `db.t3.micro` (free tier, 2vCPU, 1GB RAM), `db.t3.small` (2vCPU, 2GB), `db.t3.medium` (2vCPU, 4GB), `db.m5.large` (2vCPU, 8GB), `db.m5.xlarge` (4vCPU, 16GB) (e.g. `db.t3.small`)" + + allocated_storage: + type: number + required: false + description: "Initial storage size in GB, 20-65536. Can grow with max_allocated_storage (e.g. `20`)" + + max_allocated_storage: + type: number + required: false + description: "Maximum storage autoscaling limit in GB. Set higher than allocated_storage to enable autoscaling (e.g. `100`)" + + storage_type: + type: string + required: false + description: 'Storage type: `gp2` (general SSD, legacy), `gp3` (newer SSD with better performance), `io1` (provisioned IOPS) (e.g. `gp3`)' + + storage_encrypted: + type: bool + required: false + description: "`true` (recommended) encrypts database storage at rest using AWS KMS. `false` leaves data unencrypted" + + kms_key_id: + type: string + required: false + description: "ARN of AWS KMS key for encryption. If storage_encrypted is true and this is not set, uses default AWS RDS key (e.g. `arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012`)" + + database_name: + type: string + required: false + description: "Initial database name to create. At least one database must exist for PostgreSQL provider to connect (e.g. `postgres`)" + + master_username: + type: string + description: "Master username for database access (e.g. `postgres`)" + + port: + type: number + required: false + description: "TCP port for database connections (default: 5432)" + + multi_az: + type: bool + required: false + description: "`false` (default) single AZ deployment for dev/test. `true` enables multi-AZ with automatic failover for production high availability" + + publicly_accessible: + type: bool + required: false + description: "`false` (recommended) keeps database private within VPC. `true` assigns public IP - use only for development, not production" + + vpc_id: + type: string + required: true + description: "VPC ID where RDS will be deployed (e.g. `vpc-0123456789abcdef0`)" + + subnet_ids: + type: list(string) + required: true + description: 'List of subnet IDs for RDS subnet group, must span at least 2 availability zones (e.g. `["subnet-abc123", "subnet-def456"]`)' + + allowed_security_group_ids: + type: list(string) + required: false + description: 'Security group IDs allowed to connect to the database (e.g. `["sg-lambda-app", "sg-fargate-backend"]`)' + + allowed_cidr_blocks: + type: list(string) + required: false + description: 'CIDR blocks allowed to connect to the database (e.g. `["10.0.1.0/24", "10.0.2.0/24"]`)' + + backup_retention_period: + type: number + required: false + description: "Days to retain automated backups, 0-35. 0 disables backups (not recommended). 7+ required for point-in-time recovery (e.g. `7`)" + + backup_window: + type: string + required: false + description: 'Daily backup time window in UTC format HH:MM-HH:MM, must be at least 30 minutes (e.g. `03:00-04:00`)' + + maintenance_window: + type: string + required: false + description: 'Weekly maintenance window in UTC format ddd:HH:MM-ddd:HH:MM, must not overlap backup_window (e.g. `mon:04:00-mon:05:00`)' + + skip_final_snapshot: + type: bool + required: false + description: "`false` (recommended) creates final snapshot before deletion. `true` skips snapshot - use only for dev/test databases" + + final_snapshot_identifier: + type: string + required: false + description: "Name for final snapshot when database is deleted. Required if skip_final_snapshot is false (e.g. `myapp-db-final-snapshot`)" + + deletion_protection: + type: bool + required: false + description: "`false` (default) allows database deletion. `true` prevents accidental deletion - recommended for production databases" + + enabled_cloudwatch_logs_exports: + type: list(string) + required: false + description: 'PostgreSQL log types to export to CloudWatch (e.g. `["postgresql"]` for general logs, `["postgresql", "upgrade"]` for logs and upgrade logs)' + + monitoring_interval: + type: number + required: false + description: "Enhanced monitoring interval in seconds: 0 (disabled), 1, 5, 10, 15, 30, 60. Values >0 require monitoring_role_arn (e.g. `60`)" + + monitoring_role_arn: + type: string + required: false + description: "IAM role ARN for enhanced monitoring. Required if monitoring_interval > 0 (e.g. `arn:aws:iam::123456789012:role/rds-monitoring-role`)" + + performance_insights_enabled: + type: bool + required: false + description: "`false` (default) disables performance insights. `true` enables advanced performance monitoring (additional costs apply)" + + performance_insights_retention_period: + type: number + required: false + description: "Days to retain performance insights data: 7 (free tier) or 731 (2 years, additional cost). Only applies if performance_insights_enabled is true (e.g. `7`)" + + auto_minor_version_upgrade: + type: bool + required: false + description: "`true` (default) automatically applies minor engine upgrades during maintenance window. `false` requires manual upgrades" + + apply_immediately: + type: bool + required: false + description: "`false` (default) applies changes during maintenance window. `true` applies changes immediately (may cause downtime)" + + parameter_group_name: + type: string + required: false + description: "Custom DB parameter group name for PostgreSQL configuration. If not specified, uses default parameter group (e.g. `custom-postgres15-params`)" + + tags: + type: map(string) + required: false + description: 'Resource tags for organization and cost tracking (e.g. `{"Environment": "production", "Application": "web-api"}`)' + + enable_ssm_bastion_access: + type: bool + required: false + description: "`false` (default) disables SSM bastion resources. `true` creates a security group and IAM instance profile that users can attach to their own EC2 instances for SSM Session Manager port forwarding access to the database" + +outputs: + db_instance_id: + type: string + description: "Unique identifier of the RDS instance" + + db_instance_arn: + type: string + description: "Amazon Resource Name (ARN) of the RDS instance" + + db_instance_endpoint: + type: string + description: "Connection endpoint in format hostname:port (e.g. mydb.abc123.us-east-1.rds.amazonaws.com:5432)" + + db_instance_name: + type: string + description: "Name of the initial database created" + + db_instance_username: + type: string + description: "Master username for database access" + + db_instance_resource_id: + type: string + description: "Resource ID of the RDS instance (format: db-ABCDEFGHIJKLMNOPQRS)" + + db_subnet_group_id: + type: string + description: "ID of the DB subnet group" + + db_security_group_id: + type: string + description: "ID of the security group attached to the RDS instance" + + db_master_password: + type: string + description: "Master password for the RDS instance (sensitive)" + + codebuild_project_name: + type: string + description: "Name of the CodeBuild project for database operations" + + codebuild_project_arn: + type: string + description: "ARN of the CodeBuild project for database operations" + + bastion_security_group_id: + type: string + description: "Security group ID for SSM bastion instances (only created if enable_ssm_bastion_access is true). Attach this to EC2 instances that need database access via SSM port forwarding" + + bastion_instance_profile_name: + type: string + description: "IAM instance profile name for SSM bastion instances (only created if enable_ssm_bastion_access is true). Attach this to EC2 instances to enable SSM Session Manager access" diff --git a/rds-instance/module/main.tf b/rds-instance/module/main.tf new file mode 100644 index 0000000..1bfb148 --- /dev/null +++ b/rds-instance/module/main.tf @@ -0,0 +1,373 @@ +# Generate a random password for the master user +resource "random_password" "master_password" { + length = 32 + special = false +} + +# DB Subnet Group +resource "aws_db_subnet_group" "this" { + name = "${var.identifier}-subnet-group" + subnet_ids = var.subnet_ids + + tags = merge( + var.tags, + { + Name = "${var.identifier}-subnet-group" + } + ) +} + +# Security Group for RDS +resource "aws_security_group" "this" { + name = "${var.identifier}-sg" + description = "Security group for RDS PostgreSQL instance ${var.identifier}" + vpc_id = var.vpc_id + + tags = merge( + var.tags, + { + Name = "${var.identifier}-sg" + } + ) +} + +# Allow ingress from specified security groups +resource "aws_security_group_rule" "from_security_groups" { + count = length(var.allowed_security_group_ids) + + type = "ingress" + from_port = local.db_port + to_port = local.db_port + protocol = "tcp" + source_security_group_id = var.allowed_security_group_ids[count.index] + security_group_id = aws_security_group.this.id + description = "Allow PostgreSQL access from security group ${var.allowed_security_group_ids[count.index]}" +} + +# Allow ingress from specified CIDR blocks +resource "aws_security_group_rule" "from_cidr_blocks" { + count = length(var.allowed_cidr_blocks) > 0 ? 1 : 0 + + type = "ingress" + from_port = local.db_port + to_port = local.db_port + protocol = "tcp" + cidr_blocks = var.allowed_cidr_blocks + security_group_id = aws_security_group.this.id + description = "Allow PostgreSQL access from specified CIDR blocks" +} + +# Self-referential rule (allows resources in the same SG to communicate) +resource "aws_security_group_rule" "self" { + type = "ingress" + from_port = local.db_port + to_port = local.db_port + protocol = "tcp" + self = true + security_group_id = aws_security_group.this.id + description = "Allow PostgreSQL access within security group" +} + +# Allows codebuild job to pull images and updates +# More open to allow overriding job externally for additional work/image runs in future +# e.g. if a user wants to run containerised migrations in the same CodeBuild project +# trivy:ignore:avd-aws-0104 +resource "aws_security_group_rule" "egress" { + type = "egress" + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + security_group_id = aws_security_group.this.id + description = "Allow all outbound traffic" +} + +# Security Group for SSM Bastion instances (optional) +resource "aws_security_group" "bastion" { + count = var.enable_ssm_bastion_access ? 1 : 0 + + name = "${var.identifier}-bastion-sg" + description = "Security group for SSM bastion instances to access RDS ${var.identifier}" + vpc_id = var.vpc_id + + # Allow all outbound traffic (needed for SSM Session Manager) + egress { + from_port = 0 + to_port = 0 + protocol = "-1" + cidr_blocks = ["0.0.0.0/0"] + description = "Allow all outbound traffic for SSM" + } + + tags = merge( + var.tags, + { + Name = "${var.identifier}-bastion-sg" + } + ) +} + +# Allow ingress from bastion security group to RDS +resource "aws_security_group_rule" "from_bastion" { + count = var.enable_ssm_bastion_access ? 1 : 0 + + type = "ingress" + from_port = local.db_port + to_port = local.db_port + protocol = "tcp" + source_security_group_id = aws_security_group.bastion[0].id + security_group_id = aws_security_group.this.id + description = "Allow PostgreSQL access from SSM bastion instances" +} + +# Local variables +locals { + db_port = var.port != null ? var.port : 5432 +} + +# RDS PostgreSQL Instance +resource "aws_db_instance" "this" { + identifier = var.identifier + + # Engine configuration + engine = "postgres" + engine_version = var.engine_version + instance_class = var.instance_class + + # Storage configuration + allocated_storage = var.allocated_storage + max_allocated_storage = var.max_allocated_storage + storage_type = var.storage_type + storage_encrypted = var.storage_encrypted + kms_key_id = var.kms_key_id + + # Database configuration + db_name = var.database_name + username = var.master_username + password = random_password.master_password.result + port = local.db_port + + # Network configuration + db_subnet_group_name = aws_db_subnet_group.this.name + vpc_security_group_ids = [aws_security_group.this.id] + publicly_accessible = var.publicly_accessible + multi_az = var.multi_az + + # Backup configuration + backup_retention_period = var.backup_retention_period + backup_window = var.backup_window + maintenance_window = var.maintenance_window + skip_final_snapshot = var.skip_final_snapshot + final_snapshot_identifier = var.skip_final_snapshot == false ? ( + var.final_snapshot_identifier != null ? var.final_snapshot_identifier : "${var.identifier}-final-snapshot" + ) : null + + # Deletion protection + deletion_protection = var.deletion_protection + + # Monitoring and logging + enabled_cloudwatch_logs_exports = var.enabled_cloudwatch_logs_exports + monitoring_interval = var.monitoring_interval + monitoring_role_arn = var.monitoring_role_arn + + # Performance Insights + performance_insights_enabled = var.performance_insights_enabled + performance_insights_retention_period = var.performance_insights_enabled ? var.performance_insights_retention_period : null + + # Maintenance and upgrades + auto_minor_version_upgrade = var.auto_minor_version_upgrade + apply_immediately = var.apply_immediately + + # Parameter group + parameter_group_name = var.parameter_group_name + + # Tags + tags = merge( + var.tags, + { + Name = var.identifier + } + ) + +} + +# IAM Role for CodeBuild +resource "aws_iam_role" "codebuild" { + name = "${var.identifier}-codebuild-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "codebuild.amazonaws.com" + } + } + ] + }) + + tags = var.tags +} + +# IAM Policy for CodeBuild +resource "aws_iam_role_policy" "codebuild" { + role = aws_iam_role.codebuild.name + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "logs:CreateLogGroup", + "logs:CreateLogStream", + "logs:PutLogEvents" + ] + Resource = "arn:aws:logs:*:*:*" + }, + { + Effect = "Allow" + Action = [ + "ec2:CreateNetworkInterface", + "ec2:DescribeNetworkInterfaces", + "ec2:DeleteNetworkInterface", + "ec2:DescribeSubnets", + "ec2:DescribeSecurityGroups", + "ec2:DescribeDhcpOptions", + "ec2:DescribeVpcs", + "ec2:CreateNetworkInterfacePermission" + ] + Resource = "*" + } + ] + }) +} + +# CodeBuild Project for Database Operations +resource "aws_codebuild_project" "db_operations" { + name = "${var.identifier}-db-operations" + description = "CodeBuild project for creating databases and roles on RDS instance" + service_role = aws_iam_role.codebuild.arn + build_timeout = 10 + + artifacts { + type = "NO_ARTIFACTS" + } + + environment { + compute_type = "BUILD_GENERAL1_SMALL" + image = "postgres:16-alpine" + type = "LINUX_CONTAINER" + image_pull_credentials_type = "CODEBUILD" + + environment_variable { + name = "DB_HOST" + value = aws_db_instance.this.address + } + + environment_variable { + name = "DB_PORT" + value = tostring(aws_db_instance.this.port) + } + + environment_variable { + name = "DB_MASTER_USER" + value = var.master_username + } + + environment_variable { + name = "DB_PASSWORD" + value = random_password.master_password.result + } + } + + vpc_config { + vpc_id = var.vpc_id + subnets = var.subnet_ids + security_group_ids = [aws_security_group.this.id] + } + + source { + type = "NO_SOURCE" + buildspec = <<-EOT + version: 0.2 + phases: + build: + commands: + - echo "Running database operations..." + - | + export PGPASSWORD="$DB_PASSWORD" + + # Create role if it doesn't exist + if ! psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_MASTER_USER" -d postgres -tc \ + "SELECT 1 FROM pg_roles WHERE rolname='$DB_ROLE'" | grep -q 1; then + psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_MASTER_USER" -d postgres -c \ + "CREATE ROLE \"$DB_ROLE\" WITH LOGIN PASSWORD '$DB_ROLE_PASSWORD';" + psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_MASTER_USER" -d postgres -c \ + "GRANT \"$DB_ROLE\" TO \"$DB_MASTER_USER\";" + fi + + # Create database if it doesn't exist + psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_MASTER_USER" -d postgres -tc \ + "SELECT 1 FROM pg_database WHERE datname='$DB_NAME'" | grep -q 1 || \ + psql -h "$DB_HOST" -p "$DB_PORT" -U "$DB_MASTER_USER" -d postgres -c \ + "CREATE DATABASE \"$DB_NAME\" OWNER \"$DB_ROLE\";" + + echo "Database operations completed successfully" + EOT + } + + tags = var.tags +} + +# IAM Role for SSM Bastion instances (optional) +resource "aws_iam_role" "bastion" { + count = var.enable_ssm_bastion_access ? 1 : 0 + + name = "${var.identifier}-bastion-role" + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "ec2.amazonaws.com" + } + } + ] + }) + + tags = merge( + var.tags, + { + Name = "${var.identifier}-bastion-role" + } + ) +} + +# Attach AWS managed policy for SSM +resource "aws_iam_role_policy_attachment" "bastion_ssm" { + count = var.enable_ssm_bastion_access ? 1 : 0 + + role = aws_iam_role.bastion[0].name + policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore" +} + +# IAM Instance Profile for SSM Bastion instances +resource "aws_iam_instance_profile" "bastion" { + count = var.enable_ssm_bastion_access ? 1 : 0 + + name = "${var.identifier}-bastion-profile" + role = aws_iam_role.bastion[0].name + + tags = merge( + var.tags, + { + Name = "${var.identifier}-bastion-profile" + } + ) +} diff --git a/rds-instance/module/outputs.tf b/rds-instance/module/outputs.tf new file mode 100644 index 0000000..e917918 --- /dev/null +++ b/rds-instance/module/outputs.tf @@ -0,0 +1,65 @@ +output "db_instance_id" { + description = "Unique identifier of the RDS instance" + value = aws_db_instance.this.id +} + +output "db_instance_arn" { + description = "Amazon Resource Name (ARN) of the RDS instance" + value = aws_db_instance.this.arn +} + +output "db_instance_endpoint" { + description = "Connection endpoint in format hostname:port" + value = aws_db_instance.this.endpoint +} + +output "db_instance_name" { + description = "Name of the initial database created" + value = aws_db_instance.this.db_name +} + +output "db_instance_username" { + description = "Master username for database access" + value = aws_db_instance.this.username +} + +output "db_instance_resource_id" { + description = "Resource ID of the RDS instance" + value = aws_db_instance.this.resource_id +} + +output "db_subnet_group_id" { + description = "ID of the DB subnet group" + value = aws_db_subnet_group.this.id +} + +output "db_security_group_id" { + description = "ID of the security group attached to the RDS instance" + value = aws_security_group.this.id +} + +output "db_master_password" { + description = "Master password for the RDS instance" + value = random_password.master_password.result + sensitive = true +} + +output "codebuild_project_name" { + description = "Name of the CodeBuild project for database operations" + value = aws_codebuild_project.db_operations.name +} + +output "codebuild_project_arn" { + description = "ARN of the CodeBuild project for database operations" + value = aws_codebuild_project.db_operations.arn +} + +output "bastion_security_group_id" { + description = "Security group ID for SSM bastion instances (empty if enable_ssm_bastion_access is false)" + value = var.enable_ssm_bastion_access ? aws_security_group.bastion[0].id : "" +} + +output "bastion_instance_profile_name" { + description = "IAM instance profile name for SSM bastion instances (empty if enable_ssm_bastion_access is false)" + value = var.enable_ssm_bastion_access ? aws_iam_instance_profile.bastion[0].name : "" +} diff --git a/rds-instance/module/variables.tf b/rds-instance/module/variables.tf new file mode 100644 index 0000000..45f480a --- /dev/null +++ b/rds-instance/module/variables.tf @@ -0,0 +1,194 @@ +variable "identifier" { + type = string + description = "Unique identifier for the RDS instance" +} + +variable "engine_version" { + type = string + description = "PostgreSQL engine version" + default = null +} + +variable "instance_class" { + type = string + description = "Compute and memory capacity for the RDS instance" + default = "db.t3.micro" +} + +variable "allocated_storage" { + type = number + description = "Initial storage size in GB" + default = 20 +} + +variable "max_allocated_storage" { + type = number + description = "Maximum storage autoscaling limit in GB" + default = null +} + +variable "storage_type" { + type = string + description = "Storage type (gp2, gp3, io1)" + default = "gp3" +} + +variable "storage_encrypted" { + type = bool + description = "Enable storage encryption at rest" + default = true +} + +variable "kms_key_id" { + type = string + description = "ARN of AWS KMS key for encryption" + default = null +} + +variable "database_name" { + type = string + description = "Initial database name to create" + default = null +} + +variable "master_username" { + type = string + description = "Master username for database access" + default = "postgres" +} + +variable "port" { + type = number + description = "TCP port for database connections" + default = null +} + +variable "multi_az" { + type = bool + description = "Enable multi-AZ deployment" + default = false +} + +variable "publicly_accessible" { + type = bool + description = "Allow public access to the database" + default = false +} + +variable "vpc_id" { + type = string + description = "VPC ID where RDS will be deployed" +} + +variable "subnet_ids" { + type = list(string) + description = "List of subnet IDs for RDS subnet group" +} + +variable "allowed_security_group_ids" { + type = list(string) + description = "Security group IDs allowed to connect to the database" + default = [] +} + +variable "allowed_cidr_blocks" { + type = list(string) + description = "CIDR blocks allowed to connect to the database" + default = [] +} + +variable "backup_retention_period" { + type = number + description = "Days to retain automated backups" + default = 7 +} + +variable "backup_window" { + type = string + description = "Daily backup time window in UTC" + default = null +} + +variable "maintenance_window" { + type = string + description = "Weekly maintenance window in UTC" + default = null +} + +variable "skip_final_snapshot" { + type = bool + description = "Skip final snapshot before deletion" + default = false +} + +variable "final_snapshot_identifier" { + type = string + description = "Name for final snapshot when database is deleted" + default = null +} + +variable "deletion_protection" { + type = bool + description = "Prevent accidental deletion" + default = false +} + +variable "enabled_cloudwatch_logs_exports" { + type = list(string) + description = "PostgreSQL log types to export to CloudWatch" + default = [] +} + +variable "monitoring_interval" { + type = number + description = "Enhanced monitoring interval in seconds" + default = 0 +} + +variable "monitoring_role_arn" { + type = string + description = "IAM role ARN for enhanced monitoring" + default = null +} + +variable "performance_insights_enabled" { + type = bool + description = "Enable performance insights" + default = false +} + +variable "performance_insights_retention_period" { + type = number + description = "Days to retain performance insights data" + default = 7 +} + +variable "auto_minor_version_upgrade" { + type = bool + description = "Automatically apply minor engine upgrades" + default = true +} + +variable "apply_immediately" { + type = bool + description = "Apply changes immediately instead of during maintenance window" + default = false +} + +variable "parameter_group_name" { + type = string + description = "Custom DB parameter group name" + default = null +} + +variable "tags" { + type = map(string) + description = "Resource tags" + default = {} +} + +variable "enable_ssm_bastion_access" { + type = bool + description = "Enable creation of security group and IAM instance profile for SSM bastion access" + default = false +}