1variable "environment" {
2description = "The target deployment environment (e.g., 'dev', 'staging', 'prod')."
3type = string
4default = "dev"
5validation {
6condition = contains(["dev", "staging", "prod"], var.environment)
7error_message = "Environment must be one of 'dev', 'staging', or 'prod'."
8}
9}
10
11variable "enable_database" {
12description = "Set to true to provision the database resources."
13type = bool
14default = true
15}
16
17# --- Network Resources ---
18resource "aws_vpc" "main" {
19cidr_block = "10.0.0.0/16"
20tags = {
21Name = "${var.environment}-main-vpc"
22Environment = var.environment
23}
24}
25
26resource "aws_subnet" "public" {
27count = 2
28vpc_id = aws_vpc.main.id
29cidr_block = "10.0.${count.index + 1}.0/24"
30availability_zone = data.aws_availability_zones.available.names[count.index]
31
32tags = {
33Name = "${var.environment}-public-subnet-${count.index}"
34Environment = var.environment
35}
36}
37
38resource "aws_internet_gateway" "gw" {
39vpc_id = aws_vpc.main.id
40
41tags = {
42Name = "${var.environment}-internet-gateway"
43Environment = var.environment
44}
45}
46
47# --- Database Resources (Conditional) ---
48resource "aws_db_instance" "app_db" {
49# Only create the database if enable_database is true
50count = var.enable_database ? 1 : 0
51
52identifier = "${var.environment}-app-db"
53engine = "postgres"
54engine_version = "14.5"
55allocated_storage = 20
56storage_type = "gp2"
57instance_class = "db.t3.micro"
58db_name = "appdb"
59username = "appuser"
60password = "a-very-secure-password-for-dev"
61parameter_group_name = "default.postgres14"
62skip_final_snapshot = true
63
64# Explicitly depend on the VPC to ensure it's created first.
65# This is often implicitly handled, but explicit is clearer.
66vpc_security_group_ids = [aws_security_group.db.id]
67db_subnet_group_name = aws_db_subnet_group.db_subnet_group.name
68
69tags = {
70Name = "${var.environment}-app-db"
71Environment = var.environment
72}
73}
74
75resource "aws_db_subnet_group" "db_subnet_group" {
76# Only create DB subnet group if database is enabled.
77count = var.enable_database ? 1 : 0
78
79name = "${var.environment}-db-subnet-group"
80subnet_ids = aws_subnet.public[*].id
81
82tags = {
83Name = "${var.environment}-db-subnet-group"
84Environment = var.environment
85}
86}
87
88# --- Application Resources ---
89resource "aws_security_group" "app_sg" {
90name = "${var.environment}-app-sg"
91description = "Allow TLS inbound traffic"
92vpc_id = aws_vpc.main.id
93
94ingress {
95description = "TLS from VPC"
96from_port = 443
97to_port = 443
98protocol = "tcp"
99cidr_blocks = ["10.0.0.0/16"]
100}
101
102egress {
103from_port = 0
104to_port = 0
105protocol = "-1"
106cidr_blocks = ["0.0.0.0/0"]
107}
108
109tags = {
110Name = "${var.environment}-app-sg"
111Environment = var.environment
112}
113}
114
115resource "aws_security_group" "db" {
116name = "${var.environment}-db-sg"
117description = "Allow DB traffic from app SG"
118vpc_id = aws_vpc.main.id
119
120ingress {
121description = "Postgres from App SG"
122from_port = 5432
123to_port = 5432
124protocol = "tcp"
125security_groups = [aws_security_group.app_sg.id]
126}
127
128egress {
129from_port = 0
130to_port = 0
131protocol = "-1"
132cidr_blocks = ["0.0.0.0/0"]
133}
134
135tags = {
136Name = "${var.environment}-db-sg"
137Environment = var.environment
138}
139}
140
141resource "aws_instance" "app_server" {
142ami = "ami-0abcdef1234567890"
143instance_type = "t2.micro"
144subnet_id = aws_subnet.public[0].id
145vpc_security_group_ids = [aws_security_group.app_sg.id]
146
147# Ensure DB is provisioned before app server attempts to connect (if enabled)
148# This dependency is implicit via the security group reference, but explicit can be added.
149# depends_on = [aws_db_instance.app_db, aws_db_subnet_group.db_subnet_group]
150
151tags = {
152Name = "${var.environment}-app-server"
153Environment = var.environment
154}
155}
156
157# --- Data Sources ---
158data "aws_availability_zones" "available" {}
159
160# --- Outputs ---
161output "vpc_id" {
162description = "The ID of the VPC."
163value = aws_vpc.main.id
164}
165
166output "app_server_public_ip" {
167description = "Public IP address of the application server."
168value = aws_instance.app_server.public_ip
169}
170
171output "database_endpoint" {
172description = "Endpoint of the application database."
173# Safely access the endpoint only if the database was provisioned.
174value = var.enable_database && length(aws_db_instance.app_db) > 0 ? aws_db_instance.app_db[0].address : "Database not provisioned."
175}