Skip to content

Commit e37574e

Browse files
feat(infra): Add complete main.tf, variables.tf, outputs.tf for Terraform module (#372)
* feat(infra): Add complete main.tf, variables.tf, outputs.tf for Terraform module Resolves #164 - Refactor infrastructure/terraform/ from flat .tf files into a composable module structure with network, compute, and data submodules. * style(terraform): fix formatting in main.tf via terraform fmt
1 parent 2172d60 commit e37574e

62 files changed

Lines changed: 4309 additions & 112 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

infrastructure/terraform/README.md

Lines changed: 85 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,95 @@
11
# Terraform Configurations
22

3-
Infrastructure as Code for cloud resource provisioning.
3+
Infrastructure as Code for VertexChain cloud resource provisioning.
44

55
## Overview
66

7-
Terraform modules for provisioning cloud infrastructure for VertexChain.
7+
Terraform modules for provisioning AWS infrastructure for VertexChain,
8+
a location-aware micro-messaging platform built on Stellar.
89

9-
## Contents
10+
## Module Structure
1011

11-
- AWS/GCP/Azure resource definitions
12-
- Network configurations
13-
- Database provisioning
14-
- Storage buckets
15-
- Load balancers
12+
```
13+
infrastructure/terraform/
14+
├── main.tf # Root module entry point
15+
├── variables.tf # Root module input variables
16+
├── outputs.tf # Root module outputs (ARNs for every resource)
17+
├── providers.tf # Terraform and provider configuration
18+
├── modules/
19+
│ ├── network/ # VPC, subnets, gateways, NACLs, security groups
20+
│ ├── compute/ # EKS, ASG, ALB, launch templates, target groups
21+
│ └── data/ # RDS, ElastiCache, S3, backup vaults & plans
22+
├── envs/ # Per-environment tfvars files
23+
│ ├── terraform.tfvars.dev
24+
│ ├── terraform.tfvars.staging
25+
│ ├── terraform.tfvars.prod
26+
│ └── terraform.tfvars.example
27+
├── tests/ # Terratest integration tests
28+
│ └── test_helper.go
29+
└── archive/ # Previous flat .tf files (kept for reference)
30+
```
1631

1732
## Usage
1833

19-
Run `terraform plan` and `terraform apply` to provision resources.
34+
```bash
35+
# Initialize Terraform
36+
terraform init
37+
38+
# Select workspace
39+
terraform workspace select dev || terraform workspace new dev
40+
41+
# Plan with environment-specific variables
42+
terraform plan -var-file=envs/terraform.tfvars.dev
43+
44+
# Apply changes
45+
terraform apply -var-file=envs/terraform.tfvars.dev
46+
```
47+
48+
## Workspace Strategy
49+
50+
Per-environment state isolation is handled by workspaces. Each environment
51+
uses its own `tfvars` file while sharing the same root module:
52+
53+
| Environment | Workspace | Variable file |
54+
|-------------|-----------|--------------------------|
55+
| dev | `dev` | `envs/terraform.tfvars.dev` |
56+
| staging | `staging` | `envs/terraform.tfvars.staging` |
57+
| prod | `prod` | `envs/terraform.tfvars.prod` |
58+
59+
## Outputs
60+
61+
All resource ARNs are surfaced through the root module's `outputs.tf`.
62+
Run `terraform output` to see the full list after an apply.
63+
64+
```bash
65+
terraform output
66+
# vpc_id = "vpc-xxx"
67+
# alb_arn = "arn:aws:elasticloadbalancing:..."
68+
# rds_instance_arn = "arn:aws:rds:..."
69+
# redis_replication_group_arn = "arn:aws:elasticache:..."
70+
# s3_uploads_bucket_arn = "arn:aws:s3:::..."
71+
# eks_cluster_arn = "arn:aws:eks:..."
72+
# waf_web_acl_arn = "arn:aws:wafv2:..."
73+
# cloudfront_distribution_arn = "arn:aws:cloudfront:..."
74+
# ...and many more
75+
```
76+
77+
## Migrating from the flat structure
78+
79+
The previous flat `.tf` files (vpc.tf, rds.tf, etc.) have been refactored into
80+
the submodule structure above. The original files are preserved in the
81+
`archive/` directory for reference and should be removed once the new modular
82+
structure is validated.
83+
84+
Before applying the new module structure to an existing deployment:
85+
86+
1. Import existing resources into the new module state:
87+
```bash
88+
terraform import module.network.aws_vpc.this vpc-xxx
89+
terraform import module.data.aws_db_instance.postgres db-xxx
90+
# ... etc.
91+
```
92+
93+
2. Run `terraform plan` to verify no unexpected changes.
94+
95+
3. Apply once all differences are reconciled.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Archived Terraform files
2+
3+
This directory contains the previous flat `.tf` files that were in the root
4+
`infrastructure/terraform/` directory before the module-based refactoring
5+
(see issue #164).
6+
7+
## Why was this refactored?
8+
9+
The old structure had 40+ `.tf` files in a single flat directory with no
10+
`main.tf` entry point, scattered variable declarations, duplicate resource
11+
definitions (e.g., `aws_security_group.alb` defined in both `alb.tf` and
12+
`security-groups.tf`), and no outputs for resource ARNs.
13+
14+
The new structure:
15+
- **`main.tf`** — clear root module entry point
16+
- **`outputs.tf`** — ARNs for every created resource
17+
- **`variables.tf`** — consolidated variable declarations (no duplicates)
18+
- **`modules/`** — clean split into `network`, `compute`, and `data` submodules
19+
20+
## Removal
21+
22+
These archive files can be safely removed once the new modular structure has
23+
been validated with `terraform plan` against a live environment. They are kept
24+
only as a reference during the migration period.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
resource "aws_cloudwatch_metric_alarm" "cpu_high" {
2+
alarm_name = "vertexchain-cpu-high"
3+
comparison_operator = "GreaterThanThreshold"
4+
evaluation_periods = 2
5+
metric_name = "CPUUtilization"
6+
namespace = "AWS/ECS"
7+
period = 300
8+
statistic = "Average"
9+
threshold = 80
10+
alarm_actions = [aws_sns_topic.vertexchain_alerts.arn]
11+
}
12+
13+
resource "aws_cloudwatch_metric_alarm" "memory_high" {
14+
alarm_name = "vertexchain-memory-high"
15+
comparison_operator = "GreaterThanThreshold"
16+
evaluation_periods = 2
17+
metric_name = "MemoryUtilization"
18+
namespace = "AWS/ECS"
19+
period = 300
20+
statistic = "Average"
21+
threshold = 80
22+
alarm_actions = [aws_sns_topic.vertexchain_alerts.arn]
23+
}
24+
25+
resource "aws_cloudwatch_metric_alarm" "errors_high" {
26+
alarm_name = "vertexchain-errors-high"
27+
comparison_operator = "GreaterThanThreshold"
28+
evaluation_periods = 1
29+
metric_name = "5XXError"
30+
namespace = "AWS/ApplicationELB"
31+
period = 60
32+
statistic = "Sum"
33+
threshold = 10
34+
alarm_actions = [aws_sns_topic.vertexchain_alerts.arn]
35+
}
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
variable "certificate_arn" {
2+
description = "ACM certificate ARN for HTTPS"
3+
type = string
4+
}
5+
6+
resource "aws_lb_listener" "https" {
7+
load_balancer_arn = aws_lb.main.arn
8+
port = 443
9+
protocol = "HTTPS"
10+
ssl_policy = "ELBSecurityPolicy-TLS13-1-2-2021-06"
11+
certificate_arn = var.certificate_arn
12+
13+
default_action {
14+
type = "forward"
15+
target_group_arn = aws_lb_target_group.app.arn
16+
}
17+
}
18+
19+
resource "aws_lb_listener" "http_redirect" {
20+
load_balancer_arn = aws_lb.main.arn
21+
port = 80
22+
protocol = "HTTP"
23+
24+
default_action {
25+
type = "redirect"
26+
redirect {
27+
port = "443"
28+
protocol = "HTTPS"
29+
status_code = "HTTP_301"
30+
}
31+
}
32+
}
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
resource "aws_lb" "main" {
2+
name = "${var.project_name}-${var.environment}-alb"
3+
internal = false
4+
load_balancer_type = "application"
5+
security_groups = [aws_security_group.alb.id]
6+
subnets = var.public_subnet_ids
7+
8+
enable_deletion_protection = var.environment == "production" ? true : false
9+
10+
tags = {
11+
Environment = var.environment
12+
Project = var.project_name
13+
}
14+
}
15+
16+
resource "aws_security_group" "alb" {
17+
name = "${var.project_name}-${var.environment}-alb-sg"
18+
description = "Security group for ALB"
19+
vpc_id = var.vpc_id
20+
21+
ingress {
22+
from_port = 80
23+
to_port = 80
24+
protocol = "tcp"
25+
cidr_blocks = ["0.0.0.0/0"]
26+
}
27+
28+
ingress {
29+
from_port = 443
30+
to_port = 443
31+
protocol = "tcp"
32+
cidr_blocks = ["0.0.0.0/0"]
33+
}
34+
35+
egress {
36+
from_port = 0
37+
to_port = 0
38+
protocol = "-1"
39+
cidr_blocks = ["0.0.0.0/0"]
40+
}
41+
42+
tags = {
43+
Environment = var.environment
44+
Project = var.project_name
45+
}
46+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
resource "aws_autoscaling_group" "app" {
2+
name = "${var.project_name}-${var.environment}-asg"
3+
min_size = var.asg_min_size
4+
max_size = var.asg_max_size
5+
desired_capacity = var.asg_desired_size
6+
vpc_zone_identifier = var.private_subnet_ids
7+
8+
launch_template {
9+
id = aws_launch_template.app.id
10+
version = "$Latest"
11+
}
12+
13+
health_check_type = "ELB"
14+
health_check_grace_period = 300
15+
16+
tag {
17+
key = "Name"
18+
value = "${var.project_name}-${var.environment}-app"
19+
propagate_at_launch = true
20+
}
21+
22+
tag {
23+
key = "Environment"
24+
value = var.environment
25+
propagate_at_launch = true
26+
}
27+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Weekly backup plan. Adds a higher frequency cold-storage tier on top
2+
# of the daily plan so we keep monthly snapshots for a full year without
3+
# paying hot-storage costs.
4+
#
5+
# `backup_retention_days` is declared in variables.tf; it controls the
6+
# DR-region copy retention, matching the primary tier so DR capacity
7+
# planning stays predictable.
8+
9+
resource "aws_backup_plan" "weekly" {
10+
name = "${var.project_name}-${var.environment}-weekly-plan"
11+
12+
rule {
13+
rule_name = "weekly_backup"
14+
target_vault_name = aws_backup_vault.main.name
15+
schedule = "cron(0 3 ? * SUN *)"
16+
start_window = 60
17+
completion_window = 360
18+
19+
lifecycle {
20+
cold_storage_after = 30
21+
delete_after = 365
22+
}
23+
24+
# Mirror the weekly snapshot into the DR-region vault so a single
25+
# regional outage does not lose the last good monthly copy.
26+
dynamic "copy_action" {
27+
for_each = var.enable_cross_region_backup ? [1] : []
28+
content {
29+
destination_vault_arn = aws_backup_vault.dr[0].arn
30+
31+
lifecycle {
32+
# Match the on-primary retention for consistency.
33+
cold_storage_after = 30
34+
delete_after = var.backup_retention_days
35+
}
36+
}
37+
}
38+
}
39+
40+
tags = {
41+
Environment = var.environment
42+
Project = var.project_name
43+
}
44+
}

0 commit comments

Comments
 (0)