diff --git a/infra/_modules/nixos/.sops.yaml b/infra/_modules/nixos/.sops.yaml new file mode 100644 index 0000000..65ee661 --- /dev/null +++ b/infra/_modules/nixos/.sops.yaml @@ -0,0 +1,7 @@ +creation_rules: + # TODO auto manage age keys, currently have to: + # - run age-keygen + # - copy public key here + # - copy private key to ~/.config/sops/age/keys.txt + - age: >- + age15c5rpksj0u27sp667525zqh8dhtd70rwrlv7xq2hqhsfaempcdwqu3unel diff --git a/infra/_modules/nixos/configuration.nix b/infra/_modules/nixos/configuration.nix index da82bbe..35bb552 100644 --- a/infra/_modules/nixos/configuration.nix +++ b/infra/_modules/nixos/configuration.nix @@ -63,5 +63,15 @@ }; }; + sops = { + age = { + keyFile = "/var/lib/secrets/age"; + }; + defaultSopsFile = ./secrets.yaml; + secrets = { + k3s_token = {}; + }; + }; + system.stateVersion = "25.05"; } diff --git a/infra/_modules/nixos/decrypt-age-keys.sh b/infra/_modules/nixos/decrypt-age-keys.sh new file mode 100755 index 0000000..3906828 --- /dev/null +++ b/infra/_modules/nixos/decrypt-age-keys.sh @@ -0,0 +1,12 @@ +#!/usr/bin/env sh + +set -euo pipefail -x + +mkdir -p ./var/lib/secrets + +umask 0177 +sops \ + --extract '["age_key"]' \ + --decrypt "${SOPS_FILE}" \ + > ./var/lib/secrets/age +umask 0022 diff --git a/infra/_modules/nixos/flake.lock b/infra/_modules/nixos/flake.lock index 592d3b8..b587ecc 100644 --- a/infra/_modules/nixos/flake.lock +++ b/infra/_modules/nixos/flake.lock @@ -38,7 +38,28 @@ "root": { "inputs": { "disko": "disko", - "nixpkgs": "nixpkgs" + "nixpkgs": "nixpkgs", + "sops-nix": "sops-nix" + } + }, + "sops-nix": { + "inputs": { + "nixpkgs": [ + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1754988908, + "narHash": "sha256-t+voe2961vCgrzPFtZxha0/kmFSHFobzF00sT8p9h0U=", + "owner": "Mic92", + "repo": "sops-nix", + "rev": "3223c7a92724b5d804e9988c6b447a0d09017d48", + "type": "github" + }, + "original": { + "owner": "Mic92", + "repo": "sops-nix", + "type": "github" } } }, diff --git a/infra/_modules/nixos/flake.nix b/infra/_modules/nixos/flake.nix index 113c9f0..bc132b2 100644 --- a/infra/_modules/nixos/flake.nix +++ b/infra/_modules/nixos/flake.nix @@ -5,8 +5,12 @@ url = "github:nix-community/disko"; inputs.nixpkgs.follows = "nixpkgs"; }; + sops-nix = { + url = "github:Mic92/sops-nix"; + inputs.nixpkgs.follows = "nixpkgs"; + }; }; - outputs = { nixpkgs, disko, ... }: { + outputs = { nixpkgs, disko, sops-nix, ... }: { nixosConfigurations = let hosts = builtins.fromJSON (builtins.readFile ./hosts.json); @@ -24,6 +28,7 @@ system = "x86_64-linux"; modules = [ disko.nixosModules.disko + sops-nix.nixosModules.sops ./configuration.nix ./disks.nix ./profiles/k3s.nix @@ -37,12 +42,13 @@ system = "x86_64-linux"; modules = [ disko.nixosModules.disko + sops-nix.nixosModules.sops ./configuration.nix ./disks.nix ./profiles/k3s.nix { networking.hostName = "kube-2"; - services.k3s.serverAddr = hosts.kube-1.ipv6_address; + services.k3s.serverAddr = "https://[${hosts.kube-1.ipv6_address}]:6443"; } ]; }; @@ -50,12 +56,13 @@ system = "x86_64-linux"; modules = [ disko.nixosModules.disko + sops-nix.nixosModules.sops ./configuration.nix ./disks.nix ./profiles/k3s.nix { networking.hostName = "kube-3"; - services.k3s.serverAddr = hosts.kube-1.ipv6_address; + services.k3s.serverAddr = "https://[${hosts.kube-1.ipv6_address}]:6443"; } ]; }; diff --git a/infra/_modules/nixos/hosts.json b/infra/_modules/nixos/hosts.json index c2841b0..613ce06 100644 --- a/infra/_modules/nixos/hosts.json +++ b/infra/_modules/nixos/hosts.json @@ -1 +1 @@ -{"kube-1":{"ipv6_address":"2402:800:63e2:5af5:68d0:b3c2:b44:71cc"},"kube-2":{"ipv6_address":"2402:800:63e2:5af5:19a6:50a1:765a:e396"},"kube-3":{"ipv6_address":"2402:800:63e2:5af5:3646:e232:b1cd:c96a"}} \ No newline at end of file +{"kube-1":{"ipv6_address":"2402:800:63e2:5af5:1b0:f4a:e854:5355"},"kube-2":{"ipv6_address":"2402:800:63e2:5af5:cb46:f8e4:131b:93c5"},"kube-3":{"ipv6_address":"2402:800:63e2:5af5:1ced:4595:b4bf:3634"}} \ No newline at end of file diff --git a/infra/_modules/nixos/main.tf b/infra/_modules/nixos/main.tf index bc85040..d23e38e 100644 --- a/infra/_modules/nixos/main.tf +++ b/infra/_modules/nixos/main.tf @@ -17,4 +17,8 @@ module "nixos" { nixos_partitioner_attr = "${var.flake}#nixosConfigurations.${each.key}.config.system.build.diskoScript" target_host = each.value.ipv6_address instance_id = each.key + extra_files_script = "${path.module}/decrypt-age-keys.sh" + extra_environment = { + SOPS_FILE = var.sops_file + } } diff --git a/infra/_modules/nixos/profiles/installer.nix b/infra/_modules/nixos/profiles/installer.nix new file mode 100644 index 0000000..d460a32 --- /dev/null +++ b/infra/_modules/nixos/profiles/installer.nix @@ -0,0 +1,24 @@ +{ modulesPath, ... }: + +{ + imports = [ + (modulesPath + "/installer/cd-dvd/installation-cd-minimal.nix") + ]; + + services = { + openssh = { + enable = true; + }; + qemuGuest = { + enable = true; + }; + }; + + users.users = { + root = { + openssh.authorizedKeys.keys = [ + "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIN5ue4np7cF34f6dwqH1262fPjkowHQ8irfjVC156PCG" + ]; + }; + }; +} diff --git a/infra/_modules/nixos/profiles/k3s.nix b/infra/_modules/nixos/profiles/k3s.nix index 0c49e0b..f33e935 100644 --- a/infra/_modules/nixos/profiles/k3s.nix +++ b/infra/_modules/nixos/profiles/k3s.nix @@ -1,4 +1,4 @@ -{ pkgs, ... }: +{ config, ... }: { networking = { @@ -18,6 +18,7 @@ k3s = { enable = true; role = "server"; + tokenFile = config.sops.secrets.k3s_token.path; extraFlags = toString [ "--disable-helm-controller" "--disable-network-policy" diff --git a/infra/_modules/nixos/secrets.yaml b/infra/_modules/nixos/secrets.yaml new file mode 100644 index 0000000..de98ed6 --- /dev/null +++ b/infra/_modules/nixos/secrets.yaml @@ -0,0 +1,16 @@ +k3s_token: ENC[AES256_GCM,data:Gkpz+zgUN4qHacbB52LOoVB4cm1OM7MrsEmKbqRvaukRnh4ctvBDd+9C+6fnOQsTNw==,iv:VD/YnqtVnu7PCGoGFCzzt8WrBAa6bdluNrRDO/YP2RA=,tag:+wu5MiCbMELVaIrEcK0KIQ==,type:str] +sops: + age: + - recipient: age15c5rpksj0u27sp667525zqh8dhtd70rwrlv7xq2hqhsfaempcdwqu3unel + enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArSUFnczNDTzl1Mm8wVWdN + NnZCN2hJa3JMOW42Mno0UGZod3hYMjhvWm5nCkpqRklwRSt6Sm9NWFA3aFEvYncv + QjFqRng3TVhVRERDUkZwNTV2YThocTgKLS0tIGoyc0oxbU5FenhHVVJZTXpkSlhC + eFpDWWg4Z2dWc3JvV2l0Q2Evd25mSTAKfZn8kohXG6O7y54dPpSXhRj1E75XGZDj + CRxObtI2s+ddACiHzNVDuDJkq5RForvOYwR/6nk6jEdIQt8pfnwiSA== + -----END AGE ENCRYPTED FILE----- + lastmodified: "2025-08-27T13:36:25Z" + mac: ENC[AES256_GCM,data:uEdpYAK1kygA3ZlM7ZfNE11RxaPDCPthHf3orHZgeBSfCsoBERtvfh9eqc6SdAFSkd8gXRViy38Yt8q0Y/9aRvfz1/sBX2wnUkB8VDYzlZDUr1Aj4BYGetXlgfHPzuD131NtsbcXmU6X7K+xAT6vFLqrnB5uvhPG9w6ZNYxSEOw=,iv:f0kGlZ0dLkOoJg4A2AWnNAnZPBydghI6gyZUR7jmYh4=,tag:KU3J8cGZjrk/xaUokqmuXg==,type:str] + unencrypted_suffix: _unencrypted + version: 3.10.2 diff --git a/infra/_modules/nixos/variables.tf b/infra/_modules/nixos/variables.tf index 76bae5a..935147b 100644 --- a/infra/_modules/nixos/variables.tf +++ b/infra/_modules/nixos/variables.tf @@ -7,3 +7,7 @@ variable "hosts" { ipv6_address = string })) } + +variable "sops_file" { + type = string +} diff --git a/infra/_modules/proxmox-vm/variables.tf b/infra/_modules/proxmox-vm/variables.tf index a64840a..07e0f18 100644 --- a/infra/_modules/proxmox-vm/variables.tf +++ b/infra/_modules/proxmox-vm/variables.tf @@ -17,7 +17,7 @@ variable "cdrom" { }) default = { - file = "nixos-24.11.20250123.035f8c0-x86_64-linux.iso" + file = "nixos-minimal-25.05.808723.b1b329146965-x86_64-linux.iso" } } diff --git a/infra/production/nixos/terragrunt.hcl b/infra/production/nixos/terragrunt.hcl index c36e846..7257f3a 100644 --- a/infra/production/nixos/terragrunt.hcl +++ b/infra/production/nixos/terragrunt.hcl @@ -12,6 +12,7 @@ dependency "proxmox" { } inputs = { - flake = "${find_in_parent_folders("_modules")}//nixos" - hosts = dependency.proxmox.outputs.hosts + flake = "${find_in_parent_folders("_modules")}//nixos" + hosts = dependency.proxmox.outputs.hosts + sops_file = find_in_parent_folders("secrets.yaml") } diff --git a/infra/production/proxmox/compute/terragrunt.hcl b/infra/production/proxmox/compute/terragrunt.hcl index a628ee8..2f76edb 100644 --- a/infra/production/proxmox/compute/terragrunt.hcl +++ b/infra/production/proxmox/compute/terragrunt.hcl @@ -9,20 +9,8 @@ terraform { inputs = { hosts = { - "kube-1" = { - cpu = 2 - memory = 4 - disk = 128 - } - "kube-2" = { - cpu = 2 - memory = 4 - disk = 128 - } - "kube-3" = { - cpu = 8 - memory = 16 - disk = 128 - } + "kube-1" = { cpu = 4, memory = 12, disk = 128 } + "kube-2" = { cpu = 4, memory = 12, disk = 128 } + "kube-3" = { cpu = 4, memory = 12, disk = 128 } } } diff --git a/infra/production/secrets.yaml b/infra/production/secrets.yaml index 858d4ae..df9a95f 100644 --- a/infra/production/secrets.yaml +++ b/infra/production/secrets.yaml @@ -1,3 +1,4 @@ +age_key: ENC[AES256_GCM,data:Q5n2nohubYGddLVghlUMUyaL5rgc8sy7fygzkw1Z+7Fk8HSl6nn7IC46OGx3nSu6ypStg1anvjOkTTZWvoL/ETL+pGeRgETdf7Y=,iv:AdSB/+HwVWFD0GQ5kNoybXvGVBLla9CmQ8pAOkf6tow=,tag:ZILB6vg8dXHjptDLtkqTAg==,type:str] cloudflare_tfstate_api_token: ENC[AES256_GCM,data:ZNK2qzaiXV93txbV73sSnvxicazxY8uzxf/0yLe/NwQYZKc+t2AVkA==,iv:6gNRl8Kr2xYfwKDVefKP+Fe7/NOf1zKftnBqzoWo5N0=,tag:pjCsHKYL4wbyGGZ63ERvDQ==,type:str] cloudflare_tfstate_access_key: ENC[AES256_GCM,data:1N7/YeqYBLaPD0u9EMzQA9nZDpAAk/cb70pF+EwlPMM=,iv:BJ4x220lnXcle3MiDnlj3mY1Wl56z0Fc1bgyA7p294o=,tag:5HcspXjzggy2aQnnR4q71A==,type:str] cloudflare_tfstate_secret_key: ENC[AES256_GCM,data:/EEAKxDwtEgMdDNPVXJ5pu8Xzx20ZZwRqMR+90M8KkQwbBRxk67IHP4LeY7Sm6BEQOfjim+tvAdjABfSMpzl4w==,iv:Kj2RP5EDGPkJp5VN7qE6tmCao/QBSxHMRk9VC0up7D4=,tag:fM9oYGx9NpVepSJctp2Y8w==,type:str] @@ -23,7 +24,7 @@ sops: bzdTeVZWYVIwM1VyUm5UM0pQZW5KYlUKWw7Fq17anbkfY6U3HCr00OKEfffRL/TM zvtvDaWLg2ZilP7kWM7YbqyTi4XqjLXKldOblwIcF7qA5E/OfbbzXw== -----END AGE ENCRYPTED FILE----- - lastmodified: "2025-08-01T09:36:57Z" - mac: ENC[AES256_GCM,data:kjxsG3hl90Rsu2EQNPwQs+YX5rTaPGV58drChHhwWWQKjxuSxogRBZgCZ7E0+x/8hiU45LAU9cHYASisqS5BQ9OZlHRf6gENWuyEvHA0NXYezO/8Qa+ki0R2/SlrtUNuAk4/v4DUdUydxijTWGL/sF21QwmD4y3e5jrW6+g7inY=,iv:IKxJVRPg9WQdVos6IILnejjKGSSaz/WICahmE2R/OtA=,tag:O56XtwjHQ9Tu4MprEx/LPQ==,type:str] + lastmodified: "2025-08-27T13:36:29Z" + mac: ENC[AES256_GCM,data:BlvMknGkzj83c3WeKgAV+y07xgxiFFfTCB7fM8+5XiYenvv1zSLXrHwxTMk3vWgvlhE5rWu9z/dAfoV10niYuJNTub6k9sk9Bty/q927e2kfwO1xw2N6UA1UROYoJfsFWsFJOiH9E6qMRMP4RwshVNrmpY7ixixWiRgCPTurNCY=,iv:lZ0sVPNhW78dOKaRS87EJG0Zmm2vVkfjS2tjnzTz8qs=,tag:ikaKjIvvLnlolBIdaD0+qQ==,type:str] unencrypted_suffix: _unencrypted version: 3.10.2