Infrastructure as Code & Drop-in Replacements
This document details the transition from manual cloud configuration ("ClickOps") to a fully declarative Infrastructure as Code (IaC) approach.
1. Architectural Decisions
OpenTofu over HashiCorp Terraform
- Decision: We utilize
OpenTofuCLI instead ofTerraformCLI. - Context: Following the 2023 license change by HashiCorp (MPL to BSL), the Linux Foundation forked the project into OpenTofu.
- Justification: OpenTofu serves as a 1:1 drop-in replacement. We maintain complete compatibility with existing
.tffiles, the HCL syntax, and thehashicorp/awsprovider, while adhering to true Open Source principles.
2. Infrastructure Topology
The code provisions the main-production-vpc (10.200.0.0/20) and sets up a robust 3-tier architecture.
graph TD
Client((User / Browser))
subgraph AWS Cloud ["AWS Cloud (eu-central-1)"]
IGW["Internet Gateway"]
subgraph VPC ["VPC: 10.200.0.0/20"]
subgraph PubA ["Public Subnet A (/24)"]
EC2["EC2 Bastion Server<br>Debian 13 + Docker"]
end
subgraph DataA ["Data Subnet A (/24)"]
RDS[("AWS RDS PostgreSQL<br>16.3")]
end
subgraph DataB ["Data Subnet B (/24)"]
Dummy["(Required for RDS Subnet Group)"]
end
end
end
Client -->|SSH / HTTP| IGW
IGW --> EC2
EC2 -->|Port 5432| RDS
classDef public fill:#1e88e5,stroke:#0d47a1,stroke-width:2px,color:#fff;
classDef data fill:#e53935,stroke:#b71c1c,stroke-width:2px,color:#fff;
class PubA public;
class DataA,DataB data;
3. Implementation Details
Security Group Referencing
To adhere strictly to the Principle of Least Privilege, the RDS database has publicly_accessible = false and possesses no inbound IP rules. Instead, it utilizes Security Group Referencing:
ingress {
description = "PostgreSQL from App Server"
from_port = 5432
to_port = 5432
protocol = "tcp"
security_groups = [aws_security_group.app_sg.id] # The "Red VIP Band"
}
app_sg (Bastion Host) are permitted to route traffic to the database.
Input Validation & Secret Management
No secrets or hardcoded IPs are tracked in version control. We utilize a local terraform.tfvars file (ignored via .gitignore) to inject sensitive data.
Input validation prevents API errors before they reach AWS:
variable "home_ip" {
type = string
validation {
condition = can(cidrhost(var.home_ip, 0))
error_message = "home_ip must be valid CIDR notation, e.g., 203.0.113.1/32"
}
}
4. Operational Workflow
The standard deployment lifecycle for this lab environment:
1. Verification
tofu init
tofu plan
2. Provisioning
tofu apply -auto-approve
3. Local Database Access (via SSH Tunnel):
Because the RDS instance is hidden in a private data subnet, local debugging requires port forwarding through the Bastion host:
ssh -L 5432:<rds-endpoint>:5432 admin@<ec2-public-ip>
4. Teardown:
tofu destroy -auto-approve