aboutsummaryrefslogtreecommitdiff
path: root/terraform
diff options
context:
space:
mode:
Diffstat (limited to 'terraform')
-rw-r--r--terraform/admin/backups.nix28
-rw-r--r--terraform/admin/base.nix30
-rw-r--r--terraform/admin/default.nix9
-rw-r--r--terraform/admin/dns.nix117
-rw-r--r--terraform/admin/droplet-proxy.nix89
-rw-r--r--terraform/admin/variables.nix29
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";
+ };
+ };
+}