From 0e5187d1947082b64856bf7935fd9177da2e612a Mon Sep 17 00:00:00 2001 From: "RingOfStorms (Joshua Bell)" Date: Sun, 4 Jan 2026 22:31:43 -0600 Subject: [PATCH 1/2] wip --- flakes/secrets-bao/nixos-module.nix | 94 +++++++++++++++++++++++++---- hosts/juni/flake.lock | 44 +++++++------- hosts/juni/impermanence.nix | 10 ++- 3 files changed, 114 insertions(+), 34 deletions(-) diff --git a/flakes/secrets-bao/nixos-module.nix b/flakes/secrets-bao/nixos-module.nix index 303bebad..4f87af58 100644 --- a/flakes/secrets-bao/nixos-module.nix +++ b/flakes/secrets-bao/nixos-module.nix @@ -46,14 +46,41 @@ let sig="$(${pkgs.coreutils}/bin/printf '%s' "$h64.$p64" | ${pkgs.openssl}/bin/openssl dgst -sha256 -sign "$pem_file" | b64url)" assertion="$h64.$p64.$sig" - ${pkgs.curl}/bin/curl -sS -X POST "${cfg.zitadelTokenEndpoint}" \ + resp="" + if ! resp="$(${pkgs.curl}/bin/curl -sS --fail-with-body -X POST "${cfg.zitadelTokenEndpoint}" \ -H 'content-type: application/x-www-form-urlencoded' \ --data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer' \ --data-urlencode "assertion=$assertion" \ --data-urlencode "scope=${cfg.zitadelScopes}" \ - | ${pkgs.jq}/bin/jq -r .access_token + )"; then + echo "Zitadel token endpoint returned error; response:" >&2 + echo "$resp" >&2 + exit 1 + fi + + token="$(${pkgs.jq}/bin/jq -r '.access_token // empty' <<<"$resp" 2>/dev/null || true)" + if [ -z "$token" ] || [ "$token" = "null" ]; then + echo "Zitadel token mint did not return access_token; response:" >&2 + echo "$resp" >&2 + exit 1 + fi + + # Quick sanity check: JWT should have 2 dots. + if ! ${pkgs.gnugrep}/bin/grep -q '\\.' <<<"$token"; then + echo "Zitadel access_token does not look like a JWT; response:" >&2 + echo "$resp" >&2 + exit 1 + fi + + ${pkgs.coreutils}/bin/printf '%s' "$token" ''; + zitadelHost = + let + noProto = lib.strings.removePrefix "https://" (lib.strings.removePrefix "http://" cfg.zitadelTokenEndpoint); + in + builtins.head (lib.strings.splitString "/" noProto); + mkAgentConfig = pkgs.writeText "vault-agent.hcl" '' vault { address = "${cfg.openBaoAddr}" @@ -231,8 +258,13 @@ in zitadel-mint-jwt = { description = "Mint Zitadel access token (JWT) for OpenBao"; wantedBy = [ "multi-user.target" ]; - after = [ "network-online.target" "nss-lookup.target" ]; - wants = [ "network-online.target" ]; + after = [ + "network-online.target" + "nss-lookup.target" + "NetworkManager-wait-online.service" + "systemd-resolved.service" + ]; + wants = [ "network-online.target" "NetworkManager-wait-online.service" ]; serviceConfig = { Type = "oneshot"; @@ -249,16 +281,50 @@ in exit 1 fi - # Wait for DNS + routing to be up. - for i in {1..60}; do - if ${pkgs.glibc}/bin/getent hosts sso.joshuabell.xyz >/dev/null; then + echo "zitadel-mint-jwt: starting (host=${zitadelHost})" >&2 + + jwt_is_valid() { + local token="$1" + local payload_b64 payload_json exp now + + payload_b64="$(${pkgs.coreutils}/bin/printf '%s' "$token" | ${pkgs.coreutils}/bin/cut -d. -f2)" + payload_b64="$(${pkgs.coreutils}/bin/printf '%s' "$payload_b64" | ${pkgs.gnused}/bin/sed -e 's/-/+/g' -e 's/_/\//g')" + + case $((${pkgs.coreutils}/bin/printf '%s' "$payload_b64" | ${pkgs.coreutils}/bin/wc -c)) in + *1) payload_b64="$payload_b64=" ;; + *2) payload_b64="$payload_b64==" ;; + *3) : ;; + *0) : ;; + esac + + payload_json="$(${pkgs.coreutils}/bin/printf '%s' "$payload_b64" | ${pkgs.coreutils}/bin/base64 -d 2>/dev/null || true)" + exp="$(${pkgs.jq}/bin/jq -r '.exp // empty' <<<"$payload_json" 2>/dev/null || true)" + if [ -z "$exp" ]; then + return 1 + fi + + now="$(${pkgs.coreutils}/bin/date +%s)" + if [ "$exp" -gt $(( now + 60 )) ]; then + return 0 + fi + return 1 + } + + if [ -s "${cfg.zitadelJwtPath}" ] && jwt_is_valid "$(cat "${cfg.zitadelJwtPath}")"; then + echo "zitadel-mint-jwt: existing token still valid; skipping" >&2 + exit 0 + fi + + # Wait for DNS to be usable. + for i in {1..120}; do + if ${pkgs.glibc}/bin/getent hosts ${zitadelHost} >/dev/null; then break fi sleep 1 done - if ! ${pkgs.glibc}/bin/getent hosts sso.joshuabell.xyz >/dev/null; then - echo "DNS still not ready for sso.joshuabell.xyz" >&2 + if ! ${pkgs.glibc}/bin/getent hosts ${zitadelHost} >/dev/null; then + echo "DNS still not ready for ${zitadelHost}" >&2 exit 1 fi @@ -276,7 +342,10 @@ in exit 1 fi - ${pkgs.coreutils}/bin/printf '%s' "$jwt" > "${cfg.zitadelJwtPath}" + tmp="$(${pkgs.coreutils}/bin/mktemp)" + trap '${pkgs.coreutils}/bin/rm -f "$tmp"' EXIT + ${pkgs.coreutils}/bin/printf '%s' "$jwt" > "$tmp" + ${pkgs.coreutils}/bin/mv -f "$tmp" "${cfg.zitadelJwtPath}" ''; }; }; @@ -296,7 +365,7 @@ in User = "root"; Group = "root"; Restart = "on-failure"; - RestartSec = "2s"; + RestartSec = "30s"; UMask = "0077"; ExecStart = "${pkgs.openbao}/bin/bao agent -config=${mkAgentConfig}"; @@ -310,6 +379,8 @@ in description = "Wait for OpenBao secret ${name}"; after = [ "vault-agent.service" ]; requires = [ "vault-agent.service" ]; + startLimitIntervalSec = 300; + startLimitBurst = 3; serviceConfig = { Type = "oneshot"; @@ -346,3 +417,4 @@ in ) cfg.secrets; }; } + diff --git a/hosts/juni/flake.lock b/hosts/juni/flake.lock index 0f4d6da0..13c2a4f9 100644 --- a/hosts/juni/flake.lock +++ b/hosts/juni/flake.lock @@ -6,11 +6,11 @@ }, "locked": { "dir": "flakes/beszel", - "lastModified": 1767293741, - "narHash": "sha256-mqcZB2uthea2TMcFmEgfPYGDC+O2px5hc/XPrlqsYMs=", + "lastModified": 1767294731, + "narHash": "sha256-hwTTYLO7nfPA98w3r6zXP2zj66yWBjHAf90gWGcX4Yw=", "ref": "refs/heads/master", - "rev": "8fff3be0425341a048167db5385d9639f6355133", - "revCount": 1031, + "rev": "d923e49c193ef38127ca6680013eec31c55c8809", + "revCount": 1032, "type": "git", "url": "https://git.joshuabell.xyz/ringofstorms/dotfiles" }, @@ -39,11 +39,11 @@ "common": { "locked": { "dir": "flakes/common", - "lastModified": 1767293741, - "narHash": "sha256-mqcZB2uthea2TMcFmEgfPYGDC+O2px5hc/XPrlqsYMs=", + "lastModified": 1767294731, + "narHash": "sha256-hwTTYLO7nfPA98w3r6zXP2zj66yWBjHAf90gWGcX4Yw=", "ref": "refs/heads/master", - "rev": "8fff3be0425341a048167db5385d9639f6355133", - "revCount": 1031, + "rev": "d923e49c193ef38127ca6680013eec31c55c8809", + "revCount": 1032, "type": "git", "url": "https://git.joshuabell.xyz/ringofstorms/dotfiles" }, @@ -59,11 +59,11 @@ }, "locked": { "dir": "flakes/de_plasma", - "lastModified": 1767293741, - "narHash": "sha256-mqcZB2uthea2TMcFmEgfPYGDC+O2px5hc/XPrlqsYMs=", + "lastModified": 1767294731, + "narHash": "sha256-hwTTYLO7nfPA98w3r6zXP2zj66yWBjHAf90gWGcX4Yw=", "ref": "refs/heads/master", - "rev": "8fff3be0425341a048167db5385d9639f6355133", - "revCount": 1031, + "rev": "d923e49c193ef38127ca6680013eec31c55c8809", + "revCount": 1032, "type": "git", "url": "https://git.joshuabell.xyz/ringofstorms/dotfiles" }, @@ -79,11 +79,11 @@ }, "locked": { "dir": "flakes/flatpaks", - "lastModified": 1767293741, - "narHash": "sha256-mqcZB2uthea2TMcFmEgfPYGDC+O2px5hc/XPrlqsYMs=", + "lastModified": 1767294731, + "narHash": "sha256-hwTTYLO7nfPA98w3r6zXP2zj66yWBjHAf90gWGcX4Yw=", "ref": "refs/heads/master", - "rev": "8fff3be0425341a048167db5385d9639f6355133", - "revCount": 1031, + "rev": "d923e49c193ef38127ca6680013eec31c55c8809", + "revCount": 1032, "type": "git", "url": "https://git.joshuabell.xyz/ringofstorms/dotfiles" }, @@ -1147,11 +1147,11 @@ }, "locked": { "dir": "flakes/opencode", - "lastModified": 1767293741, - "narHash": "sha256-mqcZB2uthea2TMcFmEgfPYGDC+O2px5hc/XPrlqsYMs=", + "lastModified": 1767294731, + "narHash": "sha256-hwTTYLO7nfPA98w3r6zXP2zj66yWBjHAf90gWGcX4Yw=", "ref": "refs/heads/master", - "rev": "8fff3be0425341a048167db5385d9639f6355133", - "revCount": 1031, + "rev": "d923e49c193ef38127ca6680013eec31c55c8809", + "revCount": 1032, "type": "git", "url": "https://git.joshuabell.xyz/ringofstorms/dotfiles" }, @@ -1310,8 +1310,8 @@ }, "secrets-bao": { "locked": { - "lastModified": 1767294512, - "narHash": "sha256-VJsOr6MRAskbLVRHtLplIHBvi6K45yj0H2TSP0V2SKI=", + "lastModified": 1767294735, + "narHash": "sha256-AF5iJYVdgmXuNBblVymhS8jAniZerX/CyfBbcM0Hh5g=", "path": "/home/josh/.config/nixos-config/flakes/secrets-bao", "type": "path" }, diff --git a/hosts/juni/impermanence.nix b/hosts/juni/impermanence.nix index 23b2b22d..9564267b 100644 --- a/hosts/juni/impermanence.nix +++ b/hosts/juni/impermanence.nix @@ -12,7 +12,6 @@ "/etc/nixos" "/etc/ssh" - "/etc/shadow" # keep passwords "/etc/NetworkManager/system-connections" "/var/lib/bluetooth" @@ -21,7 +20,16 @@ "/var/lib/fail2ban" ]; files = [ + "/machine-key.json" "/etc/machine-id" + "/etc/resolv.conf" # TODO describe + "/etc/shadow" # keep passwords + "/etc/group" + "/etc/passwd" + "/etc/sudoers" + "/etc/localtime" + "/etc/timezone" + "/etc/adjtime" ]; users."${primaryUser}" = { directories = [ From 0c47bfedd555432d3ff8de74ecea9da255b52633 Mon Sep 17 00:00:00 2001 From: "RingOfStorms (Joshua Bell)" Date: Sun, 4 Jan 2026 22:59:46 -0600 Subject: [PATCH 2/2] update juni module with remote builds --- hosts/juni/flake.nix | 1 + 1 file changed, 1 insertion(+) diff --git a/hosts/juni/flake.nix b/hosts/juni/flake.nix index 8bac7468..efff5d1f 100644 --- a/hosts/juni/flake.nix +++ b/hosts/juni/flake.nix @@ -87,6 +87,7 @@ inputs.common.nixosModules.tty_caps_esc inputs.common.nixosModules.zsh # inputs.common.nixosModules.tailnet + inputs.common.nixosModules.remote_lio_builds ({ ringofstorms.secretsBao = {