Compare commits

...
Author SHA1 Message Date
beatzaplenty 2526b2dca7 Merge pull request 'chore(secrets): Phase 4 — remove stale sops.yaml anchors and re-encrypt' (#60) from worktree-phase0-provision-ordering-fix into main
Check NixOS configurations / eval-hosts (push) Successful in 10m19s
Merge PR #60: Phase 4 — remove stale sops.yaml anchors
2026-07-25 11:32:25 +00:00
beatzaplentyandClaude Sonnet 4.6 2df53fd5d7 chore(secrets): Phase 4 — remove stale sops.yaml anchors and re-encrypt
Check NixOS configurations / eval-hosts (pull_request) Successful in 10m21s
Remove four stale age key anchors from .sops.yaml that correspond to
non-lxc build-type variants that were never deployed (or are now
superseded by their lxc-* counterparts):

  &docker   → superseded by &lxc-docker (active running host)
  &server   → superseded by &lxc-server (active running host)
  &nix-cache → superseded by &lxc-nix-cache (active running host)
  &nix-minimal → superseded by &lxc-minimal (active running host)

Also remove the secrets/docker.yaml creation_rules block entirely since
that file does not exist.

Re-encrypt secrets/common.yaml, secrets/nix-cache.yaml, and
secrets/server.yaml with sops updatekeys to drop the stale recipients.
The four removed keys can no longer decrypt these files.

Update README.md and CLAUDE.md to clarify that deployed lxc-* hosts
now use clan vars (vars/per-machine/<target>/openssh/) rather than the
gitignored host-keys/ directory.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B2EJ4qTsM5KUqhS5c3GAwx
2026-07-25 21:31:56 +10:00
beatzaplenty 5e2ff76cf7 Merge pull request 'refactor(provision): Phase 3 — remove legacy host-keys/ fallback' (#59) from worktree-phase0-provision-ordering-fix into main
Check NixOS configurations / eval-hosts (push) Successful in 10m23s
Merge PR #59: Phase 3 — remove legacy host-keys/ fallback
2026-07-25 11:24:55 +00:00
beatzaplentyandClaude Sonnet 4.6 e8c4122460 refactor(provision): Phase 3 — remove legacy host-keys/ fallback
Check NixOS configurations / eval-hosts (pull_request) Successful in 10m22s
All actively deployed lxc-* hosts now have clan vars. Remove the legacy
scp -pr host-keys/ fallback in sync_remote_host_keys(): instead of
silently copying the gitignored directory, error clearly if no clan var
exists for the target and tell the operator how to generate one.

Also extend the uncommitted-changes check to cover vars/per-machine/ in
addition to .sops.yaml and secrets/, since clan vars must be committed
before the remote build git-pulls them.

Update the script header and sync_remote_host_keys comment to reflect
the new clan-only key flow.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B2EJ4qTsM5KUqhS5c3GAwx
2026-07-25 21:24:32 +10:00
beatzaplenty 5db41b1166 Merge pull request 'chore(vars): clan vars SSH host key for lxc-nix-cache' (#58) from worktree-phase0-provision-ordering-fix into main
Check NixOS configurations / eval-hosts (push) Successful in 10m22s
Merge PR #58: clan vars SSH host key for lxc-nix-cache
2026-07-25 11:18:19 +00:00
beatzaplentyandClaude Sonnet 4.6 ea7794dc05 chore(vars): commit clan vars SSH host key for lxc-nix-cache
Check NixOS configurations / eval-hosts (pull_request) Successful in 10m27s
Encrypted private key matches the running container's key and the
vars.nixCacheHostKey in variables.nix (no rotation). Age fingerprint
age1ufg390... matches the &lxc-nix-cache anchor in .sops.yaml.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B2EJ4qTsM5KUqhS5c3GAwx
2026-07-25 21:10:46 +10:00
beatzaplenty 67752fb1e8 Merge pull request 'fix(lxc): clan vars for lxc-tor-relay + sops-reinstall service fix (network.target)' (#57) from worktree-phase0-provision-ordering-fix into main
Check NixOS configurations / eval-hosts (push) Successful in 10m30s
Merge PR #57: fix(lxc): sops-reinstall to network.target + clan vars for lxc-tor-relay
2026-07-25 09:55:25 +00:00
beatzaplentyandClaude Sonnet 4.6 1a14b1d4d3 fix(lxc): move sops-reinstall service from sysinit to network.target
Check NixOS configurations / eval-hosts (pull_request) Successful in 10m34s
nixos-lxc-sops-reinstall.service called switch-to-configuration test at
sysinit.target time (DefaultDependencies=false), before D-Bus was up.
D-Bus is required to restart systemd targets after activation scripts
run. The service reported failure on every boot (exit 1: "Failed to open
dbus connection") even though secrets were correctly installed, because
the D-Bus call happens after activation scripts complete.

Move the service to network.target so basic.target (which includes
dbus-broker.service) runs first. Also drop DefaultDependencies=false so
systemd auto-adds After=basic.target. Add SuccessExitStatus=11 to handle
the edge case where switch-to-configuration holds the lock during a
concurrent rebuild (exit 11 = "Could not acquire lock" -- the rebuild's
own activation already installed the secrets, so treating it as success
is correct).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B2EJ4qTsM5KUqhS5c3GAwx
2026-07-25 19:50:35 +10:00
beatzaplentyandClaude Sonnet 4.6 68aea4cdcc chore(vars): commit clan vars SSH host key for lxc-tor-relay
The key was generated in a prior session but not committed — the clan vars
files existed only in that session's working tree. Recovered the original
private key from pve1's host-keys/ backup (fingerprint age16kqf... matches
the &lxc-tor-relay anchor already in .sops.yaml), re-encrypted for admin
age key only, and stored in the canonical clan vars layout.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B2EJ4qTsM5KUqhS5c3GAwx
2026-07-25 19:29:21 +10:00
beatzaplenty 0853952269 Merge pull request 'feat(provision): Phase 0-2 + fix — clan-core SSH host keys, activation ordering, boot-time sops' (#56) from worktree-phase0-provision-ordering-fix into main
Check NixOS configurations / eval-hosts (push) Successful in 10m33s
Merge feat(provision): Phase 0-2 + fix — clan-core SSH host keys, activation ordering, boot-time sops
2026-07-25 09:16:43 +00:00
beatzaplentyandClaude Sonnet 4.6 055577ee91 fix(lxc): fix activation ordering and add boot-time sops reinstall
Check NixOS configurations / eval-hosts (pull_request) Successful in 10m33s
Two bugs prevented nixos-rebuild switch from working on lxc-* hosts after
first boot, both confirmed live on a deployed lxc-tor-relay container:

1. Ordering bug: preserveSshHostKey had no explicit deps, so the topological
   sort placed it at position 7 — after etc at position 5. By the time it
   tried to save the SSH key, etc had already removed it as "obsolete"
   (absent from the current generation's environment.etc when built without
   NIXOS_HOST_KEYS_DIR). Consolidate all four system.activationScripts entries
   into one block and add etc = { deps = ["preserveSshHostKey"]; } and
   setupSecrets = { deps = ["restoreSshHostKey"]; } to enforce the correct
   save→etc→restore→sops chain.

2. No boot-time secrets: /run/secrets is a tmpfs cleared on every reboot, and
   sops-nix does NOT generate a boot-time service in this configuration
   (confirmed live: no sops-nix.service in systemctl list-unit-files).
   Add nixos-lxc-sops-reinstall.service, modelled after sops-nix's own service
   placement (wantedBy/before sysinit.target, DefaultDependencies=false), so
   secrets are reinstalled before basic.target on every non-first boot.
   ConditionPathExists skips it on first boot; nixos-lxc-first-boot-activate
   handles that case.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B2EJ4qTsM5KUqhS5c3GAwx
2026-07-25 19:07:30 +10:00
beatzaplentyandClaude Sonnet 4.6 a63e1c70c3 feat(provision): Phase 2 — migrate SSH host keys to clan vars
Replaces the gitignored host-keys/ directory with clan vars as the
authoritative storage for SSH host keys. Keys are now generated as
sops-binary-encrypted clan var files (admin-key only) and checked into
vars/per-machine/<target>/openssh/, eliminating the plaintext private
key that previously had to live outside the repo.

Changes:
- modules/clan/ssh-host-key.nix: clan vars generator for the ed25519
  SSH host key pair (neededFor="activation" — not mapped to sops.secrets,
  delivered via tarball baking for LXC or --pre-format-files for VMs)
- flake.nix: add clanCore module + required settings to every mkTarget;
  deduplicate bundled disko/sops-nix via follows; all 27 hosts eval clean
- flake.lock: updated to reflect the new follows constraints
- scripts/lib/clan-vars.sh: new helper library with
  clan_ssh_key_exists / clan_ssh_pubkey_path / clan_decrypt_ssh_key /
  clan_generate_ssh_key for use by the provisioning and sync scripts
- scripts/secrets/sync-host-keys.sh: queue_host_sync() now checks clan
  vars first; generates via clan_generate_ssh_key if no key exists;
  derives age fingerprint from clan pub key for .sops.yaml registration
- scripts/proxmox/create-proxmox-resource.sh: key management simplified
  (sync-host-keys.sh now generates the key if missing, so the inline
  prepare-host-key.sh call is gone); sync_remote_host_keys() decrypts
  the clan key into a temp dir and scps just the two files to the node
  when a clan key exists, falling back to the old host-keys/ scp for
  any remaining legacy entries

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01B2EJ4qTsM5KUqhS5c3GAwx
2026-07-25 18:22:33 +10:00
beatzaplentyandClaude Sonnet 4.6 a9745b594b feat(flake): add clan-core 26.05 as a flake input (Phase 1, no behavior change)
Introduces clan-core pinned to its 26.05 release alongside the existing nixpkgs
26.05 input. No host configuration is changed — this is a pure dependency
addition so Phase 2 (per-host vars/secret management migration) has the input
available without a separate flake.lock bump.

clan-core.inputs.nixpkgs.follows = "nixpkgs" keeps a single nixpkgs closure.
sops-nix remains as a flake input; vars layers on top of it rather than
replacing it (clan's sops storage backend still needs sops-nix).

All hosts evaluate cleanly (codex-maintenance.sh --full-check equivalent
triggered by the flake.nix change).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-25 17:29:29 +10:00
beatzaplentyandClaude Sonnet 4.6 78bb784265 fix(provision): block build until sops changes are committed, guard missing host keys
Three ordering-related fixes to the Proxmox provisioning flow:

1. prepare-host-key.sh: make idempotent -- if the key already exists, print
   a note and exit 0 instead of erroring. The caller (create-proxmox-resource.sh)
   already guards standalone calls, but the script itself should be safe to
   run directly on a host that was already keyed.

2. create-proxmox-resource.sh: after sync-host-keys.sh updates .sops.yaml /
   secrets/, detect uncommitted changes and block with a prompt until the
   operator confirms they've committed and pushed. The PVE node's git pull
   only picks up committed+pushed state; without this gate, a new host's sops
   recipient is missing from the secrets files the image build uses, so the
   host can't decrypt secrets on first boot.

3. create-proxmox-resource.sh: add an explicit existence check for the host
   key in both the LXC and VM remote build heredocs, before it's passed as
   --pre-format-files / NIXOS_HOST_KEYS_DIR input. Gives a clear error
   pointing at sync-host-keys.sh instead of a raw `cp: cannot stat` from
   disko deep in the build.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-25 17:14:25 +10:00
beatzaplentyandClaude Sonnet 4.6 784e064fa2 fix(create-proxmox-resource): use absolute path for --pre-format-files
Check NixOS configurations / eval-hosts (push) Successful in 10m20s
The disko images script does `cd "$TMPDIR"` before parsing its arguments,
so relative paths passed to --pre-format-files resolve against the temp
dir instead of the repo root. Use $(pwd) to capture the absolute repo
path before the disko script changes directory.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-25 16:45:04 +10:00
beatzaplenty 4a5afa6c1c Merge pull request 'fix(tailscale): rename tailscale-subnet-router to tailscale-router everywhere' (#55) from worktree-fix-tailscale-host-dir into main
Check NixOS configurations / eval-hosts (push) Successful in 10m33s
fix(tailscale): rename tailscale-subnet-router to tailscale-router everywhere
2026-07-25 06:37:18 +00:00
beatzaplentyandClaude Sonnet 4.6 9a0aea8f89 fix(create-proxmox-resource): auto-generate missing host key before sync
Check NixOS configurations / eval-hosts (push) Successful in 10m19s
If host-keys/<target>_ssh_host_ed25519_key doesn't exist, run
prepare-host-key.sh to generate it before sync-host-keys.sh runs.
Prevents sync-host-keys.sh from hitting its SKIP/exit-1 path (anchor
in .sops.yaml but no local key) and the downstream disko build failure
when --pre-format-files can't find the key file.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-07-25 16:26:49 +10:00
beatzaplenty b013e28dcd Merge pull request 'fix(tailscale): rename hosts/tailscale-subnet-router → hosts/tailscale-router' (#54) from worktree-fix-tailscale-host-dir into main
Check NixOS configurations / eval-hosts (push) Successful in 10m32s
Reviewed-on: #54
2026-07-25 06:24:59 +00:00
18 changed files with 682 additions and 282 deletions

No files matched your search

-16
View File
@@ -1,9 +1,5 @@
keys:
- &admin age1njap586hc0q43kr03g6c8eqhdsmk8zcafkl3f83xwlc2gqhlmfgs4tmwad
- &docker age19gfn2yedg76dmztm4hncr7vf3r3c9j0qpt4rap7y7gersjk4m3ks2lhd0e
- &server age1ll6hj5ggruetgjwjfnplpn5xtq35uhlcdflksx3xmnjm6s3uad9sz70jkf
- &nix-cache age120le4a5l8dh3lyfgvmj3d9ksmej6ajs5mer5y7r0vfg3x9fn69dqf8xgzu
- &nix-minimal age120whqj96g26lsgy4udvgsn8dc9lumh8jeu3a564fx79rjr5lxffqmrljuu
- &proxmox-minimal age10at8862478urh0eeuwh8hzln6ck78jgwtztgxatwqlzwagg77y5snm4xzg
- &lxc-gui age190htw7prp4vln076dxjx3gxxaq06h0zl0te7cqgpx79vl3lhkaes8suy05
- &baremetal-gui age1adur9g330gua4l6ndk8cqjg35qc8yxwgme6wrl2hpylcc7vxm38q05ejuy
@@ -36,10 +32,6 @@ creation_rules:
key_groups:
- age:
- *admin
- *docker
- *server
- *nix-cache
- *nix-minimal
- *proxmox-minimal
- *lxc-gui
- *baremetal-gui
@@ -67,7 +59,6 @@ creation_rules:
key_groups:
- age:
- *admin
- *nix-cache
- *linode-nix-cache
- *lxc-nix-cache
- *proxmox-nix-cache
@@ -76,17 +67,10 @@ creation_rules:
key_groups:
- age:
- *admin
- *server
- *linode-server
- *lxc-server
- *proxmox-server
- path_regex: secrets/docker\.yaml$
key_groups:
- age:
- *admin
- *docker
- path_regex: secrets/tor-relay\.yaml$
key_groups:
- age:
+11 -5
View File
@@ -27,9 +27,12 @@ machines when deployed.
template for a *real* host — every other host uses sops-nix
(`hashedPasswordFile`, see "Security Notes" in `README.md`). Flag any *new*
secret-like string you encounter instead of committing it.
- `host-keys/` is gitignored — locally-generated *private* SSH host keys for
the auto-installer (see `docs/auto-installer.md`). Never commit its
contents; if `git status` ever shows it as trackable, something is wrong.
- `host-keys/` is gitignored — locally-generated *private* SSH host keys
for the auto-installer and non-LXC hosts (see `docs/auto-installer.md`).
Never commit its contents; if `git status` ever shows it as trackable,
something is wrong. Deployed LXC hosts use clan vars
(`vars/per-machine/<target>/openssh/`, committed and sops-encrypted)
instead — those ARE tracked by git and belong in the repo.
### Two Proxmox nodes: `pve1.sweet.home` (production) and `pve-test.sweet.home` (sandbox)
@@ -203,8 +206,11 @@ instead of copying it.
- `scripts/secrets/sync-host-keys.sh` — generates/registers SSH host keys
and their `.sops.yaml`/`secrets/*.yaml` recipients for flake targets,
idempotently (`--all`, `<target>`, `--remove`, `--regenerate-all-keys`,
all with `--dry-run`). The primary tool for provisioning a new host's
secrets access — see "Creating a new machine" in `docs/auto-installer.md`.
all with `--dry-run`). For lxc-* targets it stores keys as clan vars
(`vars/per-machine/<target>/openssh/`, committed and sops-encrypted);
for other targets it uses the gitignored `host-keys/` directory. The
primary tool for provisioning a new host's secrets access — see
"Creating a new machine" in `docs/auto-installer.md`.
- `scripts/secrets/prepare-host-key.sh` — narrower predecessor: generates a
key by an arbitrary name without touching `.sops.yaml`. Still useful to
pre-generate a key before its flake target exists yet, since
+4 -2
View File
@@ -72,7 +72,8 @@ nix eval --json .#nixosConfigurations --apply builtins.attrNames | jq -r '.[]'
| `modules/common/` | Shared NixOS config, Home Manager, aliases imported by every host |
| `modules/nix-cache/` | Binary cache and remote builder client/server modules |
| `modules/installer/` | Auto-installer environment (ISO, also served as PXE netboot) — see `docs/auto-installer.md` |
| `host-keys/` | Gitignored, locally-generated SSH host keys for the auto-installer — see `docs/auto-installer.md` |
| `host-keys/` | Gitignored, locally-generated SSH host keys for the auto-installer (non-LXC hosts) — see `docs/auto-installer.md`. LXC hosts use clan vars (`vars/per-machine/<target>/openssh/`) instead |
| `vars/per-machine/` | Clan vars: committed, sops-encrypted SSH host keys for deployed LXC hosts; read by `create-proxmox-resource.sh` at deploy time |
| `docs/` | Operational notes for cache, builders, lock updates, boot services, the auto-installer, and Proxmox image builds |
| `scripts/` | Codex setup, validation, host-key, release-bump, and Proxmox resource helpers |
@@ -162,7 +163,8 @@ sops-nix-everywhere: it has a hardcoded login password instead (no stable
per-boot host key for sops-nix to derive from on ephemeral media) — see
"Host keys" in `docs/auto-installer.md` for why, and how the private keys it
*does* pre-seed for target hosts stay out of git via the gitignored
`host-keys/` directory.
`host-keys/` directory. Deployed LXC hosts instead use clan vars
(`vars/per-machine/<target>/openssh/`, committed and sops-encrypted).
This repository's git *history* still contains secrets committed before this
migration (see `remove-sensetive-info-refactor.md`) — those are being
Generated
+151 -1
View File
@@ -1,5 +1,62 @@
{
"nodes": {
"clan-core": {
"inputs": {
"data-mesher": "data-mesher",
"disko": [
"disko"
],
"flake-parts": "flake-parts",
"nix-darwin": "nix-darwin",
"nix-select": "nix-select",
"nixpkgs": [
"nixpkgs"
],
"sops-nix": [
"sops-nix"
],
"systems": "systems",
"treefmt-nix": "treefmt-nix"
},
"locked": {
"lastModified": 1783497933,
"narHash": "sha256-TxmwEews6URFPqOWEHNychtXbFDgLZjbOfEXtvtOm6U=",
"rev": "3dc0221ca09033599fe98055e9bbc81bdf32732a",
"type": "tarball",
"url": "https://git.clan.lol/api/v1/repos/clan/clan-core/archive/3dc0221ca09033599fe98055e9bbc81bdf32732a.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://git.clan.lol/clan/clan-core/archive/26.05.tar.gz"
}
},
"data-mesher": {
"inputs": {
"flake-parts": [
"clan-core",
"flake-parts"
],
"nixpkgs": [
"clan-core",
"nixpkgs"
],
"treefmt-nix": [
"clan-core",
"treefmt-nix"
]
},
"locked": {
"lastModified": 1778718524,
"narHash": "sha256-pXLoI6Ax0EnUK6r34UM1vibVC7CfTu6j72R2692ZzPs=",
"rev": "12c552ad547d87254f33f33bddd1a2cdbeac754d",
"type": "tarball",
"url": "https://git.clan.lol/api/v1/repos/clan/data-mesher/archive/12c552ad547d87254f33f33bddd1a2cdbeac754d.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://git.clan.lol/clan/data-mesher/archive/main.tar.gz"
}
},
"disko": {
"inputs": {
"nixpkgs": [
@@ -51,9 +108,30 @@
"type": "github"
}
},
"flake-parts": {
"inputs": {
"nixpkgs-lib": [
"clan-core",
"nixpkgs"
]
},
"locked": {
"lastModified": 1778716662,
"narHash": "sha256-m1Yf0wZ8j1OHjTc2UwHwyQRSnNeSgLJOd7q5Y45hzi4=",
"owner": "hercules-ci",
"repo": "flake-parts",
"rev": "f7c1a2d347e4c52d5fb8d10cb4d94b5884e546fb",
"type": "github"
},
"original": {
"owner": "hercules-ci",
"repo": "flake-parts",
"type": "github"
}
},
"flake-utils": {
"inputs": {
"systems": "systems"
"systems": "systems_2"
},
"locked": {
"lastModified": 1694529238,
@@ -109,6 +187,40 @@
"type": "github"
}
},
"nix-darwin": {
"inputs": {
"nixpkgs": [
"clan-core",
"nixpkgs"
]
},
"locked": {
"lastModified": 1779036909,
"narHash": "sha256-zXcwYQGCT6pzinK+1dBB2ekTVtfxGZAapb3Evdcu4fY=",
"owner": "nix-darwin",
"repo": "nix-darwin",
"rev": "56c666e108467d87d13508936aade6d567f2a501",
"type": "github"
},
"original": {
"owner": "nix-darwin",
"repo": "nix-darwin",
"type": "github"
}
},
"nix-select": {
"locked": {
"lastModified": 1763303120,
"narHash": "sha256-yxcNOha7Cfv2nhVpz9ZXSNKk0R7wt4AiBklJ8D24rVg=",
"rev": "3d1e3860bef36857a01a2ddecba7cdb0a14c35a9",
"type": "tarball",
"url": "https://git.clan.lol/api/v1/repos/clan/nix-select/archive/3d1e3860bef36857a01a2ddecba7cdb0a14c35a9.tar.gz"
},
"original": {
"type": "tarball",
"url": "https://git.clan.lol/clan/nix-select/archive/main.tar.gz"
}
},
"nixos-conf-editor": {
"inputs": {
"flake-compat": "flake-compat",
@@ -163,6 +275,7 @@
},
"root": {
"inputs": {
"clan-core": "clan-core",
"disko": "disko",
"home-manager": "home-manager",
"nixos-conf-editor": "nixos-conf-editor",
@@ -214,6 +327,22 @@
}
},
"systems": {
"locked": {
"lastModified": 1774449309,
"narHash": "sha256-brhZ8DmuGtzkCYHJg4HEd602amKm89Y9ytsFZ5uWD1w=",
"owner": "nix-systems",
"repo": "default",
"rev": "c29398b59d2048c4ab79345812849c9bd15e9150",
"type": "github"
},
"original": {
"owner": "nix-systems",
"ref": "future-26.11",
"repo": "default",
"type": "github"
}
},
"systems_2": {
"locked": {
"lastModified": 1681028828,
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
@@ -227,6 +356,27 @@
"repo": "default",
"type": "github"
}
},
"treefmt-nix": {
"inputs": {
"nixpkgs": [
"clan-core",
"nixpkgs"
]
},
"locked": {
"lastModified": 1780220602,
"narHash": "sha256-eynAfOmbmxJnkp7YewvCEbShNnnYJ9gLLqkzsYtBPeM=",
"owner": "numtide",
"repo": "treefmt-nix",
"rev": "db947814a175b7ca6ded66e21383d938df01c227",
"type": "github"
},
"original": {
"owner": "numtide",
"repo": "treefmt-nix",
"type": "github"
}
}
},
"root": "root",
+29
View File
@@ -16,6 +16,19 @@
url = "github:Mic92/sops-nix";
inputs.nixpkgs.follows = "nixpkgs";
};
clan-core = {
url = "https://git.clan.lol/clan/clan-core/archive/26.05.tar.gz";
# Deduplicate modules: clan-core bundles its own disko and sops-nix
# (both imported by nixosModules.clanCore). Without follows, we'd get
# two different versions of each, and disko's _module.args.diskoLib
# unique option would conflict. With follows, clan-core uses the same
# store paths as us, so NixOS deduplicates the imports.
inputs = {
nixpkgs.follows = "nixpkgs";
disko.follows = "disko";
sops-nix.follows = "sops-nix";
};
};
};
outputs = { self, nixpkgs, nixos-conf-editor, home-manager, sops-nix, ... } @ inputs:
@@ -41,6 +54,22 @@
modules = [
inputs.disko.nixosModules.disko
sops-nix.nixosModules.sops
inputs.clan-core.nixosModules.clanCore
{
# Required clan settings. directory is the flake root (where
# vars/ and sops/ directories live); machine.name is the flake
# target name (matches what clan vars generate uses as the key
# under vars/per-machine/). enableRecommendedDefaults = false
# is mandatory: without it, clan unconditionally enables
# networking.useNetworkd, adds packages, and tweaks nix settings
# -- none of which belong here.
clan.core = {
settings.directory = self;
settings.machine.name = flakeTarget;
enableRecommendedDefaults = false;
};
}
./modules/clan/ssh-host-key.nix
./modules/common/configuration.nix
./modules/platforms/${platform}.nix
./modules/build-types/${buildType}.nix
+30
View File
@@ -0,0 +1,30 @@
{ pkgs, ... }: {
# Defines the SSH host key as a clan vars generator so that:
# - `clan vars generate <target>` creates and encrypts the key pair
# - The private key lives at vars/per-machine/<target>/openssh/ssh_host_ed25519_key/secret
# (sops binary-encrypted, admin-key-only; decrypted by the build script)
# - The public key lives at vars/per-machine/<target>/openssh/ssh_host_ed25519_key.pub/value
# (plaintext; used by sync-host-keys.sh to derive the sops age fingerprint)
#
# neededFor = "activation" means clan's deployment tool would upload this
# before running nixos-rebuild/nixos-install (for VM/baremetal via
# nixos-anywhere). For lxc-* hosts, the build script bakes it into the
# tarball directly via NIXOS_HOST_KEYS_DIR -- the neededFor value here
# simply ensures it is NOT mapped to sops.secrets (which would try to
# decrypt it at runtime as a regular service secret, which is wrong: the
# SSH host key reaches the container via the tarball, not sops).
clan.core.vars.generators.openssh = {
files."ssh_host_ed25519_key" = {
secret = true;
neededFor = "activation";
};
files."ssh_host_ed25519_key.pub" = {
secret = false;
neededFor = "activation";
};
runtimeInputs = [ pkgs.openssh ];
script = ''
ssh-keygen -t ed25519 -N "" -C "" -f "$out/ssh_host_ed25519_key"
'';
};
}
+74 -25
View File
@@ -114,30 +114,39 @@ in
# /etc/ssh/ssh_host_ed25519_key; deletion cascades into every sops secret
# failing with "Error getting data key: 0 successful groups required, got 0".
#
# Fix: two activation scripts that bracket the etc step.
# preserveSshHostKey — no deps, runs before etc — saves the live key to
# /run (tmpfs) before etc can delete it.
# restoreSshHostKey — deps=[etc], runs after etc — reinstalls the key via
# `install` (atomic, sets mode) if etc removed it.
# The resulting file is not registered in environment.etc
# for either the previous or current generation, so
# subsequent rebuilds leave it alone permanently.
system.activationScripts.preserveSshHostKey = ''
if [ -f /etc/ssh/ssh_host_ed25519_key ]; then
cp /etc/ssh/ssh_host_ed25519_key /run/sshd-host-key-preserve.tmp
cp /etc/ssh/ssh_host_ed25519_key.pub /run/sshd-host-key-preserve.pub.tmp
fi
'';
system.activationScripts.restoreSshHostKey = {
deps = [ "etc" ];
text = ''
if [ ! -f /etc/ssh/ssh_host_ed25519_key ] && [ -f /run/sshd-host-key-preserve.tmp ]; then
install -m 0600 /run/sshd-host-key-preserve.tmp /etc/ssh/ssh_host_ed25519_key
install -m 0644 /run/sshd-host-key-preserve.pub.tmp /etc/ssh/ssh_host_ed25519_key.pub
# Fix: activation scripts that bracket the etc step, with explicit deps
# to enforce the correct ordering. Without deps the topological sort places
# preserveSshHostKey AFTER etc (confirmed live on a deployed lxc-tor-relay:
# position 7 vs etc's position 5) -- the key is already gone by the time it
# tries to save it. The etc/setupSecrets entries ADD to existing deps
# (types.listOf concatenates across module definitions).
system.activationScripts = {
# Saves the live key to /run before etc can delete it.
preserveSshHostKey = ''
if [ -f /etc/ssh/ssh_host_ed25519_key ]; then
cp /etc/ssh/ssh_host_ed25519_key /run/sshd-host-key-preserve.tmp
cp /etc/ssh/ssh_host_ed25519_key.pub /run/sshd-host-key-preserve.pub.tmp
fi
rm -f /run/sshd-host-key-preserve.tmp /run/sshd-host-key-preserve.pub.tmp
'';
# Reinstalls the key after etc runs if it was removed as "obsolete".
# The resulting file is not registered in environment.etc for either
# generation, so subsequent rebuilds leave it alone permanently.
restoreSshHostKey = {
deps = [ "etc" ];
text = ''
if [ ! -f /etc/ssh/ssh_host_ed25519_key ] && [ -f /run/sshd-host-key-preserve.tmp ]; then
install -m 0600 /run/sshd-host-key-preserve.tmp /etc/ssh/ssh_host_ed25519_key
install -m 0644 /run/sshd-host-key-preserve.pub.tmp /etc/ssh/ssh_host_ed25519_key.pub
fi
rm -f /run/sshd-host-key-preserve.tmp /run/sshd-host-key-preserve.pub.tmp
'';
};
# Force etc to wait until the key is saved, and sops to wait until the
# key is restored. Without these the topological sort breaks the chain.
etc = { deps = [ "preserveSshHostKey" ]; };
setupSecrets = { deps = [ "restoreSshHostKey" ]; };
};
# virtualisation/proxmox-lxc.nix (imported above) registers the Nix
@@ -146,9 +155,12 @@ in
# sops-nix's "for users" secrets (password hashes -- installed by the
# activation script itself, not a systemd service, since they need to
# exist *before* user creation) nor the user-creation step that
# consumes them ever run on a real lxc-* boot. Regular secrets
# (nix-serve's key, beszel's token, etc.) work anyway because sops-nix
# provides its own systemd service for those.
# consumes them ever run on a real lxc-* boot. In this config sops-nix
# does NOT generate its own boot-time service (confirmed live: no
# sops-nix.service in systemctl list-unit-files on a deployed
# lxc-tor-relay container); /run/secrets is a tmpfs cleared on every
# reboot, so secrets must be reinstalled on each non-first boot by
# nixos-lxc-sops-reinstall (below).
#
# A systemd service, not boot.postBootCommands: tried that first (it's
# a genuine, generally-invoked hook -- nixos/modules/system/boot/stage-2-init.sh,
@@ -199,4 +211,41 @@ in
touch /var/lib/nixos-lxc-first-boot-activated
'';
};
# Reinstalls sops secrets on every non-first boot. /run/secrets is a
# tmpfs that is cleared on each reboot; without this service, secrets
# are permanently absent after the first boot and every service that
# reads from /run/secrets fails on start.
#
# wantedBy/before network.target: switch-to-configuration test requires
# D-Bus to restart systemd targets after running activation scripts. D-Bus
# is available once basic.target completes (the default After=basic.target
# that DefaultDependencies would otherwise add). Placing the service before
# network.target ensures secrets are ready before any network-dependent
# service (including beszel-agent and nix-serve) starts, while running late
# enough that D-Bus is already up.
#
# ConditionPathExists=... skips this service on the genuine first boot
# (the marker doesn't exist yet); nixos-lxc-first-boot-activate handles
# that case. On every subsequent boot the condition passes and secrets
# are reinstalled before user services start.
#
# SuccessExitStatus=11: switch-to-configuration exits 11 when it cannot
# acquire the activation lock (another switch is already in progress).
# During a nixos-rebuild switch the activation already installs secrets, so
# treating the lock-held case as success is correct.
systemd.services.nixos-lxc-sops-reinstall = {
description = "Reinstall sops secrets on each non-first boot (LXC, /run is tmpfs)";
wantedBy = [ "network.target" ];
before = [ "network.target" ];
unitConfig.ConditionPathExists = "/var/lib/nixos-lxc-first-boot-activated";
serviceConfig = {
Type = "oneshot";
RemainAfterExit = true;
SuccessExitStatus = "11";
};
script = ''
/run/current-system/bin/switch-to-configuration test
'';
};
}
+106
View File
@@ -0,0 +1,106 @@
#!/usr/bin/env bash
# Clan vars helpers: manage SSH host keys stored as clan vars (sops-encrypted
# binary files under vars/per-machine/<target>/openssh/) instead of the
# gitignored host-keys/ directory.
#
# Layout (per clan's convention):
# vars/per-machine/<target>/openssh/ssh_host_ed25519_key/secret -- sops binary (admin-encrypted)
# vars/per-machine/<target>/openssh/ssh_host_ed25519_key.pub/value -- plaintext SSH pubkey
#
# Sourced by create-proxmox-resource.sh and sync-host-keys.sh.
# Depends on sops-age.sh and ssh-host-keys.sh being sourced first (for
# sops_yaml_admin_pubkey, ssh_pubkey_to_age, and NIX_OPTS).
if ! declare -p NIX_OPTS >/dev/null 2>&1; then
declare -a NIX_OPTS=()
fi
# clan_ssh_key_exists <target> <repo_root>
# Returns 0 if clan vars hold a SSH host key for <target>, 1 otherwise.
clan_ssh_key_exists() {
local target="$1" repo_root="$2"
[[ -f "${repo_root}/vars/per-machine/${target}/openssh/ssh_host_ed25519_key/secret" ]]
}
# clan_ssh_pubkey_path <target> <repo_root>
# Prints the path to the plaintext SSH public key value file.
clan_ssh_pubkey_path() {
local target="$1" repo_root="$2"
echo "${repo_root}/vars/per-machine/${target}/openssh/ssh_host_ed25519_key.pub/value"
}
# clan_decrypt_ssh_key <target> <repo_root> <dest_dir>
# Decrypts the sops-encrypted SSH host private key for <target> into <dest_dir>,
# naming it <target>_ssh_host_ed25519_key (to match NIXOS_HOST_KEYS_DIR
# conventions that lxc.nix and the disko build already expect). Also copies
# the plaintext public key. The caller is responsible for protecting and
# cleaning up <dest_dir>.
clan_decrypt_ssh_key() {
local target="$1" repo_root="$2" dest_dir="$3"
local secret="${repo_root}/vars/per-machine/${target}/openssh/ssh_host_ed25519_key/secret"
local pubval="${repo_root}/vars/per-machine/${target}/openssh/ssh_host_ed25519_key.pub/value"
local dest_priv="${dest_dir}/${target}_ssh_host_ed25519_key"
local dest_pub="${dest_dir}/${target}_ssh_host_ed25519_key.pub"
nix-shell "${NIX_OPTS[@]}" -p sops --run \
"sops -d --output-type binary '${secret}'" > "$dest_priv"
chmod 0600 "$dest_priv"
cp "$pubval" "$dest_pub"
}
# clan_generate_ssh_key <target> <repo_root>
# Generates a new SSH host key pair and stores it in clan vars format:
# - private key: sops binary-encrypted for the admin age key
# - public key: plaintext value file
# Idempotent: if the secret already exists, prints a note and returns 0.
# Requires sops_yaml_admin_pubkey (from sops-age.sh) to be available.
clan_generate_ssh_key() {
local target="$1" repo_root="$2"
local var_base="${repo_root}/vars/per-machine/${target}/openssh"
local secret_dir="${var_base}/ssh_host_ed25519_key"
local pubval_dir="${var_base}/ssh_host_ed25519_key.pub"
if [[ -f "${secret_dir}/secret" ]]; then
echo "Clan SSH host key for ${target} already exists -- skipping generation."
return 0
fi
# Resolve admin age public key from .sops.yaml
local admin_pubkey
admin_pubkey="$(sops_yaml_admin_pubkey "${repo_root}/.sops.yaml")"
if [[ -z "$admin_pubkey" ]]; then
echo "ERROR: Could not find &admin age key in ${repo_root}/.sops.yaml" >&2
return 1
fi
# Generate the SSH key pair in a secure temp directory
local tmpdir
tmpdir="$(mktemp -d)"
local priv_tmp="${tmpdir}/ssh_host_ed25519_key"
# shellcheck disable=SC2064
trap "rm -rf '${tmpdir}'" RETURN
nix-shell "${NIX_OPTS[@]}" -p openssh --run \
"ssh-keygen -t ed25519 -N '' -C '${target}' -f '${priv_tmp}'" >/dev/null
# Create a minimal sops config that uses only the admin age key -- this
# prevents sops from merging in ALL recipients from .sops.yaml (which
# would unnecessarily encrypt for every host's key, not just admin).
local sops_cfg="${tmpdir}/sops-config.json"
printf '{"creation_rules":[{"key_groups":[{"age":["%s"]}]}]}\n' \
"$admin_pubkey" > "$sops_cfg"
# Encrypt the private key in sops binary format (admin-only recipient)
mkdir -p "$secret_dir" "$pubval_dir"
nix-shell "${NIX_OPTS[@]}" -p sops --run \
"sops -e --config '${sops_cfg}' --input-type binary '${priv_tmp}'" \
> "${secret_dir}/secret"
# Store the public key as a plaintext value file
cp "${priv_tmp}.pub" "${pubval_dir}/value"
echo "Generated and stored clan SSH host key for ${target}."
echo " Private key: ${secret_dir}/secret (sops binary, admin-key encrypted)"
echo " Public key: ${pubval_dir}/value"
}
+72 -14
View File
@@ -8,9 +8,12 @@
# script -- there's no multi-gigabyte image to transfer afterward. The first
# time a node doesn't have that repo path yet, it's bootstrapped: cloned from
# this checkout's own `origin` remote, then scripts/codex-setup.sh installs
# the build tooling (Nix, etc.). Every run after that just `git pull`s it and
# copies over the locally-managed host-keys/ (gitignored, so a git pull
# alone wouldn't carry it) before building.
# the build tooling (Nix, etc.). Every run after that just `git pull`s it.
# SSH host keys are stored as clan vars (vars/per-machine/<target>/openssh/,
# committed and sops-encrypted) -- the script decrypts them locally and
# copies only the two files for this target to the node's host-keys/ before
# building. A target with no clan var is an error (generate one first with
# scripts/secrets/sync-host-keys.sh <target>).
#
# --node (default: $PROXMOX_HOST, see scripts/env.sh) picks which of the two
# LAN Proxmox nodes this runs against: production, pve1.sweet.home
@@ -59,6 +62,10 @@ source "${repo_root}/scripts/env.sh"
source "${repo_root}/scripts/lib/nix-eval.sh"
# shellcheck source=../lib/confirm.sh
source "${repo_root}/scripts/lib/confirm.sh"
# shellcheck source=../lib/sops-age.sh
source "${repo_root}/scripts/lib/sops-age.sh"
# shellcheck source=../lib/clan-vars.sh
source "${repo_root}/scripts/lib/clan-vars.sh"
sync_keys="${repo_root}/scripts/secrets/sync-host-keys.sh"
@@ -485,12 +492,37 @@ echo "Target: ${flake_target} (host=${host}, type=${type}) -> Proxmox resource '
nix_extra_opts
# --- make sure this target has a registered host key --------------------
# sync-host-keys.sh is idempotent and generates the key (via clan vars) if
# no key exists yet -- the old inline prepare-host-key.sh call is gone.
echo
echo "==> Ensuring host key exists and is registered..."
sync_args=("$flake_target")
[[ "$dry_run" -eq 1 ]] && sync_args+=(--dry-run)
bash "$sync_keys" "${sync_args[@]}"
# If sync-host-keys.sh changed .sops.yaml, secrets/, or vars/per-machine/,
# those changes must be committed and pushed before the remote `git pull`
# below picks them up -- the PVE node builds from whatever HEAD is checked
# out there, not the local working tree. Uncommitted clan vars or sops
# recipients mean the image builds fine but the host cannot decrypt its
# secrets on first boot. Block until the operator confirms they've pushed.
if [[ "$dry_run" -eq 0 ]]; then
_dirty="$(git -C "$repo_root" status --porcelain -- .sops.yaml secrets/ vars/per-machine/ 2>/dev/null || true)"
if [[ -n "$_dirty" ]]; then
echo
echo "==> COMMIT + PUSH REQUIRED before the remote build can succeed:"
echo " Uncommitted changes in .sops.yaml, secrets/, or vars/per-machine/."
echo " The PVE node builds from the git-tracked flake, so these changes"
echo " must be committed and pushed first -- otherwise the image build will"
echo " succeed but the host cannot decrypt its secrets on first boot."
echo
git -C "$repo_root" status --short -- .sops.yaml secrets/ vars/per-machine/ || true
echo
read -rp " Commit and push those changes, then press Enter to continue (Ctrl-C to abort): "
fi
unset _dirty
fi
# --- VMID: pick one, and refuse to touch anything that already exists ---
echo
if [[ -z "$vmid" ]]; then
@@ -613,21 +645,35 @@ ensure_remote_repo() {
fi
}
# --- sync locally-managed host-keys/ to the node ---------------------------
# Gitignored (see .gitignore), so `git pull` above never carries it -- both
# build paths need it present as NIXOS_HOST_KEYS_DIR / --pre-format-files
# input on the node itself now that the build runs there. scp (not rsync,
# not already a dependency anywhere else in this repo) mirrors how this
# script already transfers the --image case below.
# --- sync host key to the node ---------------------------------------------
# SSH host keys are stored as clan vars (vars/per-machine/<target>/openssh/).
# Decrypt locally and scp just the two files for this target to the node's
# host-keys/ directory, where the remote build script picks them up via
# NIXOS_HOST_KEYS_DIR (LXC) or --pre-format-files (VM). A target with no
# clan var is an error -- generate one first with sync-host-keys.sh.
sync_remote_host_keys() {
echo
echo "==> Syncing host-keys/ to ${node}..."
echo "==> Syncing host key for ${flake_target} to ${node}..."
if [[ "$dry_run" -eq 1 ]]; then
echo "[dry-run] would copy ${repo_root}/host-keys/ to ${ssh_target}:${remote_repo_dir}/host-keys/"
echo "[dry-run] would decrypt clan SSH key for ${flake_target} and copy to ${ssh_target}:${remote_repo_dir}/host-keys/"
return
fi
if ! clan_ssh_key_exists "$flake_target" "$repo_root"; then
echo "ERROR: no clan SSH key found for ${flake_target}" >&2
echo " (expected: ${repo_root}/vars/per-machine/${flake_target}/openssh/ssh_host_ed25519_key/secret)" >&2
echo " Generate one first: bash scripts/secrets/sync-host-keys.sh ${flake_target}" >&2
exit 1
fi
local tmpdir
tmpdir="$(mktemp -d)"
# shellcheck disable=SC2064
trap "rm -rf '${tmpdir}'" RETURN
echo " Decrypting clan SSH key for ${flake_target}..."
clan_decrypt_ssh_key "$flake_target" "$repo_root" "$tmpdir"
ssh "$ssh_target" "mkdir -p '${remote_repo_dir}/host-keys'"
scp -pr "${repo_root}/host-keys/." "${ssh_target}:${remote_repo_dir}/host-keys/"
scp -p "${tmpdir}/${flake_target}_ssh_host_ed25519_key" \
"${tmpdir}/${flake_target}_ssh_host_ed25519_key.pub" \
"${ssh_target}:${remote_repo_dir}/host-keys/"
}
# --- build (or reuse an image already on the node) ------------------------
@@ -696,6 +742,12 @@ cd "$repo_dir"
# right after a successful install.
. scripts/lib/nix-bootstrap.sh
ensure_nix_profile
if [[ ! -f "host-keys/${target}_ssh_host_ed25519_key" ]]; then
echo "ERROR: host-keys/${target}_ssh_host_ed25519_key not found in ${repo_dir}." >&2
echo "Generate the key locally (scripts/secrets/sync-host-keys.sh ${target})" >&2
echo "and ensure it was synced here before starting the build." >&2
exit 1
fi
NIXOS_HOST_KEYS_DIR="$(pwd)/host-keys" nix build --impure \
--no-use-registries --no-accept-flake-config "${NIX_OPTS[@]}" \
".#nixosConfigurations.${target}.config.system.build.tarball" \
@@ -736,12 +788,18 @@ declare -a NIX_OPTS=()
cd "$repo_dir"
. scripts/lib/nix-bootstrap.sh
ensure_nix_profile
if [[ ! -f "host-keys/${target}_ssh_host_ed25519_key" ]]; then
echo "ERROR: host-keys/${target}_ssh_host_ed25519_key not found in ${repo_dir}." >&2
echo "Generate the key locally (scripts/secrets/sync-host-keys.sh ${target})" >&2
echo "and ensure it was synced here before starting the build." >&2
exit 1
fi
nix build --no-use-registries --no-accept-flake-config "${NIX_OPTS[@]}" \
".#nixosConfigurations.${target}.config.system.build.diskoImagesScript" \
--out-link "result-${target}"
$sudo_pfx "./result-${target}" \
--pre-format-files "host-keys/${target}_ssh_host_ed25519_key" /etc/ssh/ssh_host_ed25519_key \
--pre-format-files "host-keys/${target}_ssh_host_ed25519_key.pub" /etc/ssh/ssh_host_ed25519_key.pub \
--pre-format-files "$(pwd)/host-keys/${target}_ssh_host_ed25519_key" /etc/ssh/ssh_host_ed25519_key \
--pre-format-files "$(pwd)/host-keys/${target}_ssh_host_ed25519_key.pub" /etc/ssh/ssh_host_ed25519_key.pub \
--build-memory 2048
built="$(find . -maxdepth 1 -name '*.raw' -newer "result-${target}" | head -1)"
if [[ -z "$built" ]]; then
+3 -2
View File
@@ -41,8 +41,9 @@ mkdir -p "$keydir"
keyfile="${keydir}/${hostname}_ssh_host_ed25519_key"
if [[ -f "$keyfile" ]]; then
echo "ERROR: $keyfile already exists. Remove it first if you want to regenerate." >&2
exit 1
echo "Key already exists: ${keyfile}"
echo "Reusing the existing key. Remove it first if you want to regenerate."
exit 0
fi
nix_extra_opts
+17 -8
View File
@@ -39,6 +39,8 @@ source "${repo_root}/scripts/lib/ssh-host-keys.sh"
source "${repo_root}/scripts/lib/sops-age.sh"
# shellcheck source=../lib/confirm.sh
source "${repo_root}/scripts/lib/confirm.sh"
# shellcheck source=../lib/clan-vars.sh
source "${repo_root}/scripts/lib/clan-vars.sh"
mkdir -p "$keydir"
@@ -146,13 +148,15 @@ dry_run=0
queue_host_sync() {
local host="$1"
local keyfile="${keydir}/${host}_ssh_host_ed25519_key"
local has_local_key=0 has_anchor=0
local has_local_key=0 has_clan_key=0 has_anchor=0
[[ -f "$keyfile" ]] && has_local_key=1
clan_ssh_key_exists "$host" "$repo_root" && has_clan_key=1
grep -qE "^ - &${host} age1" "$sops_yaml" && has_anchor=1
if [[ "$has_local_key" -eq 0 && "$has_anchor" -eq 1 ]]; then
if [[ "$has_local_key" -eq 0 && "$has_clan_key" -eq 0 && "$has_anchor" -eq 1 ]]; then
echo "SKIP ${host}: .sops.yaml already has an &${host} anchor, but"
echo " host-keys/${host}_ssh_host_ed25519_key is missing locally."
echo " neither host-keys/${host}_ssh_host_ed25519_key nor"
echo " vars/per-machine/${host}/openssh/ exist locally."
echo " Not generating a replacement -- it wouldn't match whatever's"
echo " already registered (and possibly deployed). Remove the"
echo " &${host} line from .sops.yaml first if you really want a"
@@ -160,21 +164,26 @@ queue_host_sync() {
return 1
fi
if [[ "$has_local_key" -eq 0 ]]; then
if [[ "$has_local_key" -eq 0 && "$has_clan_key" -eq 0 ]]; then
if [[ "$dry_run" -eq 1 ]]; then
echo "[dry-run] ${host}: would generate host key"
echo "[dry-run] ${host}: would generate host key via clan vars"
else
echo "==> ${host}: generating host key"
generate_host_ed25519_key "$host" "$keyfile"
echo "==> ${host}: generating host key via clan vars"
clan_generate_ssh_key "$host" "$repo_root"
has_clan_key=1
fi
elif [[ "$has_clan_key" -eq 1 ]]; then
echo "==> ${host}: clan-managed SSH host key already present"
else
echo "==> ${host}: host key already present"
echo "==> ${host}: host key already present (host-keys/)"
fi
if [[ "$has_anchor" -eq 0 ]]; then
local age_pub
if [[ "$dry_run" -eq 1 ]]; then
age_pub="dry-run-placeholder-not-a-real-key"
elif [[ "$has_clan_key" -eq 1 ]]; then
age_pub="$(ssh_pubkey_to_age "$(clan_ssh_pubkey_path "$host" "$repo_root")")"
else
age_pub="$(ssh_pubkey_to_age "${keyfile}.pub")"
fi
+115 -151
View File
@@ -5,245 +5,209 @@ sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBibGF2a2FRcTRFTk9rQ0NN
TTFoRlBWbGdSMzVVRHYvVFFvVm05ZDZBb1VrCkFoM2dTMEJDMHRKd240OEExWnUv
RHV2S0taWnl0dS80YVIvTjBpVEk5a0kKLS0tIGF2TkNQdlVJTTNOSnI4cEZCRll3
NE9aSWxVVTlyV2hPQ284cU94Y2hVNEkKhUFgr345o91orzqCzkKdh6dAXlPfwqTJ
su5kATsokLzcyvT/gcOKsDBzO219CJ0cSVmpgVJtImSCJDwUS3A6Ug==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBiT2oxVkhrTVo3Wkx1SXFG
NzJFTkFrbHJKMTZGeVFDT2VVL2xFQmNsd1NjCi84eHA2TmV0WVBzckhnZFYxallI
WFptVFFKOXBlSXNvTWxEUlNNYUtPQUkKLS0tIDRjWWJVWjNtR0JSUk9Rc1hhK2lN
ME4wRE1hMlQ5d0tLYVZmTHYwZURLaE0KMKA/MUzB/a3OjibvYTlk5QQmzJ15L6y4
FvIliCLoBnGuvv/sS5/5piLHo4qRF9kqqqUuy0Cumg4SI4O2Toshtg==
-----END AGE ENCRYPTED FILE-----
recipient: age1njap586hc0q43kr03g6c8eqhdsmk8zcafkl3f83xwlc2gqhlmfgs4tmwad
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGc3cwNzk1d2xDajFqQTNH
QlhoS0ZqWnJ6b1NoU3EvMlFsTG1oYkVrYTI0CjNEekFrV285aVc2Vk5pc0VHNDBO
MndVZHgrbE10TXVOL0I2Y1hKWEJCcm8KLS0tIHRoa2JtNHVLU1YySmlXMnpsY3lh
R0NTR2szNVhvVy81bHRjLzJSTWNWMEkK26wIFqhVk1fYV79odbslVaFxoDLykRNN
ZiOkWewH/JOuIXR260UWAGq4bKXfnUs78mAchh9R2I0F4p/CjGMdQA==
-----END AGE ENCRYPTED FILE-----
recipient: age19gfn2yedg76dmztm4hncr7vf3r3c9j0qpt4rap7y7gersjk4m3ks2lhd0e
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVRTE5TUNYWUpxbWdIenB0
WVdlMXFWK01vMndHTDhRdFppRC9MY09xeFZVCkhEL21Pd1pzcjlKQld5a0JvMjlu
QnhXNDlETmV0QXJ6ZWhzdGROZ25MQjAKLS0tIDQyclo1ZWtkM3VNbjJ1dHhTZXk4
OWRVdXZEZ2pEWXJGQmNaMm1aT2l0aWsK43Oc54CGekbbBkcnctXnUMyqo8ygmBL0
BMC6FtUVYMkP++Y7KFR6sudMemf9f+FbsCVRqBd9x+c2YzzgyH8ogw==
-----END AGE ENCRYPTED FILE-----
recipient: age1ll6hj5ggruetgjwjfnplpn5xtq35uhlcdflksx3xmnjm6s3uad9sz70jkf
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEaEtNL243bFF0am9HSkZp
anh1Ukl0bTJVUGJXUzM2NFo3Ry8yeTBVUUIwCktPVkpKNXBOYjRTMWNlay9Ia3Nj
bURMbFk4WUw3NVhUb25mZmtSU1ZRbHcKLS0tIHdkVEovUVpxMk5aVGRPMWdpaUdj
NzdISWtmYTFBb1FkT3hTeWFnaFJWOGcKdcLL3/fAgDME0Xsx7lS4q1boG8t7no3T
BZ6kdHnWe7fdzoTrCsaxWZPRom1hs10FZ4H+VI+CiEKki0N2XDMB4Q==
-----END AGE ENCRYPTED FILE-----
recipient: age120le4a5l8dh3lyfgvmj3d9ksmej6ajs5mer5y7r0vfg3x9fn69dqf8xgzu
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQTkRYelcvY1VEcThELzVo
a2E5QVNnME5VMU56SDduVlZKQUdhaTlKY25rCllGRk5GZlJMb1c4M0o0dkREZFFt
MW9BcDU2MkxWeHVESUtqcHpWMDRzLzQKLS0tIFZSU2J0RXoyQUxlYVNUa2t5ZVhp
bEVlNURjeGRvdXkrS0N1eDllV3lJTGsKc/4cEEhEJwmLSxUDFzAMxD+7TWcOKNjD
+Kcz2+sX8sTXLBLCGABR1XQdy1aejVku4atujnDOE6BzYjjfkRfc9A==
-----END AGE ENCRYPTED FILE-----
recipient: age120whqj96g26lsgy4udvgsn8dc9lumh8jeu3a564fx79rjr5lxffqmrljuu
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGa3RDdTdFK2VxTGYvYm1R
RlRkRFZqTWVXSWRMd2ZjckV4bXZSWnVXYmc4CnFTNnRQSFJORWdlTGRUajNjZTNL
SkhjdVhFSGJHZ2ZvRnhvaHFhVXQzek0KLS0tIDRXUTZTU0Rlb2crTWd6VDV5VVcx
Q2x1TnAxem45RXordHlqYy9CRzBzTlEKvKncXgXO1rJcHRXJE//7YbnwqCx+472D
XXby5thGhzTSTgcNcakyK20fzNlOYr3D/iRA4Ytcd0zHcGlj4qVaQQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqR3VsSlJMWFR1WHBwcHEz
blhLLzBoWEcwL0hVbkhJY2duSGxzaU5LVERzCk1STEZ5WExsT3o1SnRQSzN0OWh5
SjBaRkp5TnBkTGhZM2cyZGNZYmRydE0KLS0tIEx0ZU5PdnhQQng0OU91SW4rcW1O
WkRReU9DTWxLMU1XR1VSNXlZV0NGbFkK23aYRtL2n8L9OOSBJDKHKY63I1k2MxDb
ZoUiB48q379xc89KpI6uV2DNV2CpSUr/S1YI5OWRzMJmf+aYzJmikg==
-----END AGE ENCRYPTED FILE-----
recipient: age10at8862478urh0eeuwh8hzln6ck78jgwtztgxatwqlzwagg77y5snm4xzg
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnMVZiZUNob2pqdTA0NlJ1
UTdGdlNEVW5YOHZaYlZFZy9YaGVoV3FoR2hzCjdwc2F3bkVaUmg3dTZ6b1F2Ymwy
QkNvb1NEYnhLUkgxUnFYb0R4U0puZ2cKLS0tIFdrbktMWTRSQS9DT3doY2RaODJL
Wi9YazhEZzZFVXZpS1k3SE5wRWlLdzgKnlng++3X0NvOvl3qES0J166pXGM46dy8
38/RE0rjc+92+JnOXsgBUfvmS0td+oR5T4lxGpdngksv6gyPaU71Pg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBVYzkxVy9La0RzZGNHVXFN
MWUrc0RmT0NCaC9TZkFtOHBsV0ZtcGx2bVdvCmNnakVmL0xReXlMVkp5eXQyK1pr
aDFGemFrUVBZUGFwcjRVT3JTanBWZHcKLS0tIDRGZTRJY3lmZnpqTW5HRThWd2FN
MHhudjM4eFE4MDlIWTZoREp2NlgyZ0kKCo6/D0nchgDt8m/+idPRnjGaJoNrlqFj
5DwysBa3WPDTqeJ8053sMFGQWoYVEaL916B6zo+ZC34pPeKA9UuPsw==
-----END AGE ENCRYPTED FILE-----
recipient: age190htw7prp4vln076dxjx3gxxaq06h0zl0te7cqgpx79vl3lhkaes8suy05
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLRmpiOTdKYmVJOEJoRFRl
bm1UcjhXeWQxdWhWMm0vQXgxWEg1VTREekJJCjFJYnFkZFFlRUM1MHo4djBjWC9h
YlBlUVl4R3BOelNqY1lPNVBINHFtRTAKLS0tIFk5QU9qWW1jRW90SmdXVU1naUJk
R1V2eGhrci9CYzdkQnRYTnAybVY4L2cKw3LFTr8m8OMmlVysBZbiMKKxaA7Nt8F4
CJEgkcPyQGOFnNen7UAX1ksJrm+3gV7ZL91VxzVvCdd6zScHlG0PFg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmUnYzd2lmVFdPRFh1b0VD
SlN2YjgrakRHRWFVSEFlWElEdGdOYTJxRWlJCnFRRm5lT0MydmVqTHduTlVLQTFk
eS9yV0kzVU1JTEJQV3dXOXVpcy9NSjQKLS0tIE56Q05mSWhVUWMyQkVqUFNlbm04
RUhIN0MrcWlQMERxa3M3RktkTW5HbVEKWzTl19inKF3wf2SrVDecFsth5PPjKyGi
839OP4IAMoM0GPOkmHk35sxjr/34hTpk5mO7yu4nYH8rOhMiSTZ9ng==
-----END AGE ENCRYPTED FILE-----
recipient: age1adur9g330gua4l6ndk8cqjg35qc8yxwgme6wrl2hpylcc7vxm38q05ejuy
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5Y1ROSGlLcFczdjJNazFE
TUZJVmg2RldsT0pQdlZrRmNNL2ZibXNoZVNFCmZ0TXN6ZTJ6SVluZDlIVjJGSm8v
N1d4T2VHZEdiSVZ4ckpCY1pRQlFDcjgKLS0tIDAySFJGVC9kM1hVbEZqUUdqSHhv
YUFUeGlCcU9GMHAyZVBnWlRDSm4zUU0Kw6c8zMdxGwpNlukkw9ECT2aXJW98qNh3
wjUXDzmXNk9f8LNvj67na/JvsqXR4yxXFsEQkphAm6DvLkZ+5BfJiA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPL2NrbFFQRWlnVnFLRXEy
aHk1K0VCZjVKblk3V0RKeUxLUEVianB4dmg0CmxUNVVoZ2tyUE1YQW8rSDdGOFQ4
TmthK0pRU01aOEtmbUNlWG03R2JyUHMKLS0tIDlMbGhKSnlsL3BUTGF0YlNjZkZx
K29odXpLQndrdDAvaTJRSlEzWUpSSlUKq7XBK9MV24UhTgahxVKADQCPyS23UotX
dPkobMY1PzIBx+yeepCicCMaFz4foX7vA6+HEtbpzqP0lqPy7N8Jmw==
-----END AGE ENCRYPTED FILE-----
recipient: age17e89ty6p0fw24daanen57wg8uald9s025t3wwxsw269svwpmgvrshfvfvt
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBzQ0trMEVBcm9RQzFXUUlF
ejBOYkt4ekFWcmxub2FETElidzI1SXZCZ0JJCldEczV6TGhzazdiOWFiWjVObU9N
NWdDOWpHWFRydHo0UjdzdHVYZ2pIeUkKLS0tIGN0RHBTbEUzMDVnK1Z3UGVhZStW
ZXJiQmhKYUtSdzRDd0JGK1h3VExoc0kKM+tX68bgbAgdi1Gk3MeW2YXwmmszGEeR
WCrKI5hkBU6ZaAMF6LU9idvdUqFCdJ4l8up5WSQuO+10a0pvYGj/Kg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1TTFSVVo4R21sWmZYaHc0
ZmFOYnVVNzlrVVRPUXlRVGUxMFpKMzdnZkZNCllZZjVxZ1dPZm1uMzUzc0hEMHdK
U3NDTVlHMDVPOVVrRlVYUTZ4c0RUR1EKLS0tIFF4YTJzWE9PdWYyY3IyNjdsdnor
YnhtSnFvK2dPdGNTdGhMdmcrb05jamMKhO+Gdv55WhJTRr4ICOzG4lVZlxF0xZKq
ksmT/QIZHyZElBtCnLNTC3n4TWoJzywv0kjBLksKP9gZwmnx2TniQA==
-----END AGE ENCRYPTED FILE-----
recipient: age1hrx8qj02fj2ea6d4g9vqhyj9hl7fppkjqfdx2l37py3h6pdkr95s8n8rvs
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEYVRwdE5vVjBKczFBY3pj
Q0R0ZDZkUU43N3Rpb3NCTWg1czFrMWtrWEhBCjlONWhjWWZISy9oUS9pRFFlNXlZ
Ri8rbEMzKzV3R1NvN2orT2o4ejNPYlUKLS0tIFVDSXZaaGxMSWRpTmphYmRuMXpH
US9qYS9MZThjbkppcXNQUFdzZ1hDUWMKa9UH9GgZt8UD+TWcR3jnkNsVsfOlWAFw
cgh/gddnKu8lTa+9g6P3gi85/JhNqt3Fl4mmzk1aU0RjOIadzPWs4w==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzM0prUHBQTDZtcmw2d1FE
VWlyemZKSFQ0WHJCR2s1Z1pNTDEvalQ5TzEwCnpuWGVrUzRTVCswY2laVFNJVVND
WDh1MnhldWx6bEI3YmZOWGs4Q0piM1EKLS0tIENOOFg1VkJQblNKTjU3NVR0SzhN
cFNReUk0WkllbmFiMmFaa2pzRHg3ancKZQ4dCV9UxhiILsPEupR0RX8sPVMSCtcf
8KnCjjer75cHlYijqnz9EvQb5ywm04qoUv35szl3Miq6RTudRohYcw==
-----END AGE ENCRYPTED FILE-----
recipient: age1e7l8dusgmgfzd2cxrrzwepzjxt69hzqj4epee0cs27u6yg4kxcuqm34ncx
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1SXpOLytMRGtzSUR6aE9S
NWpIZ3RhRElIN3dTKzNrZWoxeDVTK1Y5eUdJCjF1cVJTWnFKT2RGYkNOQjRCUm9P
V1pPSlhQaDFhWXBJV3FMSlp3N3FXVzgKLS0tIC9PQkRrZ1g4YWMyaW9zbGJ4V0lw
VDJneWs3NTJoem5oWEZFVkd5YlplQ0UKFXMBfbrVMyydpCHRaqmkYOS/+CufsDGN
69Whneu9oXKGnbrFN+ikh+2O48VLWr9DSiWb0QcIagkNlxXcV3Vd+Q==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5Q1dQMHlXQnF5NC92WFFC
bjgyQXNrMmE0L1Y2TVBIV0hGQ0lKbnh2V0EwCmxpeVNWYnFxRHcvUkpmRUJ6WUV1
cWFGK1ZmUGNOSGYzaTg5YUNLSXA2cm8KLS0tIFk3R1FWOTRYSEtleE1yUGtKeGtX
T2x5YjByeUhPTndEMVlLOTVKTUxOaEEK5MzNnIZvfREU0R12PtbD0QmpLD4EtQla
I/+c95O2YUl9sPS/OnaMETsV2PqHhI/dl/ZSzZcCYw3yfRBjFGVdBg==
-----END AGE ENCRYPTED FILE-----
recipient: age1jcx3yajjhghn8qh8za3yeu8nxykzlg3p4nrv03vnfvzl0mzayg2qmg940e
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEL0d5NytCUzNyV0k5c3VH
Tk9FK3FrcmdGVDJmN0lMTTVoaThJbUUybVhjCmVjNXVrdGp5SXJ2czVPa095cU5j
YUo0RXNXQ0dBQmlVOFlGZ3dsQTJ3MUUKLS0tIE4welZDbDZ5OVQwNk9reGozSG9P
Rkdiazg1ZjBmZVlORWtGVEREM0F3em8KFqIg8N82g3E8irYf8Zw0OtLWVH7PzLmh
bQkotIzeemREJjA6Q9mIxojG1mD4DcexIBSkBAhIH6vM8Nksa5H/xg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBPWnRuSnVrMmRpVWg3SjRJ
OHJ0cUZ5UU9KVnhvQ042UXYrdXJYZ3RSdVh3CmtIWHlPbjB4VXgrazc5dTNNcFRG
ZkY0ZUpsanN1bHp5TG4xTngyNGxVaWcKLS0tIFV1UHUyaXdpWDF0NHpGVUd5N0hi
MWhDVGpXeWRoeVExckI5OWpWOERvSnMKkVzGUKoOxLkT3PnQupfI6PhP/WIrUU6Z
7YICeH+mmTjJLaDn3ZFn0KAQKlFTeR2rejorNN7B1j/mxQmV912whw==
-----END AGE ENCRYPTED FILE-----
recipient: age1sweerhrga9yf8x6sv0apz4ed4g48rnlcq34rpv20t0rcelwgpgeqwvndzz
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkdjNHQlpCd1RJWFg5WkVY
NDU2TFA3YnlKekRKNkUzcmYrem95SG1uWXlrCkFpSThsdjNDSzh0eFpESVNEalJY
QjVlVkhQeTB1SXVpT0JvNWV3VXJFVFUKLS0tIG5SbWp1bDhDdFlvWXEvMUhxcy9R
KzBuczlWZDQ0cTFFb1dyVEpidjR5OXMKUXPeEpeoxb5egqBBI8auM4MJzZ3RbMrG
0L9Y24zY+1i+QIM7WIlanYsNyhrRMHy1mXBjRHs/ka7ibyO9HUSaBw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5TEZlTU9jUnRNaXZZS1lG
L2o3UXZrajR6R2RjdXVkZ1FHQ0FtbUMvS1c4CmMyMURXZm5KMzh3RldMMFltejRC
VHBFNENCOVJOMGE2T211SWdUbTBER2MKLS0tIE1FeE5kb2VrejRoekt2UEs3MWxl
Q0RFbGw2L3FDUUVYNzdFV05lWnRGeHMK2EKY/HQ5RCTBpsifVrjlvy6i7F431uRV
zUgs4U3G/KB/MG9kxQsFmlRy53YA7il0n/0NnG/s4hvb09+6gD8ZuQ==
-----END AGE ENCRYPTED FILE-----
recipient: age1f7usptjx9rv4rxauasve200gxtdt9jkqhhdqstlf20wvlm7u75rsjfw50m
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuMHVoK2VEYUZnNkc2VnFN
ZVRxTzh5Rk0zQjRzT3ZvcG1FWnBGL1k3Zm5BCm16amZ5Yk1PT3dBRmJEMzhBdlRK
bG5hMFdDS1owZ3lsMkJhSmZSc0F4S28KLS0tIFVhaGFCd3dUaThFYUZYT3hGaEJD
OE92TnowVjN1OTl0UVE5SjdtNFVaMmMKGcM0fE5+iL6Oz9pHCCMlpOwwQruAG2Ur
SXu4gqz4vQNZlmY5o3hQi9zmZV4OOlKhwmInc+5vE2ypeL1/zNBX8A==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvTVBROUlXVWNKelpIOTBW
WUp1OXlyemtwRjd2V2lwQUd6WmZ1ajJucGpRCmlTVzhRUjZBQ3Z5SU9IMmZGZExw
YXBOd25SOVIrd3JDK0RZMXJ2NGdvVDgKLS0tIDJsaU5aN0ZnQjJRRmZsbVRpN2c1
VUlKVUs3OEdUU2FZYlJYNzE5OWoreFEKdDFkQsdwOeQWlaODaH3ZiuOjfZioGi7x
elq4NKp9iS+1VgZ+3pLH5Ev9vPquBFyB1vd97Z04HBA8+S6tyR8PZQ==
-----END AGE ENCRYPTED FILE-----
recipient: age17jqc66x9yeshfgd9v78mj483r4zzarqdtuxtrkxe4x5mw679gphshd94th
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBobTM5QWgyem5uUlBybWVv
RE1jUGtlYXdZOHhmMFlIekpvVWNxV0J1L0RJCjhsTEVBY1V4WnhGUWNmSVJNNFor
OVI0bjJwd09NMkJkU214bnRFQVcvdzgKLS0tIFpIaWhZVWh2TGFNaG1aMWYzcDFF
NFdMeGdBTkxoWTgyeUdxL1RqTkNSdEUKb2tuVoaqRY+B+KgsbfCnWwi299aVSH/N
4GLnmC97DoIIcMF3NJbHXPyUTCCrJ142j3rXGrpATkO3IaeMTfeN1g==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwNGV3TnUvODN3VDdWTDZS
TXY0WHVUVkdPWTh0Y1V4WnJpSWRMNnhTMzFnClRJNUFLZG5vWDQ2TkxIMU1NbHF5
eXFWWEh6VWwxU0NjMm1vcWtYckhNTzQKLS0tIEJQT3N4dmdoZnBjN3BoNTNWRnI5
OUpMdzZBWTBLNzNZWmZ4dEFqdkMvbWsKZHjMAHVsl+HWUyl8G9eGWYDuaA5rH5fg
7tia6vmmKWaVbDtvr9ARDcLr862kvMkMWg/R2/RP0w7sm6HPvzU+4w==
-----END AGE ENCRYPTED FILE-----
recipient: age1px0h5l9zp2dww0m8fncrc82kfdmzplsfv2ltat7sna28xpg09pqqcl3s2k
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpS2ZqR09PSEpaN1FYSXpm
akl0QzAwbnUrNXBFL2RaaythUU1Td3FicWtNCkFtMG9Ka05PSUpCR0hiNnpBVyth
TXNLa3Z2L041SEl0bjRzR2dRWGZNVDAKLS0tIDcrV255cVFRTXJ0bVcrcVRFWVdZ
WGdVNHNIL09tVS8zTSs4VHp4dXdoUFEKkXqeKKwQ8fp4AvIy5Mzf/hD9IO3NgAw3
70TH4YjCEiBpd3Q7/+iyB4yBYCayJ8U+KjC1Q8aTLQEqQKyiEcheoA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUWk5TMVpRQ2lxWGRSU2to
WUFVb1JqSTBDMXpwTktoRkFORmI1cHZXQW5ZCnFYTnlBSjNCM2NRU0JtR0lmbkQx
aU5qRGhTbUc3aFhObElxOVdXb0xWMzAKLS0tIGtrOU1DTjZBMmUvZVBlRy9qUGJu
NzJPM0hpRzVRcE5TSWM4R05zU3pnUHcKjxDRS4tmcVod0Zor4yC9+ogX3/DWkdtn
DpJn8g6pNlE+Dyg+NYyPKhzQjZue4bpPgnknU2rvvWdfOP7dlGMa6Q==
-----END AGE ENCRYPTED FILE-----
recipient: age1ufg390ydrmma849t9xfkxxl5xvdkk6mngnlzhmy7mvuaje8sgcmsmnq6l7
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB6b2hSbm02NjhPb2s3WDQ3
VkFuMVg5eVdoTmtnbjl0L05EN0hqVThXY0RZCk1STXZveTZSSURkNnpDTVU0L3c3
UkJNclhLcEdaMXFDaEdLZEVjL2w5c1UKLS0tIGNnME5mVWk3aU1LelJGb1UrV0xS
UHl0Z0hWYlp3b3MvN0FETndicCtpd1kKOMn31Y0XKogmJpm3CrIoqEIrwKqjZxE1
2N8LX8N7FJNQW3LaoyTok2hbe7KjhASlXVapDM8aozNouKnGv5h6Kw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIb2hFNFh2c3ZwcXVwbC9P
U1h2Z0V1Zk0wL3BmbUUyVVE4SnpTYkhCeWdRClRUdzJWL3ZqUTNxNGVxSXNSVjl1
NEpGWTMvM1VjNmtVQXhSL1N4R1UybVEKLS0tIDBaTmx1amtGdy8wTk5Ec0xjQ2JR
YTlqdWswSjVVY1FHdE9USng0bjc1bjgKFE4tvSPr+D9qTbRYsErzE78usjp3L5fl
NTgjL4hBQ2KNs25bQKh8LMnjR3J5upcEsvI6dvu6oHxpcjFFUBXp0g==
-----END AGE ENCRYPTED FILE-----
recipient: age16j42pdc5dr6wnj7xayhkqdj2rny9u68fcqejs50hqq42scssh4gsnrrnlt
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvTGpYNDdYbU5qWkRJRVRu
cmt2MEs5bTJUV0k2QjA3VW91eDQ2ODVUWVRrClZORzJSVmh0eFNyQmtDNjMxMGZs
L1grblE1V2hPcXBFMHRIOERJL2pBZ0kKLS0tIFNLbkZRK2Z2Y3N2Y2hTSUgzcW5m
WXpCZEdoelo0SXNKcnNuMmg4cDAzeDgKtGn1ZDRCbrTdmzCn9st/61rKOvEZqCtG
0brTsCk21iWLzKrMsg/B+kNiPB9/bAhessFJ/TDqZPn9/DWZ0x97Dg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjTHhRZDFqWU1zNkpsek4w
QmRaSms4ZzhhRkVXQlg4allKNlU2VWVHa0hjCmNoWnVmeXJmSEQ1RzBQbXErUXV2
OFJERjZMK3JoaHRqNm9Sd2svYmFiUWcKLS0tIFpvY1F0M2wyRXUxYW9DdmJWOU41
dlk4bVFDN2ErM0doREdMY0xBQUh3NHcKZ9bBa10mawRXh7GLDD6Xt6m+E1X9i8NJ
mDP3no+kP0kejJ+H7WhxixhPeU7xOyQGGmmhj3OH0C/q9QORYlYASQ==
-----END AGE ENCRYPTED FILE-----
recipient: age1nruncs4l0ufk7yuc4des8p99c0alfndl0lhsws8tycl5pplfp56s30af5f
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyQ3Z6SkNyVW1kNWdHemZi
R3owRUViRVBFMFhXZjYrcWhzUnFjZzVkb1c0ClhZNWp5NTVpcitkSmlkMWoyL0kw
ZkExZ21Nb1E3TUtvT3BNdXEycTYwL2sKLS0tIE5MaEFyMEJnV1FiWUZxYWFsNkQw
czNCdjRZZEZIOWxXeFR5Q1kxQkNYK3cKLq/eGWojEiqYwcwvnKGxHLHFhvCGLqlP
rVu2LqLqmEkrblRas5JJ4cQg9wd9XQuxdTOT5GSFUtZrX+P7XTbhNA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1bWVSOW9HOHJuOTgwZlNJ
dzdJRHFzdC9HV1dBaEsreDJPVUpiU1pBQnpJCllwQVRUREFOSWljU3pIVm5NLzl5
NEkyaUNrNlJYbHdEeWNsMzk0dVdocHcKLS0tIFJ2dmdBNmhjUnlvK1NQQUs1ZHVB
WGprcjRmZ2dTQmhIVTBXYXBXbEgvSjgKam4xywYDQsBGwsUKtwFUXwBFNYGQpaHU
D5ZGJk3hFwCTdtdmsI7PmB2AVD7HChc3RatPUtQEZg7/Ko9zeLzb5Q==
-----END AGE ENCRYPTED FILE-----
recipient: age1k7d2du5mejsmv5rzavm4xwgpthqvcfsehduquv28nzs53zppa3kqngfxq2
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuUS9MK0hsbytBWTk3bVdJ
L0xiT2xhUG5UU1dtOXBlMVg4VFVZTDJkZVJrCk9leDBtUkN2bnBUeE9BNnY1NnlF
TVVHdUowY2pBZXBIcnNUTG1aYllwUDgKLS0tIFdpRnVZRGxmK2JYeVJMUEtMQWxT
cnBIanpxYmQ1U0U1UXdhUS8zdXRkTVUKrEoNKzY3DXyu547GmbSsXVmIDvIoNCi9
hqVSCXG1r4t/tKfVuNyUsBDzfboiRgH+5gNk+h4hxmbI2w472nvPXg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5WnBaUktML0d1Vm92dFNS
dDlHNERhT1lJMUFxWFp5ZVVvNnNILzVUblNrCnEzV0w4VmRtTnhQMEVoTDFGUy9W
YUFQNStRem4yRGNkU2VJQjFES1o1aUkKLS0tIEpnODFzSDFlbzBwVXMwT0toT1lS
eExqVHlQUzdzcWJOZ2k3MFdrSVpOemMKP+aBvhLrfBd0FCeZF89hvhjXMj2UYijW
w4Yta4Y/8X1zHaI+FyG7+IvvAcQAXrM3MM5ZqD+VaVdiMUfxTFJhYA==
-----END AGE ENCRYPTED FILE-----
recipient: age16kqfmvz4e23hmdlqresnyw69ej604s320mmd49h4hm3fhqchtgyqrws0k2
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZR1F4Q1JBa2pscXVKTUli
eFdDZWdsYlY4cmQ1ZFBreXJDOW9LaW45ZWx3CnA1MWJYSC9ucW5OT3VWQ0w1ajR6
eUN5eE4xUVFxdGNEakpQYVNuaWR5eEUKLS0tIG53RDIwZDVDWFd3ZjIwd2laK3JQ
a0hRZERlalBWTXZoUm5lYmlYR2dGdFkKIbB5cuiUOGGmZx5QxuZbYeUjNORT4pKa
ASvNnGv9aM5uJebWLhhO0Kak3dM+OxP6+tt1/MNNP1LxUqFPJuJdeA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwbVNzTlZ5MFF6UzNmUDBu
T0hMMnV0QklGZmtpb0xaNGNkTExhQkVlWDNZCmJYWmMwN3hpT1Y1MnlDaHllZDNY
SDM0OGkzcEd1UW10VVl4eTZXcnQ5TUkKLS0tIFIvSDhFYkhvRmdNNWExMllkbGpr
L2hYV3FITFZyUDhackhKOERwalNmbk0K6gyoVY9p7RKLMHDA8rPrA3aCLaQJgWE3
9cXH6IQSxvSOqHlcj0sNr4fVL0zY25IdHtQ07Jt2QYWoIQM6lmychw==
-----END AGE ENCRYPTED FILE-----
recipient: age1arhf2q45zw6wf2uevju4savp575x3m2tfvved5zzq3ay92ynua9s3cm92c
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxb254bVQ0OXQ3RDNZMWU3
aUhLQWZYa1VobDdCbHZyb1JFbGRBNHBQUkVRCmR4ei9oTEhQSkhUK29PemdRbVNn
elQvN0UvUldnRmRNZ04xbDlCL202WlEKLS0tIFdiVS9maFYrODMrSU9aMFlXRU9U
a1BXUWozUEF3YlU4RHBhTytEVktTNGMK8KiRVfHfgWojDSS5k5g+NuIIFZSucBOc
PoZNWFmDyMmL0IDvTYWS8lgzgppgjSXkecIGtTGmiiXpTxot05jLAA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1UlZpNlMzZFRSbkdrQXFk
RFB2MnVFMEgrVjRnV1AycWRlUHlVUmw0VEVZCmswd3M1dkZQemIzVDNheFVac000
QXNWcjA1a2lnSjdHZHFtQ0JyVzE1RzAKLS0tIHpWNVFqN0kvMWVJVjFVK0pvakVM
SWQvNU05b0JUMXU2bVpGdTRIWnBjcUUKtnJpK0MhUi+OVnqXvD9a/oNvMPH556gr
Xn81BdmdvILoHmPZB41Z/c/U5G1fcf+GRegL+yALOILdHaPS8w5Sfg==
-----END AGE ENCRYPTED FILE-----
recipient: age19mn8zrxl8zpps9yvrh4euquvygpp4fp8queg7xc6qhtnl4ng8c9qx02qwn
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMU1ZFRVpld1ptM2lnYm9u
QmhSTE95ZUM1cVJUV09sdVhTMGVtRnRpb0JJCnFucml1RGtxdVJCOE0xUXNXeVdt
VnVBYXFhVUpGamhCbWtySnhGeEtKNU0KLS0tIEp4OGRGYXR3WHhNZHgzU3hNS3E2
RVpSMForUGZRS1dUR0hacnBQQ0dLRW8KK77iAvB2e75eGPC587lCBic6HaKypnnn
HAbjBkl7ZwyKWpyR0pOTNauHWh2D8WDGjc2ciGaI7j0cbNeTdzCyAg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBNTEljUmIxZlhJU2YzTC9S
Q0ZQSEprZUd3WUM5bDE2OHQ0Z1V2bmc3R2dnCnU1eFhwWHNDN3hERkh0T01oZUl1
RG8yYnVFUTFYVGQ0RFpxZWdQdjU0WVUKLS0tIHFoWWZRY25BWGJybSs0ODJzN1Y0
dDJWMlRWVGdIQnovdit0Nlo2LzIzbk0KoNio+gOJ4SJHxBKA7t1v9DD5UTNoJGu6
x1/qXwh3SLFk8sirYewwY0FA8Z6XE7qq0DBTL4OjU/5IKYNOVW6Xsg==
-----END AGE ENCRYPTED FILE-----
recipient: age1jlltcv5jcnm40z5k0q6hv053k2rqpqvemtuecdwn527uw8uqz4es3x7m68
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTTUd4VWF0bXZQbGFKSFg1
K1ZsYUNlMHpSNG1WTlRxMUJmZ2I1aVNHYVY0Cm9FWGZDYnhhdXNCZUxJZmlZdGh2
ZG5FWkJJUitVMDc5L0Qza0JqQzBsN3MKLS0tIEYxanNSakVud3c4NHRyZlNnNTVp
ZVo5TUVXcFYyeUk1eXZ6VldWa2l3b1UKCuXfXW12E0ybEmADPBsuno9lUH+yZC30
buTHSyG2WUpV2J8Om0uxUrnbGXKLUhdjUut2OijAi/GQP63CWMNlMA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOU2ROSjNDN0lOamZHYjAw
d2tKL3RFRmtHKzNuQ1VXNUNZY3E5K1R3blU4Cm9QMng2OXFtWHYwRUxieFFHK0ox
cWRzdmFOOENyRnB1Y2NoRUo2UGkvZTQKLS0tIFU4b2hoeExBV0xLemxIWlpURkNa
N0VHMmtBT3JPZXF2QVFyUE51NjhWa2MKGCZK5saQ0RdbTUx+itnFTMKNj4VE59H6
FDGOVdWRne+1PA97Um1oNlYuoaUuyCtwCfOwz2iEi4RGTVPpK4ntyA==
-----END AGE ENCRYPTED FILE-----
recipient: age1ug787sgt6st6k82fgkrug2lzltw4qsukrrqqs3w27ewwqj8rg4hsxcmylz
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhbjAzd1lOM3FaVGxIUE5Y
ZENGZlZLNVZsaTg4U3MxQU9PMTNhTjRVY1NjClVVWUNUaWY1c05udUJVOG8vOGJv
dXFlZUxxQzlCaGgwYWp5TmtBbFpiNzgKLS0tIHJSMDNMRG5ONzd0d3hoQ0FLOU93
TW5HWnBRTXJwN2VjTllqTVRBcHBiTUkKcI7du8jo9LWLtwnsDFyec+fn4w6zWyaw
r7m05cm4sKv6xDPMZrGNlwRziA327qn8/7/xB+Tl62+eECaeIqLUUQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzVWRoYUVtY2hWMHZtYlpO
b3JSSFIraEZXRGd3YnZGc25VenhlYlg3R0JzCkY5Mkh5WlVuQnVSZ0trakgvTGhN
TWVVK0R5WG9HWlJ0NWNPTGtDTFlNd1EKLS0tIGhKdG9hT29qWlcvL0UwL1BOcFIz
OGpjWTZDRzROclo3a2toUFhBRnhscDAKYnwkQ4H9b1BdFNgG2pIl9Xo7skpn5+HF
BJB7wfYi6IoDbj1gfyFf1NmOB2gX07xfRcmIGfkq+I2/cHMhsXTMIQ==
-----END AGE ENCRYPTED FILE-----
recipient: age1529taqdwr6t0w7cvzmty0d5y5593wffl0krt48j6uc4u39k56g2qf6ywtp
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArSG5nejgrdDBBMnhzYVpo
eENwVzA2dnlPZS9DaXhBa25EdzArS0VIbURjCmhiYUNMOXRHLy9xaEJZZExRanpl
dGhiZzlyN2d5NStOdmZMWnBhbURQNU0KLS0tIDhDNFNleWNsK2VITHRvRVZKb2xs
NjFkYzJKdUFFS2dUeG4reW9NWlkvZXMKkUob0p2OZXPgjLJ3MUto1tiJTUL6iyFw
uZZKNG4C2phTb9Ry4+wvKb5PakAS8cmoBFRcVz0p6EBsl/yxbwcEMQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5eXFZUy85UlY5WW1qdktj
ekp5WTBFMjBLT2hMSVlzK1JGYno1bXd5TlNFCll5S2lqSXB3QTFYVm5hdmFUVDUz
TFVGNjh6VWJzTkR4TVhuK1JSaFhrVUEKLS0tIEp1SkFYR2lJS0VDSUw5bXRRTXht
QS9DaGs3SnRHZHUxREtmZm9TRThRNWMKCsbgErz3ulxAasQ6IfmWwWDTS33RSFJv
WiizvgQmjpWx8JFDyxS+eNeU0KQMf8TdI7D05f2ajkao+A7YmIAGNA==
-----END AGE ENCRYPTED FILE-----
recipient: age1zhfyuzlq40reuqlr34gf77852nhs3t6mqfzrqmas8z6sxk7tcfhsungrm0
lastmodified: "2026-07-23T21:15:41Z"
+20 -29
View File
@@ -4,47 +4,38 @@ sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMWjdNblFJdUpyMGFrSWJm
a21ESTZTK05YNk5CWFlKNlhIdXhIUFhQNVR3CnZZK1N2N3VKVWs5ZGxZaUhCb1VP
dlJaNXM2alNiUG42NlFqeVV3WDdtbnMKLS0tIFpvTlBZU2RpNUtoNVoxeUdKU2Zt
QjFydW1xeDd6N2xBU2lhRmtuREhkNDQK49/mcHVCj9tBtGe1ZnK14YWHCtgzBBvV
giDA8BzThifXjWtL8zF60kibKFVRGrsRZT38tRuv5QKzu6Z5Cbc+2g==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwMklZTFJuR3NYbkFvV0l0
eUhMWU4vMHpnN1NKVThuVVdiOFpkZW9rTjBVCjJabWkvOFpOSm1hdEdlZTYxc3BP
WkRURDFEQzMvRFlka1VnaU9zRjhiSEkKLS0tIHZXRG9GaE5iVjg3M3I0SzhtN0JP
UlJVUzRzN3NEZWxXZHJ6RW1oYWwxS2MKonnhq7YDg4v93PZtoaLANDy8mdRCenjo
FjRUzozMLpgWBll4DwRWikejsrRofRBwlcsiIdrBr90f8Lr9pHdQ/Q==
-----END AGE ENCRYPTED FILE-----
recipient: age1njap586hc0q43kr03g6c8eqhdsmk8zcafkl3f83xwlc2gqhlmfgs4tmwad
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkZmtLL3pzbmNBNkkzRDhF
MFZrS3FlZ3I0ZlNJbVN4aUpxYkQ5VkRSYlRjCnUxM0tqRFJDMis0TDd6cUthN0ZE
eTBrSDd4a1BzNHZqZVJIc3V4NzBoeGsKLS0tIE9ENFBWUUtadC9vQ1UyRmFLWG9B
UUZLeThnUzBNRSttemtuaTN1NWlkUVkKbDeId9JVSvjszcA0TT4L9C4IB5xLCuJK
ESqfwJe7QoTBpYA3RMmtIcYK3oYX9KKGrdUU0J+TV0Flr6wqHBHbOQ==
-----END AGE ENCRYPTED FILE-----
recipient: age120le4a5l8dh3lyfgvmj3d9ksmej6ajs5mer5y7r0vfg3x9fn69dqf8xgzu
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4OVJvSTVkcDdMQW9HdXcz
bmVOVjQvYU81MExSZ3NtUzZTNHNRb1VjNmljCkZ6bDN1OGx4NkhGVENOTjQxWFVy
QWNNbENkMVpOTS90dzFWalVtczZ1YU0KLS0tIFZSQVNkUGE0TERyQ1BPTjVQUEdN
Y2tFOXlkRHhGTmNWVDZWRnQ5dTNTM1EKNEZZqO6mmj3GnJJ0/8UrisHODEKPjyah
aAi5rMnEDAniqyouTP1Mq3GOn67KoESqZX4qY3nHvJC7QBIDii3sBg==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsWDJQYzM5Z1JRT3FlVkJy
TkVaSXdzanYwbnpOM1d2RFh0c2NaSUFmdW1ZCit4SVFxSS9HNXhVM2gveERGVS81
NVFQaUV2RGR5Q3kyUTQ5eEpDVXJVMWcKLS0tIHdHSy9WM0o3Q0o1THhXZW11K2Vp
NTNtSGM2UDFuWDBEdS9tbTY1ZWt6UlUK8z5qoi0kGn0ES3m9khummuU51rkR0Sb9
TWT92+BWvPdNrAsDFjv0fgpUKyTMzN72EzHZKAJCIM3crUG9I0tX2g==
-----END AGE ENCRYPTED FILE-----
recipient: age1jcx3yajjhghn8qh8za3yeu8nxykzlg3p4nrv03vnfvzl0mzayg2qmg940e
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5aW8rZG5MenF5RmFWdUgx
dk1oV3BpYmNGUnJHTkhOVjVVM0k1T2hlQkdjCm9xYXNkVWkrTWloWEtRcmRuUUkr
NUEyZ0ZFeFZ0M2dHUTNYdzFVQ2pDS2MKLS0tIGNnaXcxUUo0cGE4T28vdGJPT1d5
SnliakxSZjBNQlpjSlNJelVWVUJORDgKWVuK6VYN5BySdRLHLlU0Sk6PPAsz5lVS
Vw96AbKrmczhkiYUWGacde0KjBJb/7tyfXeckV1iqj1/6vT03dDNlA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpY3o4SEpwZEdFQmVnOTVV
d2NqL0VudHM4VjdDK1N4dWdlS0lGR1V6a0c0CmJUTHlsbEMwaEU0Kzdaa21lRFRm
RTRnTUlGUG9GQVB4U2pzTHdRY09udkEKLS0tIGlFQW9Wd0N5WFg2WUpCQzhWUm5v
aG1VVWV5ajBmc2o4ckgyQWpWaFVxVmcKisAw40bGQBRH+u6uNygfYpfb7iEgfEHj
E+g9n2WeVH8kUzD2O1o6VAu4m/SVuI4+IQ77j9GEWmlI/wgp8wKXgQ==
-----END AGE ENCRYPTED FILE-----
recipient: age1ufg390ydrmma849t9xfkxxl5xvdkk6mngnlzhmy7mvuaje8sgcmsmnq6l7
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCckVtTWtCSWpxSGFEbWI5
MkVkeTRYN1MzMEk2L1RQemRvM1RSaEVpakVNCjBsbm5qcDFlRXRCQXNkQTd2Snlk
WW51Sm1xYjJldmJ0R09WR0hHbWk3NWMKLS0tIGlWYk4zNElVQk9qcGJUUUptMVZV
aStXT2lVNXlwRG54SmhxV21tb2M3NzAK2nlgUrlarGERUClDvytMXwPO5e+zaIlW
T68ePI4e1vh2qj5xpjXoK5Pzv6oUcjhB0P7Ij2lA8bRdFLWfHPAqvA==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1elpNZXVJbmJWSU85aUV6
NG9YTWVBeWxiRHUveStTQnl4NC8rT2VNdHpNCldxZVJYNVhUR2V3Vk41VnJxenVT
WS9rRWlKcGpVdVJPakkwUTY2a2xQTlkKLS0tIFhFVTRucFNuS0pMK0FNRk1ndnFO
SlVvakczaktUa2VLY3RLYUdVRzFyamcKIhctg0mbYL7OE08dRwj5wMu2x+O8/BMu
IqA477+noQ/Rjrszb2hEvxID7keogcDUWMWQzQvdMc22+3mvAr9qIg==
-----END AGE ENCRYPTED FILE-----
recipient: age1jlltcv5jcnm40z5k0q6hv053k2rqpqvemtuecdwn527uw8uqz4es3x7m68
lastmodified: "2026-07-19T23:30:21Z"
+20 -29
View File
@@ -3,47 +3,38 @@ sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBxT3dteUY4T0VxaUljbFQ3
UjBSSjZCdWpmTGpDS1BabjV4R0lyOE9haEZrCjlmSXllWTB0L0E5N1MrTk1IODR2
bXZuamN3Yjk0THdka1dBZE5uS05DRkEKLS0tIDBkTmtpU1JoNmN0cHd0WGVseERt
eEcrOXdFaUNBQ3g2aytYM3RwM1dBd00KiSRrzv6eRMdIzZaUlC6JmsZV6rYJgrre
vbI1KHtNZKetx81+MmElIKog6kMtTPtI7MVpMwCCPO8zAU5Uh7jSoQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZeDQyNFh3dm1YZ2FTMjdK
cDBWcDE2a1c1S0s1enhWRnVuMlVJc0gyTXk0CmxWNkRJMDhkeGpRTGltaitnVkZS
a3Q5TW4zYm5Ja2FETEhJcGF0N2ZKbmcKLS0tIDN0a1FqRGNOY3Y1UWxvUU8zWU1m
bE9DVzZESG1HTEhVWUdJOTF0bDhRVGcKP6OoyDAGLB9jQ69jpFyho5eaeK9XtZgN
RlSJpBm2Jo19h/crpH9AWXUAIG0BWueyr8mwBu12cQdFIU3IyZT6gg==
-----END AGE ENCRYPTED FILE-----
recipient: age1njap586hc0q43kr03g6c8eqhdsmk8zcafkl3f83xwlc2gqhlmfgs4tmwad
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBmWUMyVGpua25ZZ1FRZ21p
a1lxdS85d2JzOXBLVC92MjlNbTZOOVgvSlhNCm12WmtIb3dQanNkanBCU2t4VTd2
TGFidEpSR254Qm5jTVF0WnprcjJWVncKLS0tIGwzRWZkY25rZXE4Q2VETU93Mno3
aGN6MmcvVkRGZkJQN3V1ak90T3BMVFEKLcEdqKQ3SStSdH5vjQ6RH+oA10OLGXad
TZE0h435sg/tq/Rff+KWngczFRuq7Yg0KYph8bNAKy6uf+RceZ8Ngg==
-----END AGE ENCRYPTED FILE-----
recipient: age1ll6hj5ggruetgjwjfnplpn5xtq35uhlcdflksx3xmnjm6s3uad9sz70jkf
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSMG12OTVwdFhnTkFrNmZl
UDFLcmJtL2FNejJnWlZYd093MlZmWG04dmdJCkhGLzNGcVQyVVp6SGdISTF0ejhv
OVRoQXNlSWZCWDdDMTM0YTFJYlRQd2cKLS0tIHJxVDVscUxEdTV1MGhNVlpWVS8v
aWhSNDh1NEZHYzRHeXZNOFRuRzBjazAK2RMK5ylm4uM55fXgrRrY+GeN86ym9wC9
JNDcNyxE6H/sZGBZJbFLWKDj+VM9X86j5TFFpnjSrKi2CPOzmzgmKw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAwRVFQcHpkQkNlSDhhM1Zp
bUZyOFduQXg1cDd6ZlNObFgzL2hmUmJhM1JFCnprMldPQXJNVW10dVRqQTdWcGlv
RnBYWWFsaVNrMkJpS0pkOGlQQzlJVVUKLS0tIFNsMEEwZTREZ1lwWFJGdE5YSVVU
ZEZ1bVpFMEQ5N0g0L2RacUpLMWQrVDQKxPzq6f960purgAmUJw6IZnZSnhkzNE8r
CSrFDowKTZI2KRdCtQ5fGhEoWO0ZPgVNxYV0KH7JBttylcpRLm6r5w==
-----END AGE ENCRYPTED FILE-----
recipient: age1sweerhrga9yf8x6sv0apz4ed4g48rnlcq34rpv20t0rcelwgpgeqwvndzz
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLRHdnSkFZc0NYYnQvd0Mz
a3dmTHdLN3Z6UGh3SkpBMGhtSHRJTC9SblJnCmFuOTJGSE5nOWIwQWRNV010RkMw
VnBJVXdtVm1tL2d2bXFWWnBtamVRVk0KLS0tIDNHUndvTnd2Z2VSb3dxVUFUcTcz
ODVDRzBBclhPZjJDYVkwWktMUENSek0KnTFdNMa8L5uPLvl2aJLvaZEUTbGwL+va
wLnWhf/bm8edMeyfWcpS2uHMSDpozWfqObrrP23LCrDBf/B7EG+TWw==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0czVoT3ZyYTZhOEQ3RWtR
bVl1MW5vNERxUEpmNXV0MGVBRE9ySnBjT3pzCkM2aUVpZjg0SkNVTnRRMlhyMTN6
NlFrZDVKV09Yc0tuKzFzR0ZtQ2t6WkkKLS0tIG1mbUNFdHBycS9UOGc2cjNpeHVm
NUd1NThRQlZXeG1WbmR5Y3pTYXRKc3MKwSnE+0bGmxOAQUje6jHxuzIIyD6ZAwVz
b5AAYwbGRagKj6fimsHBUmi4ohyG1huIGGOU8HiUYpu4PGJgOscztg==
-----END AGE ENCRYPTED FILE-----
recipient: age1nruncs4l0ufk7yuc4des8p99c0alfndl0lhsws8tycl5pplfp56s30af5f
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyeTJMS1A0eXJnQVcvaVEy
VEttdGdMcVIzNlIvclZESkJoTHBZeW1GUVFBCmhmRlBLN3lLdW9TS1JKOW83Yis4
dVBGNjdPZXdGYllzN0VyRGFVRFFCMU0KLS0tIEZqN1ljQ0s3TDJYWEEwWk1YVmFs
R1l1LzdHUDVvUHQwY1NtZUUxajZkZUkKZv1ejN+LKZqFqDRak5ktFaR3kMPCQeFl
q8/DHLFx+1IFChxMGkgstGGmkZdxG4khpYJJXAVNyQsyIW9bjJiqZQ==
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBlVGRDMWNDZUR6c1VpUjRK
WDY3L2lNcWFFcm1UV3RPMjlqYnBGVEJLcFFzCjFxck4wdlp0Wmtzc1RKNS82MXpK
ZHBzOGhkc3ZuZUE2UmpUSTgycWdLSGMKLS0tIFUyYjczeUFWU2FyMlBTdzAxMTBE
VzhaVzlSL05nZzNmR0ZjNEFPTXYycHcKfiJ0KjdxtLWsXxsWKzAL+H3hYYjHrYO9
BjKknq1ZQJM0sB/Tid+GLqDwKi966MQK+AwHF5MqbsHW7eE5bO1nwg==
-----END AGE ENCRYPTED FILE-----
recipient: age1529taqdwr6t0w7cvzmty0d5y5593wffl0krt48j6uc4u39k56g2qf6ywtp
lastmodified: "2026-07-19T02:30:40Z"
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAICuHUxGNH6ei3BZD+EfZs3l4X8uJNcjQiOsM/G4yo4O/ lxc-nix-cache
@@ -0,0 +1,14 @@
{
"data": "ENC[AES256_GCM,data:nm1TQswDfqLgzwOZTpllM96/nqW1xyOoUmbmxL3kEbygnU9kKruuijhoLMSigti8Cgb4onyI3OFkOaNnBShGaXsrFHwIH4rwd4CRv4mHLFTqs/hTXxMxo98gKdhJYuCLXOOdhWrOfOO0GofmxLEX12AUhjS/cxtJWXqINIbmOzPm0rHVVx56r6kj1MojGssV3y68gbioSF1StGG+OIQIXL1LRBWknyTJ+NK3aViXn7oBglHzL9D74Lz5v8iFQQroZ4sBPi+ov0CKAFaghRxl7T7jGA9pO354ZbLdiGmpqtYFazCGq21hwjpWyobAog/Iidngm9Mz0wleB1pEpkCaEpUsjVYQkAoknITasCGhwpmFH0F9v8Du87rJ4jdWT3W8qh3uPlCHw7e5QwQYE/I9v1HU6Au+liQJWeAbbwt9wRC5NMETCqH1PDDpRjt19Le2ECXjstBRR4b9wQQkeDefgcFibQK156/i2twhAqIgz+RqIZ05aQYfy8Kfj3c7G34PEdOdz1P3bsAgISVpgMQO,iv:Cth8/Wlf7vJo050aDNt1XyFUDiihyuMxv6WH3yEZGXM=,tag:qM1/MVU3J2Kso8w0fzEvIQ==,type:str]",
"sops": {
"age": [
{
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBqWFF4ekdNRG05bysxMGRz\nbkt0QmRKT2hsUzZWVXRxY0ZjenRXMXhrT1JNClE4WlRmU0grRG5BSjM5NWZwc1o0\nSFJ3dGRsR0pwYlJhRkV4MjJqNVFWL2MKLS0tIFBSVTU5aFVZNm5qZGtIU05XbDd1\neTd5Y1puYjBkKzlVRDVvaW9pL1B0R28KZbutmxm33H8qOE0jSDr+mrx6nFESmKLg\nTfjZBp1W0SDRVJfUbRQJvcp1ECMJIS5cWzXDoXmLnaeLFzawBPbIeQ==\n-----END AGE ENCRYPTED FILE-----\n",
"recipient": "age1njap586hc0q43kr03g6c8eqhdsmk8zcafkl3f83xwlc2gqhlmfgs4tmwad"
}
],
"lastmodified": "2026-07-25T11:10:21Z",
"mac": "ENC[AES256_GCM,data:IQ/XcH2boEt97exSgTUxuZwH+IwFHA0ota3Y15T9DP3tpN/Tvp4zWOqHYtiPfRf/Ea8Si/LDHwlVnuLIhFYtrMmTzJjKf8Xa+eN2bACzn1BAGKKkY1uQH2tIJ1HIxC08x0L7YhkGPVNMFcu2FsNB0bk57+iwUb/w5p4m5O4AZ6Q=,iv:/BkRQEGvUImCewxsfrpV+EYZVnfRlIChASpBXBAtppA=,tag:DAkApHsRza9DXOnKhhVNNA==,type:str]",
"version": "3.13.2"
}
}
@@ -0,0 +1 @@
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOAzES7wlgL7gIyxOHbmwhzI8SJ5uMSEd26u+ek6knVh lxc-tor-relay
@@ -0,0 +1,14 @@
{
"data": "ENC[AES256_GCM,data:Gx0ZxQ4OZUKUDFEPYjOEgTERHOFDYO+O36qA6h7+wp6G3ld4hTs4NhODdeCpz3xq7/EZ09Jej/ZZriIhiTUp7IjDIjR+hOsIWW7XQNUqBDfq/nO2Fz6nOd7ph1fgQfaSUvmUBo5qr68VmDs6ArnkDJ5TFNTwqypC9Ou/HXvKEvqfG+XjL8FT05ZG3iTqH68O73DlBhePhVuWby/8txyCL+fz9pXaqyFIGxmsMDE3d0Itveyi/bReOnf4g6UvCjnrA1nMpTB3rQLzVF0TvxfTv9XfaeV3On6eu8M+qUk9fqv0ytKS6+IcozuCax5kLMIGz7Y4kbw+yolgotWaM33Wu+e+UAZMHSksWAJAI/zqxHwRcyY5uEH8DJdqz6EtA06Yssup89iqMA4Nz88l+LpZ+1BPeY6PlhbubP+X1x34mbDixO8EguuUG908vd2jKi8f7GtYzDXm3ECN1iodiAXVJZ3TEGfYPfhvH6p9kSkwS9Jug1GVP5pDaPPkwvtsLjq2fV0HB/4qJQAkVJmwRz2L,iv:3sN+t1HvduJjlj+l0Jp9jqWIh0q1bwz4WiPPDLXyNzg=,tag:Qk3P3xoHoOhYQL3xzmJpaw==,type:str]",
"sops": {
"age": [
{
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBETjR1YzVoaUtGTlo4QnUv\nbVE4ZXZmMmJ4ZzFhcXlaVWNEWHAxVW4xSm44CmlOaEVxSGpKelZwTEFCcitvcThE\na1B5bVdDUk56L2ZMVDJNVkpJalZ3eTgKLS0tIGU5NUM0bDVyaVc0WGVrbFF1VzFx\nT0p3a1Z0czd4bTRzUVRURmh1MzhUelUKaaL1TewLGICnl/gdAFQHHBM/ik2qUjAy\n2dNemNJrMuX7Rd9DCZPeFIqNHRVX1sIhJo3/dC1UJc235l1NLcSsSA==\n-----END AGE ENCRYPTED FILE-----\n",
"recipient": "age1njap586hc0q43kr03g6c8eqhdsmk8zcafkl3f83xwlc2gqhlmfgs4tmwad"
}
],
"lastmodified": "2026-07-25T09:28:42Z",
"mac": "ENC[AES256_GCM,data:h/MkejHqwuJbc63HyJs8ki1aTt7bx7HVhsQCI45hHjN/WeEJxiZVcmHEXsL/dwPg/Q7H8OImC2sl6Gt7FtGwfN9O6JwYwl6BxBBoD+lZscgrPrNqp1I9u3KhgyOF7ziQhiWH2Lk3/OVa9kuFs3xYjcKxVIA+vW6VB54QkLNBcPM=,iv:BjtKnZ/B7RvWq1MBzWzudPGvntXnk9kYpzULTpK62EU=,tag:f71WOUHcjbcHHC7KIjHqrA==,type:str]",
"version": "3.13.2"
}
}