From 7bc465b41469cfeabf76bcc129a2457f02c2ecc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= Date: Sat, 7 Feb 2026 13:26:28 +0100 Subject: [PATCH 1/4] hosts: add testvm01, testvm02, testvm03 test hosts Three permanent test hosts for validating deployment and bootstrapping workflow. Each host configured with: - Static IP (10.69.13.20-22/24) - Vault AppRole integration - Bootstrap from deploy-test-hosts branch Co-Authored-By: Claude Opus 4.5 --- flake.nix | 27 ++++++++++++ hosts/testvm01/configuration.nix | 66 ++++++++++++++++++++++++++++++ hosts/testvm01/default.nix | 5 +++ hosts/testvm02/configuration.nix | 66 ++++++++++++++++++++++++++++++ hosts/testvm02/default.nix | 5 +++ hosts/testvm03/configuration.nix | 66 ++++++++++++++++++++++++++++++ hosts/testvm03/default.nix | 5 +++ terraform/vault/hosts-generated.tf | 16 ++++++++ terraform/vms.tf | 24 +++++++++++ 9 files changed, 280 insertions(+) create mode 100644 hosts/testvm01/configuration.nix create mode 100644 hosts/testvm01/default.nix create mode 100644 hosts/testvm02/configuration.nix create mode 100644 hosts/testvm02/default.nix create mode 100644 hosts/testvm03/configuration.nix create mode 100644 hosts/testvm03/default.nix diff --git a/flake.nix b/flake.nix index 91e32b9..fae0a17 100644 --- a/flake.nix +++ b/flake.nix @@ -195,6 +195,33 @@ ./hosts/vault01 ]; }; + testvm01 = nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { + inherit inputs self sops-nix; + }; + modules = commonModules ++ [ + ./hosts/testvm01 + ]; + }; + testvm02 = nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { + inherit inputs self sops-nix; + }; + modules = commonModules ++ [ + ./hosts/testvm02 + ]; + }; + testvm03 = nixpkgs.lib.nixosSystem { + inherit system; + specialArgs = { + inherit inputs self sops-nix; + }; + modules = commonModules ++ [ + ./hosts/testvm03 + ]; + }; }; packages = forAllSystems ( { pkgs }: diff --git a/hosts/testvm01/configuration.nix b/hosts/testvm01/configuration.nix new file mode 100644 index 0000000..77b71fe --- /dev/null +++ b/hosts/testvm01/configuration.nix @@ -0,0 +1,66 @@ +{ + config, + lib, + pkgs, + ... +}: + +{ + imports = [ + ../template2/hardware-configuration.nix + + ../../system + ../../common/vm + ]; + + # Host metadata (adjust as needed) + homelab.host = { + tier = "test"; # Start in test tier, move to prod after validation + }; + + nixpkgs.config.allowUnfree = true; + boot.loader.grub.enable = true; + boot.loader.grub.device = "/dev/vda"; + + networking.hostName = "testvm01"; + networking.domain = "home.2rjus.net"; + networking.useNetworkd = true; + networking.useDHCP = false; + services.resolved.enable = true; + networking.nameservers = [ + "10.69.13.5" + "10.69.13.6" + ]; + + systemd.network.enable = true; + systemd.network.networks."ens18" = { + matchConfig.Name = "ens18"; + address = [ + "10.69.13.20/24" + ]; + routes = [ + { Gateway = "10.69.13.1"; } + ]; + linkConfig.RequiredForOnline = "routable"; + }; + time.timeZone = "Europe/Oslo"; + + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + nix.settings.tarball-ttl = 0; + environment.systemPackages = with pkgs; [ + vim + wget + git + ]; + + # Open ports in the firewall. + # networking.firewall.allowedTCPPorts = [ ... ]; + # networking.firewall.allowedUDPPorts = [ ... ]; + # Or disable the firewall altogether. + networking.firewall.enable = false; + + system.stateVersion = "25.11"; # Did you read the comment? +} \ No newline at end of file diff --git a/hosts/testvm01/default.nix b/hosts/testvm01/default.nix new file mode 100644 index 0000000..57ed4b4 --- /dev/null +++ b/hosts/testvm01/default.nix @@ -0,0 +1,5 @@ +{ ... }: { + imports = [ + ./configuration.nix + ]; +} \ No newline at end of file diff --git a/hosts/testvm02/configuration.nix b/hosts/testvm02/configuration.nix new file mode 100644 index 0000000..dd3d718 --- /dev/null +++ b/hosts/testvm02/configuration.nix @@ -0,0 +1,66 @@ +{ + config, + lib, + pkgs, + ... +}: + +{ + imports = [ + ../template2/hardware-configuration.nix + + ../../system + ../../common/vm + ]; + + # Host metadata (adjust as needed) + homelab.host = { + tier = "test"; # Start in test tier, move to prod after validation + }; + + nixpkgs.config.allowUnfree = true; + boot.loader.grub.enable = true; + boot.loader.grub.device = "/dev/vda"; + + networking.hostName = "testvm02"; + networking.domain = "home.2rjus.net"; + networking.useNetworkd = true; + networking.useDHCP = false; + services.resolved.enable = true; + networking.nameservers = [ + "10.69.13.5" + "10.69.13.6" + ]; + + systemd.network.enable = true; + systemd.network.networks."ens18" = { + matchConfig.Name = "ens18"; + address = [ + "10.69.13.21/24" + ]; + routes = [ + { Gateway = "10.69.13.1"; } + ]; + linkConfig.RequiredForOnline = "routable"; + }; + time.timeZone = "Europe/Oslo"; + + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + nix.settings.tarball-ttl = 0; + environment.systemPackages = with pkgs; [ + vim + wget + git + ]; + + # Open ports in the firewall. + # networking.firewall.allowedTCPPorts = [ ... ]; + # networking.firewall.allowedUDPPorts = [ ... ]; + # Or disable the firewall altogether. + networking.firewall.enable = false; + + system.stateVersion = "25.11"; # Did you read the comment? +} \ No newline at end of file diff --git a/hosts/testvm02/default.nix b/hosts/testvm02/default.nix new file mode 100644 index 0000000..57ed4b4 --- /dev/null +++ b/hosts/testvm02/default.nix @@ -0,0 +1,5 @@ +{ ... }: { + imports = [ + ./configuration.nix + ]; +} \ No newline at end of file diff --git a/hosts/testvm03/configuration.nix b/hosts/testvm03/configuration.nix new file mode 100644 index 0000000..9ac7f5d --- /dev/null +++ b/hosts/testvm03/configuration.nix @@ -0,0 +1,66 @@ +{ + config, + lib, + pkgs, + ... +}: + +{ + imports = [ + ../template2/hardware-configuration.nix + + ../../system + ../../common/vm + ]; + + # Host metadata (adjust as needed) + homelab.host = { + tier = "test"; # Start in test tier, move to prod after validation + }; + + nixpkgs.config.allowUnfree = true; + boot.loader.grub.enable = true; + boot.loader.grub.device = "/dev/vda"; + + networking.hostName = "testvm03"; + networking.domain = "home.2rjus.net"; + networking.useNetworkd = true; + networking.useDHCP = false; + services.resolved.enable = true; + networking.nameservers = [ + "10.69.13.5" + "10.69.13.6" + ]; + + systemd.network.enable = true; + systemd.network.networks."ens18" = { + matchConfig.Name = "ens18"; + address = [ + "10.69.13.22/24" + ]; + routes = [ + { Gateway = "10.69.13.1"; } + ]; + linkConfig.RequiredForOnline = "routable"; + }; + time.timeZone = "Europe/Oslo"; + + nix.settings.experimental-features = [ + "nix-command" + "flakes" + ]; + nix.settings.tarball-ttl = 0; + environment.systemPackages = with pkgs; [ + vim + wget + git + ]; + + # Open ports in the firewall. + # networking.firewall.allowedTCPPorts = [ ... ]; + # networking.firewall.allowedUDPPorts = [ ... ]; + # Or disable the firewall altogether. + networking.firewall.enable = false; + + system.stateVersion = "25.11"; # Did you read the comment? +} \ No newline at end of file diff --git a/hosts/testvm03/default.nix b/hosts/testvm03/default.nix new file mode 100644 index 0000000..57ed4b4 --- /dev/null +++ b/hosts/testvm03/default.nix @@ -0,0 +1,5 @@ +{ ... }: { + imports = [ + ./configuration.nix + ]; +} \ No newline at end of file diff --git a/terraform/vault/hosts-generated.tf b/terraform/vault/hosts-generated.tf index 7b3049b..630a7bb 100644 --- a/terraform/vault/hosts-generated.tf +++ b/terraform/vault/hosts-generated.tf @@ -5,6 +5,22 @@ # Each host gets access to its own secrets under hosts//* locals { generated_host_policies = { + "testvm01" = { + paths = [ + "secret/data/hosts/testvm01/*", + ] + } + "testvm02" = { + paths = [ + "secret/data/hosts/testvm02/*", + ] + } + "testvm03" = { + paths = [ + "secret/data/hosts/testvm03/*", + ] + } + } # Placeholder secrets - user should add actual secrets manually or via tofu diff --git a/terraform/vms.tf b/terraform/vms.tf index b7c6c5d..35d66b2 100644 --- a/terraform/vms.tf +++ b/terraform/vms.tf @@ -38,6 +38,30 @@ locals { disk_size = "20G" flake_branch = "vault-setup" # Bootstrap from this branch instead of master } + "testvm01" = { + ip = "10.69.13.20/24" + cpu_cores = 2 + memory = 2048 + disk_size = "20G" + flake_branch = "deploy-test-hosts" + vault_wrapped_token = "s.3XeDNvlhS5wqjjeOw1w7q4Cp" + } + "testvm02" = { + ip = "10.69.13.21/24" + cpu_cores = 2 + memory = 2048 + disk_size = "20G" + flake_branch = "deploy-test-hosts" + vault_wrapped_token = "s.JDFHGWsWUBU9vKAFZK3XPu3X" + } + "testvm03" = { + ip = "10.69.13.22/24" + cpu_cores = 2 + memory = 2048 + disk_size = "20G" + flake_branch = "deploy-test-hosts" + vault_wrapped_token = "s.Msj0c4viIrvxprxRZZqw3jj4" + } } # Compute VM configurations with defaults applied From 370cf2b03a9750f65eb7266a6f79cd4eb2e82773 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= Date: Sat, 7 Feb 2026 13:50:49 +0100 Subject: [PATCH 2/4] hosts: enable vault and deploy listener on test VMs - Add vault.enable = true to testvm01, testvm02, testvm03 - Add homelab.deploy.enable = true for remote deployment via NATS - Update create-host template to include these by default Co-Authored-By: Claude Opus 4.5 --- hosts/testvm01/configuration.nix | 6 ++++++ hosts/testvm02/configuration.nix | 6 ++++++ hosts/testvm03/configuration.nix | 6 ++++++ scripts/create-host/templates/configuration.nix.j2 | 6 ++++++ terraform/vms.tf | 6 +++--- 5 files changed, 27 insertions(+), 3 deletions(-) diff --git a/hosts/testvm01/configuration.nix b/hosts/testvm01/configuration.nix index 77b71fe..c493c76 100644 --- a/hosts/testvm01/configuration.nix +++ b/hosts/testvm01/configuration.nix @@ -18,6 +18,12 @@ tier = "test"; # Start in test tier, move to prod after validation }; + # Enable Vault integration + vault.enable = true; + + # Enable remote deployment via NATS + homelab.deploy.enable = true; + nixpkgs.config.allowUnfree = true; boot.loader.grub.enable = true; boot.loader.grub.device = "/dev/vda"; diff --git a/hosts/testvm02/configuration.nix b/hosts/testvm02/configuration.nix index dd3d718..323b818 100644 --- a/hosts/testvm02/configuration.nix +++ b/hosts/testvm02/configuration.nix @@ -18,6 +18,12 @@ tier = "test"; # Start in test tier, move to prod after validation }; + # Enable Vault integration + vault.enable = true; + + # Enable remote deployment via NATS + homelab.deploy.enable = true; + nixpkgs.config.allowUnfree = true; boot.loader.grub.enable = true; boot.loader.grub.device = "/dev/vda"; diff --git a/hosts/testvm03/configuration.nix b/hosts/testvm03/configuration.nix index 9ac7f5d..a3dd2f3 100644 --- a/hosts/testvm03/configuration.nix +++ b/hosts/testvm03/configuration.nix @@ -18,6 +18,12 @@ tier = "test"; # Start in test tier, move to prod after validation }; + # Enable Vault integration + vault.enable = true; + + # Enable remote deployment via NATS + homelab.deploy.enable = true; + nixpkgs.config.allowUnfree = true; boot.loader.grub.enable = true; boot.loader.grub.device = "/dev/vda"; diff --git a/scripts/create-host/templates/configuration.nix.j2 b/scripts/create-host/templates/configuration.nix.j2 index 909d319..9edb2c8 100644 --- a/scripts/create-host/templates/configuration.nix.j2 +++ b/scripts/create-host/templates/configuration.nix.j2 @@ -18,6 +18,12 @@ tier = "test"; # Start in test tier, move to prod after validation }; + # Enable Vault integration + vault.enable = true; + + # Enable remote deployment via NATS + homelab.deploy.enable = true; + nixpkgs.config.allowUnfree = true; boot.loader.grub.enable = true; boot.loader.grub.device = "/dev/vda"; diff --git a/terraform/vms.tf b/terraform/vms.tf index 35d66b2..265024a 100644 --- a/terraform/vms.tf +++ b/terraform/vms.tf @@ -44,7 +44,7 @@ locals { memory = 2048 disk_size = "20G" flake_branch = "deploy-test-hosts" - vault_wrapped_token = "s.3XeDNvlhS5wqjjeOw1w7q4Cp" + vault_wrapped_token = "s.YRGRpAZVVtSYEa3wOYOqFmjt" } "testvm02" = { ip = "10.69.13.21/24" @@ -52,7 +52,7 @@ locals { memory = 2048 disk_size = "20G" flake_branch = "deploy-test-hosts" - vault_wrapped_token = "s.JDFHGWsWUBU9vKAFZK3XPu3X" + vault_wrapped_token = "s.tvs8yhJOkLjBs548STs6DBw7" } "testvm03" = { ip = "10.69.13.22/24" @@ -60,7 +60,7 @@ locals { memory = 2048 disk_size = "20G" flake_branch = "deploy-test-hosts" - vault_wrapped_token = "s.Msj0c4viIrvxprxRZZqw3jj4" + vault_wrapped_token = "s.sQ80FZGeG3z6jgrsuh74IopC" } } From 38348c5980d1e8c5e2617a453bc99f46dfde1b0f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= Date: Sat, 7 Feb 2026 14:05:42 +0100 Subject: [PATCH 3/4] vault: add homelab-deploy policy to generated hosts The homelab-deploy listener requires access to shared/homelab-deploy/* secrets. Update hosts-generated.tf and the generator script to include this policy automatically. Co-Authored-By: Claude Opus 4.5 --- scripts/create-host/generators.py | 2 +- terraform/vault/hosts-generated.tf | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/create-host/generators.py b/scripts/create-host/generators.py index bd1f1da..a202a39 100644 --- a/scripts/create-host/generators.py +++ b/scripts/create-host/generators.py @@ -144,7 +144,7 @@ resource "vault_approle_auth_backend_role" "generated_hosts" { backend = vault_auth_backend.approle.path role_name = each.key - token_policies = ["host-\${each.key}"] + token_policies = ["host-\${each.key}", "homelab-deploy"] secret_id_ttl = 0 # Never expire (wrapped tokens provide time limit) token_ttl = 3600 token_max_ttl = 3600 diff --git a/terraform/vault/hosts-generated.tf b/terraform/vault/hosts-generated.tf index 630a7bb..72def73 100644 --- a/terraform/vault/hosts-generated.tf +++ b/terraform/vault/hosts-generated.tf @@ -50,7 +50,7 @@ resource "vault_approle_auth_backend_role" "generated_hosts" { backend = vault_auth_backend.approle.path role_name = each.key - token_policies = ["host-${each.key}"] + token_policies = ["host-${each.key}", "homelab-deploy"] secret_id_ttl = 0 # Never expire (wrapped tokens provide time limit) token_ttl = 3600 token_max_ttl = 3600 From b046a1b862ad9628ee69ac0ae59428e6602e9bcd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Torjus=20H=C3=A5kestad?= Date: Sat, 7 Feb 2026 14:09:30 +0100 Subject: [PATCH 4/4] terraform: remove flake_branch from test VMs VMs are now bootstrapped and running. Remove temporary flake_branch and vault_wrapped_token settings so they use master going forward. Co-Authored-By: Claude Opus 4.5 --- terraform/vms.tf | 30 ++++++++++++------------------ 1 file changed, 12 insertions(+), 18 deletions(-) diff --git a/terraform/vms.tf b/terraform/vms.tf index 265024a..5d33a73 100644 --- a/terraform/vms.tf +++ b/terraform/vms.tf @@ -39,28 +39,22 @@ locals { flake_branch = "vault-setup" # Bootstrap from this branch instead of master } "testvm01" = { - ip = "10.69.13.20/24" - cpu_cores = 2 - memory = 2048 - disk_size = "20G" - flake_branch = "deploy-test-hosts" - vault_wrapped_token = "s.YRGRpAZVVtSYEa3wOYOqFmjt" + ip = "10.69.13.20/24" + cpu_cores = 2 + memory = 2048 + disk_size = "20G" } "testvm02" = { - ip = "10.69.13.21/24" - cpu_cores = 2 - memory = 2048 - disk_size = "20G" - flake_branch = "deploy-test-hosts" - vault_wrapped_token = "s.tvs8yhJOkLjBs548STs6DBw7" + ip = "10.69.13.21/24" + cpu_cores = 2 + memory = 2048 + disk_size = "20G" } "testvm03" = { - ip = "10.69.13.22/24" - cpu_cores = 2 - memory = 2048 - disk_size = "20G" - flake_branch = "deploy-test-hosts" - vault_wrapped_token = "s.sQ80FZGeG3z6jgrsuh74IopC" + ip = "10.69.13.22/24" + cpu_cores = 2 + memory = 2048 + disk_size = "20G" } }