diff options
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"; + }; + }; +} |
