Move forge tailnet secrets to agenix
This commit is contained in:
parent
8aebf56d6d
commit
20964e8ed7
9 changed files with 135 additions and 7 deletions
|
|
@ -157,6 +157,13 @@ done
|
||||||
echo "== intake =="
|
echo "== intake =="
|
||||||
ls -l /var/lib/burrow/intake || true
|
ls -l /var/lib/burrow/intake || true
|
||||||
|
|
||||||
|
if [[ "${EXPECT_TAILNET}" == "1" ]]; then
|
||||||
|
echo "== agenix =="
|
||||||
|
ls -l /run/agenix || true
|
||||||
|
test -s /run/agenix/burrowAuthentikEnv
|
||||||
|
test -s /run/agenix/burrowHeadscaleOidcClientSecret
|
||||||
|
fi
|
||||||
|
|
||||||
if command -v curl >/dev/null 2>&1; then
|
if command -v curl >/dev/null 2>&1; then
|
||||||
echo "== http-local =="
|
echo "== http-local =="
|
||||||
curl -fsS -o /dev/null -w 'forgejo_login %{http_code}\n' http://127.0.0.1:3000/user/login
|
curl -fsS -o /dev/null -w 'forgejo_login %{http_code}\n' http://127.0.0.1:3000/user/login
|
||||||
|
|
|
||||||
84
flake.lock
generated
84
flake.lock
generated
|
|
@ -1,5 +1,50 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
|
"agenix": {
|
||||||
|
"inputs": {
|
||||||
|
"darwin": "darwin",
|
||||||
|
"home-manager": "home-manager",
|
||||||
|
"nixpkgs": [
|
||||||
|
"nixpkgs"
|
||||||
|
],
|
||||||
|
"systems": "systems"
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1770165109,
|
||||||
|
"narHash": "sha256-9VnK6Oqai65puVJ4WYtCTvlJeXxMzAp/69HhQuTdl/I=",
|
||||||
|
"owner": "ryantm",
|
||||||
|
"repo": "agenix",
|
||||||
|
"rev": "b027ee29d959fda4b60b57566d64c98a202e0feb",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "ryantm",
|
||||||
|
"repo": "agenix",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"darwin": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"agenix",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1744478979,
|
||||||
|
"narHash": "sha256-dyN+teG9G82G+m+PX/aSAagkC+vUv0SgUw3XkPhQodQ=",
|
||||||
|
"owner": "lnl7",
|
||||||
|
"repo": "nix-darwin",
|
||||||
|
"rev": "43975d782b418ebf4969e9ccba82466728c2851b",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "lnl7",
|
||||||
|
"ref": "master",
|
||||||
|
"repo": "nix-darwin",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"disko": {
|
"disko": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": [
|
"nixpkgs": [
|
||||||
|
|
@ -19,7 +64,7 @@
|
||||||
},
|
},
|
||||||
"flake-utils": {
|
"flake-utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems"
|
"systems": "systems_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1731533236,
|
"lastModified": 1731533236,
|
||||||
|
|
@ -45,6 +90,27 @@
|
||||||
"url": "https://codeload.github.com/apricote/hcloud-upload-image/tar.gz/v1.3.0"
|
"url": "https://codeload.github.com/apricote/hcloud-upload-image/tar.gz/v1.3.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"home-manager": {
|
||||||
|
"inputs": {
|
||||||
|
"nixpkgs": [
|
||||||
|
"agenix",
|
||||||
|
"nixpkgs"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1745494811,
|
||||||
|
"narHash": "sha256-YZCh2o9Ua1n9uCvrvi5pRxtuVNml8X2a03qIFfRKpFs=",
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"rev": "abfad3d2958c9e6300a883bd443512c55dfeb1be",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-community",
|
||||||
|
"repo": "home-manager",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
|
},
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1773389992,
|
"lastModified": 1773389992,
|
||||||
|
|
@ -59,6 +125,7 @@
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
|
"agenix": "agenix",
|
||||||
"disko": "disko",
|
"disko": "disko",
|
||||||
"flake-utils": "flake-utils",
|
"flake-utils": "flake-utils",
|
||||||
"hcloud-upload-image-src": "hcloud-upload-image-src",
|
"hcloud-upload-image-src": "hcloud-upload-image-src",
|
||||||
|
|
@ -79,6 +146,21 @@
|
||||||
"repo": "default",
|
"repo": "default",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"systems_2": {
|
||||||
|
"locked": {
|
||||||
|
"lastModified": 1681028828,
|
||||||
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
|
"type": "github"
|
||||||
|
},
|
||||||
|
"original": {
|
||||||
|
"owner": "nix-systems",
|
||||||
|
"repo": "default",
|
||||||
|
"type": "github"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,10 @@
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "tarball+https://codeload.github.com/NixOS/nixpkgs/tar.gz/nixos-unstable";
|
nixpkgs.url = "tarball+https://codeload.github.com/NixOS/nixpkgs/tar.gz/nixos-unstable";
|
||||||
flake-utils.url = "tarball+https://codeload.github.com/numtide/flake-utils/tar.gz/main";
|
flake-utils.url = "tarball+https://codeload.github.com/numtide/flake-utils/tar.gz/main";
|
||||||
|
agenix = {
|
||||||
|
url = "github:ryantm/agenix";
|
||||||
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
};
|
||||||
disko = {
|
disko = {
|
||||||
url = "tarball+https://codeload.github.com/nix-community/disko/tar.gz/master";
|
url = "tarball+https://codeload.github.com/nix-community/disko/tar.gz/master";
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
inputs.nixpkgs.follows = "nixpkgs";
|
||||||
|
|
@ -14,7 +18,7 @@
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = { self, nixpkgs, flake-utils, disko, hcloud-upload-image-src }:
|
outputs = { self, nixpkgs, flake-utils, agenix, disko, hcloud-upload-image-src }:
|
||||||
let
|
let
|
||||||
supportedSystems = [
|
supportedSystems = [
|
||||||
"x86_64-linux"
|
"x86_64-linux"
|
||||||
|
|
@ -161,6 +165,7 @@
|
||||||
|
|
||||||
packages =
|
packages =
|
||||||
{
|
{
|
||||||
|
agenix = agenix.packages.${system}.agenix;
|
||||||
hcloud-upload-image = hcloudUploadImagePkg;
|
hcloud-upload-image = hcloudUploadImagePkg;
|
||||||
forgejo-nsc-dispatcher = forgejoNscDispatcher;
|
forgejo-nsc-dispatcher = forgejoNscDispatcher;
|
||||||
forgejo-nsc-autoscaler = forgejoNscAutoscaler;
|
forgejo-nsc-autoscaler = forgejoNscAutoscaler;
|
||||||
|
|
@ -180,6 +185,7 @@
|
||||||
inherit self;
|
inherit self;
|
||||||
};
|
};
|
||||||
modules = [
|
modules = [
|
||||||
|
agenix.nixosModules.default
|
||||||
disko.nixosModules.disko
|
disko.nixosModules.disko
|
||||||
./nixos/hosts/burrow-forge/default.nix
|
./nixos/hosts/burrow-forge/default.nix
|
||||||
];
|
];
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ Mail hosting is intentionally not part of this NixOS host in the current plan. B
|
||||||
- `modules/burrow-forgejo-nsc.nix`: Namespace-backed ephemeral Forgejo runner services
|
- `modules/burrow-forgejo-nsc.nix`: Namespace-backed ephemeral Forgejo runner services
|
||||||
- `modules/burrow-authentik.nix`: minimal Authentik IdP for Burrow control planes
|
- `modules/burrow-authentik.nix`: minimal Authentik IdP for Burrow control planes
|
||||||
- `modules/burrow-headscale.nix`: Headscale control plane rooted in Authentik OIDC
|
- `modules/burrow-headscale.nix`: Headscale control plane rooted in Authentik OIDC
|
||||||
|
- `../secrets.nix`: agenix recipient map for tracked Burrow forge secrets
|
||||||
- `hetzner-cloud-config.yaml`: desired Hetzner host shape
|
- `hetzner-cloud-config.yaml`: desired Hetzner host shape
|
||||||
- `keys/contact_at_burrow_net.pub`: initial operator SSH public key
|
- `keys/contact_at_burrow_net.pub`: initial operator SSH public key
|
||||||
- `keys/agent_at_burrow_net.pub`: automation SSH public key
|
- `keys/agent_at_burrow_net.pub`: automation SSH public key
|
||||||
|
|
@ -32,7 +33,7 @@ Mail hosting is intentionally not part of this NixOS host in the current plan. B
|
||||||
4. Let `burrow-forgejo-bootstrap.service` create or rotate the initial Forgejo admin account.
|
4. Let `burrow-forgejo-bootstrap.service` create or rotate the initial Forgejo admin account.
|
||||||
5. Let `burrow-forgejo-runner-bootstrap.service` register the self-hosted Forgejo runner and seed Git identity as `agent <agent@burrow.net>`.
|
5. Let `burrow-forgejo-runner-bootstrap.service` register the self-hosted Forgejo runner and seed Git identity as `agent <agent@burrow.net>`.
|
||||||
6. Run `Scripts/provision-forgejo-nsc.sh` locally, then `Scripts/sync-forgejo-nsc-config.sh` to place the Namespace dispatcher/autoscaler runtime inputs under `/var/lib/burrow/intake/`.
|
6. Run `Scripts/provision-forgejo-nsc.sh` locally, then `Scripts/sync-forgejo-nsc-config.sh` to place the Namespace dispatcher/autoscaler runtime inputs under `/var/lib/burrow/intake/`.
|
||||||
7. Ensure `/var/lib/burrow/intake/authentik.env` exists on the host, and let `services.burrow.headscale` generate `/var/lib/burrow/intake/authentik_headscale_client_secret.txt` on first boot if it is absent.
|
7. Ensure `/var/lib/agenix/agenix.key` exists on the host, encrypt `secrets/infra/authentik.env.age` and `secrets/infra/headscale-oidc-client-secret.age`, and let agenix materialize them under `/run/agenix/`.
|
||||||
8. Use `Scripts/cloudflare-upsert-a-record.sh` to point `git.burrow.net`, `burrow.net`, `auth.burrow.net`, `ts.burrow.net`, and `nsc-autoscaler.burrow.net` at the host with Cloudflare proxying disabled for ACME.
|
8. Use `Scripts/cloudflare-upsert-a-record.sh` to point `git.burrow.net`, `burrow.net`, `auth.burrow.net`, `ts.burrow.net`, and `nsc-autoscaler.burrow.net` at the host with Cloudflare proxying disabled for ACME.
|
||||||
9. Use `Scripts/forge-deploy.sh --allow-dirty` for subsequent remote `nixos-rebuild` runs from the live workspace.
|
9. Use `Scripts/forge-deploy.sh --allow-dirty` for subsequent remote `nixos-rebuild` runs from the live workspace.
|
||||||
10. Configure Forward Email custom S3 backups for `burrow.net` and `burrow.rs` out-of-band with `Tools/forwardemail-custom-s3.sh`.
|
10. Configure Forward Email custom S3 backups for `burrow.net` and `burrow.rs` out-of-band with `Tools/forwardemail-custom-s3.sh`.
|
||||||
|
|
@ -40,6 +41,7 @@ Mail hosting is intentionally not part of this NixOS host in the current plan. B
|
||||||
## Current Constraints
|
## Current Constraints
|
||||||
|
|
||||||
- `burrow-forge` is live on NixOS in `hel1` at `89.167.47.21`, and `Scripts/check-forge-host.sh --expect-nsc` passes locally against that host.
|
- `burrow-forge` is live on NixOS in `hel1` at `89.167.47.21`, and `Scripts/check-forge-host.sh --expect-nsc` passes locally against that host.
|
||||||
|
- Authentik and Headscale secrets now live in tracked agenix blobs under `secrets/infra/` and decrypt to `/run/agenix/` on the forge host.
|
||||||
- Public Burrow forge cutover completed on March 15, 2026:
|
- Public Burrow forge cutover completed on March 15, 2026:
|
||||||
- `burrow.net`, `git.burrow.net`, and `nsc-autoscaler.burrow.net` now publish public `A` records to `89.167.47.21`
|
- `burrow.net`, `git.burrow.net`, and `nsc-autoscaler.burrow.net` now publish public `A` records to `89.167.47.21`
|
||||||
- HTTP redirects to HTTPS on all three names
|
- HTTP redirects to HTTPS on all three names
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{ self, ... }:
|
{ config, self, ... }:
|
||||||
|
|
||||||
{
|
{
|
||||||
imports = [
|
imports = [
|
||||||
|
|
@ -20,6 +20,20 @@
|
||||||
"flakes"
|
"flakes"
|
||||||
];
|
];
|
||||||
|
|
||||||
|
age.identityPaths = [ "/var/lib/agenix/agenix.key" ];
|
||||||
|
age.secrets.burrowAuthentikEnv = {
|
||||||
|
file = ../../../secrets/infra/authentik.env.age;
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
mode = "0400";
|
||||||
|
};
|
||||||
|
age.secrets.burrowHeadscaleOidcClientSecret = {
|
||||||
|
file = ../../../secrets/infra/headscale-oidc-client-secret.age;
|
||||||
|
owner = "root";
|
||||||
|
group = "root";
|
||||||
|
mode = "0400";
|
||||||
|
};
|
||||||
|
|
||||||
networking.extraHosts = ''
|
networking.extraHosts = ''
|
||||||
127.0.0.1 burrow.net git.burrow.net auth.burrow.net ts.burrow.net nsc-autoscaler.burrow.net
|
127.0.0.1 burrow.net git.burrow.net auth.burrow.net ts.burrow.net nsc-autoscaler.burrow.net
|
||||||
::1 burrow.net git.burrow.net auth.burrow.net ts.burrow.net nsc-autoscaler.burrow.net
|
::1 burrow.net git.burrow.net auth.burrow.net ts.burrow.net nsc-autoscaler.burrow.net
|
||||||
|
|
@ -53,11 +67,12 @@
|
||||||
|
|
||||||
services.burrow.authentik = {
|
services.burrow.authentik = {
|
||||||
enable = true;
|
enable = true;
|
||||||
envFile = "/var/lib/burrow/intake/authentik.env";
|
envFile = config.age.secrets.burrowAuthentikEnv.path;
|
||||||
headscaleClientSecretFile = "/var/lib/burrow/intake/authentik_headscale_client_secret.txt";
|
headscaleClientSecretFile = config.age.secrets.burrowHeadscaleOidcClientSecret.path;
|
||||||
};
|
};
|
||||||
|
|
||||||
services.burrow.headscale = {
|
services.burrow.headscale = {
|
||||||
enable = true;
|
enable = true;
|
||||||
|
oidcClientSecretFile = config.age.secrets.burrowHeadscaleOidcClientSecret.path;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -191,7 +191,9 @@ in
|
||||||
set -euo pipefail
|
set -euo pipefail
|
||||||
|
|
||||||
list_users() {
|
list_users() {
|
||||||
${pkgs.headscale}/bin/headscale users list -o json
|
local users_json
|
||||||
|
users_json="$(${pkgs.headscale}/bin/headscale users list -o json)"
|
||||||
|
printf '%s\n' "$users_json" | ${pkgs.jq}/bin/jq -c 'if type == "array" then . else [] end'
|
||||||
}
|
}
|
||||||
|
|
||||||
ensure_user() {
|
ensure_user() {
|
||||||
|
|
|
||||||
14
secrets.nix
Normal file
14
secrets.nix
Normal file
|
|
@ -0,0 +1,14 @@
|
||||||
|
let
|
||||||
|
contact = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIO42guJ5QvNMw3k6YKWlQnjcTsc+X4XI9F2GBtl8aHOa";
|
||||||
|
agent = "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEN0+tRJy7Y2DW0uGYHb86N2t02WyU5lDNX6FaxBF/G8 agent@burrow.net";
|
||||||
|
burrowForgeHost = "age1quxf27gnun0xghlnxf3jrmqr3h3a3fzd8qxpallsaztd2u74pdfq9e7w9l";
|
||||||
|
burrowForgeRecipients = [
|
||||||
|
contact
|
||||||
|
agent
|
||||||
|
burrowForgeHost
|
||||||
|
];
|
||||||
|
in
|
||||||
|
{
|
||||||
|
"secrets/infra/authentik.env.age".publicKeys = burrowForgeRecipients;
|
||||||
|
"secrets/infra/headscale-oidc-client-secret.age".publicKeys = burrowForgeRecipients;
|
||||||
|
}
|
||||||
BIN
secrets/infra/authentik.env.age
Normal file
BIN
secrets/infra/authentik.env.age
Normal file
Binary file not shown.
BIN
secrets/infra/headscale-oidc-client-secret.age
Normal file
BIN
secrets/infra/headscale-oidc-client-secret.age
Normal file
Binary file not shown.
Loading…
Add table
Add a link
Reference in a new issue