diff options
| author | Franck Cuny <franck@fcuny.net> | 2025-08-31 13:33:54 -0700 |
|---|---|---|
| committer | Franck Cuny <franck@fcuny.net> | 2025-08-31 13:33:54 -0700 |
| commit | 145e1dab68caf3f57c53820c6359bef83a5ce52a (patch) | |
| tree | 592546ad50121b32f386f532e3be8f75cb521d54 /terraform | |
| parent | add terranix (diff) | |
| download | infra-145e1dab68caf3f57c53820c6359bef83a5ce52a.tar.gz | |
manage terraform configuration with terranix
All the terraform configuration is managed within one state instead of
having multiple state for each components. This might not be the best
practice but it simplifies things for me.
Now, all I need to do is to run `nix run .#tf -- plan` and I can see
what will be changed for all the resources that I care about.
Diffstat (limited to 'terraform')
| -rw-r--r-- | terraform/admin/backups.nix | 28 | ||||
| -rw-r--r-- | terraform/admin/base.nix | 30 | ||||
| -rw-r--r-- | terraform/admin/default.nix | 9 | ||||
| -rw-r--r-- | terraform/admin/dns.nix | 117 | ||||
| -rw-r--r-- | terraform/admin/droplet-proxy.nix | 89 | ||||
| -rw-r--r-- | terraform/admin/variables.nix | 29 |
6 files changed, 302 insertions, 0 deletions
diff --git a/terraform/admin/backups.nix b/terraform/admin/backups.nix new file mode 100644 index 0000000..ae021e5 --- /dev/null +++ b/terraform/admin/backups.nix @@ -0,0 +1,28 @@ +{ lib, ... }: +{ + resource.google_storage_bucket.backups = { + name = "fcuny-infra-backups"; + storage_class = "NEARLINE"; + force_destroy = true; + uniform_bucket_level_access = true; + public_access_prevention = "enforced"; + location = lib.tfRef "var.gcp_region"; + + lifecycle_rule = [ + { + condition.age = 365; # After 1 year + action = { + type = "SetStorageClass"; + storage_class = "COLDLINE"; + }; + } + { + condition.age = 730; # After 2 years + action = { + type = "SetStorageClass"; + storage_class = "ARCHIVE"; + }; + } + ]; + }; +} diff --git a/terraform/admin/base.nix b/terraform/admin/base.nix new file mode 100644 index 0000000..7221742 --- /dev/null +++ b/terraform/admin/base.nix @@ -0,0 +1,30 @@ +{ lib, ... }: +{ + provider.google = { + region = lib.tfRef "var.gcp_region"; + project = lib.tfRef "var.gcp_project"; + }; + + terraform = { + backend.gcs = { + bucket = "fcuny-infra-tofu-state"; + prefix = "admin"; + }; + required_providers = { + google = { + source = "hashicorp/google"; + }; + cloudflare = { + source = "cloudflare/cloudflare"; + }; + digitalocean = { + source = "digitalocean/digitalocean"; + version = "~> 2.0"; + }; + random = { + source = "hashicorp/random"; + version = "~> 3.1"; + }; + }; + }; +} diff --git a/terraform/admin/default.nix b/terraform/admin/default.nix new file mode 100644 index 0000000..0cbbe12 --- /dev/null +++ b/terraform/admin/default.nix @@ -0,0 +1,9 @@ +{ + imports = [ + ./backups.nix + ./base.nix + ./dns.nix + ./droplet-proxy.nix + ./variables.nix + ]; +} diff --git a/terraform/admin/dns.nix b/terraform/admin/dns.nix new file mode 100644 index 0000000..eeddfd5 --- /dev/null +++ b/terraform/admin/dns.nix @@ -0,0 +1,117 @@ +{ lib, ... }: +let + zoneId = lib.tfRef "var.cloudflare_zone_id"; + primaryIPv4 = "165.232.158.110"; + domain = "fcuny.net"; + + # GitHub Pages IP addresses for root domain + githubPagesIPs = [ + "185.199.108.153" + "185.199.110.153" + "185.199.109.153" + "185.199.111.153" + ]; + + mkARecord = name: content: ttl: { + inherit name content ttl; + type = "A"; + proxied = false; + zone_id = zoneId; + }; + + mkCNAMERecord = name: content: ttl: { + inherit name content ttl; + type = "CNAME"; + proxied = false; + zone_id = zoneId; + }; + + mkMXRecord = name: content: priority: { + inherit name content priority; + type = "MX"; + proxied = false; + ttl = 1; + zone_id = zoneId; + }; + + mkSRVRecord = name: port: priority: target: weight: { + inherit name priority; + type = "SRV"; + proxied = false; + ttl = 1; + zone_id = zoneId; + data = { + inherit + port + priority + target + weight + ; + }; + }; + + mkTXTRecord = name: content: { + inherit name content; + type = "TXT"; + proxied = false; + ttl = 1; + zone_id = zoneId; + }; + + mkMultipleARecords = + baseName: ips: + lib.listToAttrs ( + lib.imap0 (i: ip: { + name = "${baseName}_${toString i}"; + value = mkARecord domain ip 1; + }) ips + ); + + dkimRecords = lib.listToAttrs ( + lib.imap1 + (i: _: { + name = "cname_dkim_${toString (i - 1)}"; + value = mkCNAMERecord "fm${toString i}._domainkey" "fm${toString i}.${domain}.dkim.fmhosted.com" 60; + }) + [ + 1 + 2 + 3 + ] + ); + + subdomainARecords = { + cname_code = mkARecord "code.${domain}" primaryIPv4 1; + cname_go = mkARecord "go.${domain}" primaryIPv4 1; + cname_id = mkARecord "id.${domain}" primaryIPv4 1; + }; + + mxRecords = { + mx_0 = mkMXRecord domain "in1-smtp.messagingengine.com" 10; + mx_1 = mkMXRecord domain "in2-smtp.messagingengine.com" 20; + }; + + srvRecords = { + srv_caldavs = mkSRVRecord "_caldavs._tcp" 443 0 "caldav.fastmail.com" 1; + srv_caldav = mkSRVRecord "_caldav._tcp" 0 0 "." 0; + srv_carddavs = mkSRVRecord "_carddavs._tcp" 443 0 "carddav.fastmail.com" 1; + srv_carddav = mkSRVRecord "_carddav._tcp" 0 0 "." 0; + srv_imaps = mkSRVRecord "_imaps._tcp" 993 0 "imap.fastmail.com" 1; + srv_imap = mkSRVRecord "_imap._tcp" 0 0 "." 0; + srv_smtp = mkSRVRecord "_submission._tcp" 587 0 "smtp.fastmail.com" 1; + }; + + txtRecords = { + txt_spf = mkTXTRecord domain "\"v=spf1 include:spf.messagingengine.com ?all\""; + }; + +in +{ + resource.cloudflare_dns_record = + (mkMultipleARecords "cname_root" githubPagesIPs) + // subdomainARecords + // dkimRecords + // mxRecords + // srvRecords + // txtRecords; +} diff --git a/terraform/admin/droplet-proxy.nix b/terraform/admin/droplet-proxy.nix new file mode 100644 index 0000000..51ad138 --- /dev/null +++ b/terraform/admin/droplet-proxy.nix @@ -0,0 +1,89 @@ +{ lib, pkgs, ... }: +let + serverSize = "s-2vcpu-2gb"; + + extraFilesScript = pkgs.writeShellScript "extra-files-script" '' + #!/usr/bin/env bash + set -euo pipefail + + mkdir -p etc/ssh/ + + if [ -n "''${DO_SSH_HOSTKEY:-}" ]; then + echo "Setting up SSH host key from environment" + echo "$DO_SSH_HOSTKEY" | base64 -d > etc/ssh/ssh_host_ed25519_key + chmod 0600 etc/ssh/ssh_host_ed25519_key + else + echo "Warning: DO_SSH_HOSTKEY environment variable not set" + fi + ''; + +in +{ + provider.digitalocean = { + # Token will be read from DIGITALOCEAN_TOKEN environment variable + }; + + resource = { + # Random string for unique naming + random_string.host = { + length = 6; + special = false; + upper = false; + }; + + digitalocean_ssh_key.default = { + name = "nixos-anywhere-\${random_string.host.result}"; + public_key = lib.tfRef "var.digitalocean_public_key"; + }; + + digitalocean_droplet.nixos = { + name = "nixos-\${random_string.host.result}"; + image = "ubuntu-24-04-x64"; # Bootstrap image + size = serverSize; + region = lib.tfRef "var.digitalocean_region"; + ssh_keys = [ "\${digitalocean_ssh_key.default.id}" ]; + tags = [ + "nixos" + "infrastructure" + ]; + }; + }; + + module = { + nixos-system-build = { + source = "github.com/nix-community/nixos-anywhere//terraform/nix-build"; + attribute = ".#nixosConfigurations.do-rproxy.config.system.build.toplevel"; + }; + + nixos-disko = { + source = "github.com/nix-community/nixos-anywhere//terraform/nix-build"; + attribute = ".#nixosConfigurations.do-rproxy.config.system.build.diskoScript"; + }; + + nixos-install = { + source = "github.com/nix-community/nixos-anywhere//terraform/install"; + nixos_system = "\${module.nixos-system-build.result.out}"; + nixos_partitioner = "\${module.nixos-disko.result.out}"; + target_host = "\${digitalocean_droplet.nixos.ipv4_address}"; + build_on_remote = true; + extra_files_script = toString extraFilesScript; + }; + }; + + output = { + server_ip = { + description = "IP address of the NixOS server"; + value = "\${digitalocean_droplet.nixos.ipv4_address}"; + }; + + ssh_command = { + description = "SSH command to connect to the server"; + value = "ssh root@\${digitalocean_droplet.nixos.ipv4_address}"; + }; + + server_name = { + description = "Name of the created server"; + value = "\${digitalocean_droplet.nixos.name}"; + }; + }; +} diff --git a/terraform/admin/variables.nix b/terraform/admin/variables.nix new file mode 100644 index 0000000..0c795dd --- /dev/null +++ b/terraform/admin/variables.nix @@ -0,0 +1,29 @@ +{ + variable = { + gcp_region = { + description = "GCP region"; + type = "string"; + default = "us-west1"; + }; + gcp_project = { + description = "GCP project"; + type = "string"; + default = "fcuny-infra"; + }; + cloudflare_zone_id = { + description = "cloudflare zone ID"; + type = "string"; + default = "6878e48b5cb81c7d789040632153719d"; + }; + digitalocean_region = { + description = "DigitalOcean region"; + type = "string"; + default = "SFO3"; + }; + digitalocean_public_key = { + description = "SSH public key"; + type = "string"; + default = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAINBkozy+X96u5ciX766bJ/AyQ3xm1tXZTIr5+4PVFZFi"; + }; + }; +} |
