infra/terraform/main.tf
Jeremie Fraeys e2f732c0f5
infra: cleanup repository and add rollback documentation
- Remove unimplemented placeholder roles (airflow, spark)
- Delete cache files (__pycache__, .DS_Store) and generated inventory
- Remove outdated INFRA_GAP_ANALYSIS.md (functionality now in README)
- Standardize DISABLED comments for monitoring stack (Prometheus, Loki, Grafana)
- Add ROLLBACK.md with comprehensive recovery procedures
- Expand vault.example.yml with all backup and alerting variables
- Update README with complete vault variables documentation
2026-03-06 14:40:56 -05:00

377 lines
9.9 KiB
HCL

terraform {
required_version = ">= 1.5.0"
backend "s3" {
key = "infra/terraform.tfstate"
# bucket, region, endpoint, access_key, secret_key passed via -backend-config during init
skip_credentials_validation = true
skip_metadata_api_check = true
skip_region_validation = true
force_path_style = true
}
required_providers {
linode = {
source = "linode/linode"
version = "~> 2.0"
}
cloudflare = {
source = "cloudflare/cloudflare"
version = "~> 4.0"
}
}
}
provider "linode" {
token = var.linode_token
}
provider "cloudflare" {
api_token = var.cloudflare_api_token
}
resource "linode_stackscript" "essentials" {
label = "essentials"
description = "Baseline server init (SSH hardening, UFW, Docker, Ansible, etc.)"
images = [var.image]
rev_note = "managed by terraform"
script = file("${path.module}/../stackscripts/essentials.sh")
}
resource "linode_stackscript" "services" {
label = "services"
description = "Services node init (runs essentials + services specific steps)"
images = [var.image]
rev_note = "managed by terraform"
script = replace(
file("${path.module}/../stackscripts/services.sh"),
"__ESSENTIALS_STACKSCRIPT_ID__",
tostring(linode_stackscript.essentials.id)
)
}
resource "linode_instance" "web" {
label = var.web_label
region = var.region
type = var.instance_type
image = var.image
root_pass = var.root_pass
authorized_keys = [var.ssh_public_key]
stackscript_id = linode_stackscript.essentials.id
stackscript_data = {
NAME = var.web_label
GROUP = var.group
SSH_USER = var.user
USER_PASSWORD = var.user_password
SSH_PUBLIC_KEY = var.ssh_public_key
SSH_PORT = var.ssh_port
TIMEZONE = var.timezone
ADD_CLOUDFLARE_IPS = var.add_cloudflare_ips
}
lifecycle {
ignore_changes = [
root_pass,
stackscript_id,
stackscript_data,
]
}
}
resource "linode_instance" "services" {
label = var.services_label
region = var.region
type = var.instance_type
image = var.image
root_pass = var.root_pass
authorized_keys = [var.ssh_public_key]
stackscript_id = linode_stackscript.services.id
stackscript_data = {
NAME = var.services_label
GROUP = var.group
SSH_USER = var.user
USER_PASSWORD = var.user_password
SSH_PUBLIC_KEY = var.ssh_public_key
SSH_PORT = var.ssh_port
TIMEZONE = var.timezone
ADD_CLOUDFLARE_IPS = var.add_cloudflare_ips
}
lifecycle {
ignore_changes = [
root_pass,
stackscript_id,
stackscript_data,
]
}
}
resource "cloudflare_record" "root_a" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "@"
type = "A"
content = sort(tolist(linode_instance.web.ipv4))[0]
ttl = 1
proxied = true
}
resource "cloudflare_record" "root_aaaa" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "@"
type = "AAAA"
content = split("/", linode_instance.web.ipv6)[0]
ttl = 1
proxied = true
}
resource "cloudflare_record" "www_a" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "www"
type = "A"
content = sort(tolist(linode_instance.web.ipv4))[0]
ttl = 1
proxied = true
}
resource "cloudflare_record" "www_aaaa" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "www"
type = "AAAA"
content = split("/", linode_instance.web.ipv6)[0]
ttl = 1
proxied = true
}
resource "cloudflare_record" "services_a" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "services"
type = "A"
content = sort(tolist(linode_instance.services.ipv4))[0]
ttl = 1
proxied = true
}
resource "cloudflare_record" "services_aaaa" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "services"
type = "AAAA"
content = split("/", linode_instance.services.ipv6)[0]
ttl = 1
proxied = true
}
resource "cloudflare_record" "services_ssh_a" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "services-ssh"
type = "A"
content = sort(tolist(linode_instance.services.ipv4))[0]
ttl = 1
proxied = false
}
resource "cloudflare_record" "services_ssh_aaaa" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "services-ssh"
type = "AAAA"
content = split("/", linode_instance.services.ipv6)[0]
ttl = 1
proxied = false
}
resource "cloudflare_record" "auth_services_a" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "auth"
type = "A"
content = sort(tolist(linode_instance.services.ipv4))[0]
ttl = 1
proxied = true
}
resource "cloudflare_record" "auth_services_aaaa" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "auth"
type = "AAAA"
content = split("/", linode_instance.services.ipv6)[0]
ttl = 1
proxied = true
}
resource "cloudflare_record" "git_services_a" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "git"
type = "A"
content = sort(tolist(linode_instance.services.ipv4))[0]
ttl = var.cloudflare_ttl
proxied = false
}
resource "cloudflare_record" "git_services_aaaa" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "git"
type = "AAAA"
content = split("/", linode_instance.services.ipv6)[0]
ttl = var.cloudflare_ttl
proxied = false
}
# DISABLED: Grafana DNS records - uncomment to enable monitoring stack
# resource "cloudflare_record" "grafana_services_a" {
# count = var.enable_cloudflare_dns ? 1 : 0
# zone_id = var.cloudflare_zone_id
# name = "grafana"
# type = "A"
# content = sort(tolist(linode_instance.services.ipv4))[0]
# ttl = 1
# proxied = true
# }
# resource "cloudflare_record" "grafana_services_aaaa" {
# count = var.enable_cloudflare_dns ? 1 : 0
# zone_id = var.cloudflare_zone_id
# name = "grafana"
# type = "AAAA"
# content = split("/", linode_instance.services.ipv6)[0]
# ttl = 1
# proxied = true
# }
# DISABLED: Prometheus DNS records - uncomment to enable monitoring stack
# resource "cloudflare_record" "prometheus_services_a" {
# count = var.enable_cloudflare_dns ? 1 : 0
# zone_id = var.cloudflare_zone_id
# name = "prometheus"
# type = "A"
# content = sort(tolist(linode_instance.services.ipv4))[0]
# ttl = 1
# proxied = true
# }
# resource "cloudflare_record" "prometheus_services_aaaa" {
# count = var.enable_cloudflare_dns ? 1 : 0
# zone_id = var.cloudflare_zone_id
# name = "prometheus"
# type = "AAAA"
# content = split("/", linode_instance.services.ipv6)[0]
# ttl = 1
# proxied = true
# }
# App DNS records
resource "cloudflare_record" "app_services_a" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "app"
type = "A"
content = sort(tolist(linode_instance.services.ipv4))[0]
ttl = 1
proxied = true
}
resource "cloudflare_record" "app_services_aaaa" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "app"
type = "AAAA"
content = split("/", linode_instance.services.ipv6)[0]
ttl = 1
proxied = true
}
resource "cloudflare_record" "mail_a" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "mail"
type = "A"
content = sort(tolist(linode_instance.web.ipv4))[0]
ttl = var.cloudflare_ttl
proxied = false
}
resource "cloudflare_record" "mail_aaaa" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "mail"
type = "AAAA"
content = split("/", linode_instance.web.ipv6)[0]
ttl = var.cloudflare_ttl
proxied = false
}
resource "cloudflare_record" "services_wildcard_a" {
count = (var.enable_cloudflare_dns && var.enable_services_wildcard) ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "*"
type = "A"
content = sort(tolist(linode_instance.services.ipv4))[0]
ttl = 1
proxied = true
}
resource "cloudflare_record" "services_wildcard_aaaa" {
count = (var.enable_cloudflare_dns && var.enable_services_wildcard) ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "*"
type = "AAAA"
content = split("/", linode_instance.services.ipv6)[0]
ttl = 1
proxied = true
}
resource "cloudflare_record" "blizzard_cname" {
count = (var.enable_cloudflare_dns && length(var.object_storage_bucket) > 0 && length(var.object_storage_region) > 0) ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "blizzard"
type = "CNAME"
content = "${var.object_storage_bucket}.${var.object_storage_region}.linodeobjects.com"
ttl = var.cloudflare_ttl
proxied = false
}
resource "cloudflare_record" "dkim" {
count = (var.enable_cloudflare_dns && length(var.dkim_hostname) > 0 && length(var.dkim_value) > 0) ? 1 : 0
zone_id = var.cloudflare_zone_id
name = var.dkim_hostname
type = "TXT"
content = "v=DKIM1; ${var.dkim_value}"
ttl = var.cloudflare_ttl
proxied = false
}
resource "cloudflare_record" "return_path" {
count = (var.enable_cloudflare_dns && length(var.return_path_target) > 0) ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "pm-bounces"
type = "CNAME"
content = var.return_path_target
ttl = var.cloudflare_ttl
proxied = false
}
resource "cloudflare_record" "dmarc" {
count = var.enable_cloudflare_dns ? 1 : 0
zone_id = var.cloudflare_zone_id
name = "_dmarc"
type = "TXT"
content = "v=DMARC1; p=reject; rua=mailto:dmarc@jfraeys.com; adkim=s; aspf=r"
ttl = var.cloudflare_ttl
proxied = false
}