# SOPS recipient rules. # # Each rule pins one or more age public keys as recipients for files matching # the path_regex. The build_host_files.py generator doesn't read this file; # `sops` does — to encrypt a new secret, run `sops -e secrets/.yaml` # from the repo root and SOPS will pick the matching rule below. # # To grant a secret to a new client: add their age public key (from # inventory.yaml `hosts..age_pubkey`) to the relevant rule below, then # run `sops updatekeys secrets/.yaml` to re-encrypt without rotating # the ciphertext payload. # # To revoke: remove the recipient from the relevant rule and run # `sops updatekeys` (this is what `homelab client remove` calls). Past # ciphertext the client already decrypted is not affected — rotate the # underlying credential if compromise is suspected. creation_rules: - path_regex: ^secrets/hello\.yaml$ # The "hello" secret is encrypted to every enrolled client so the bootstrap # decrypt test works for everyone. Add each new client's age_pubkey when # they enrol; re-key with `sops updatekeys -y secrets/hello.yaml`. age: >- age1xkklkvnk5z0fsnh6cfgv70hy9ksfy8rdprwerzw4yk3p4p7cxcqs2yvpz6, age1duyl8mkpgu80uv934dy8q7enqjms6yvdz264hme8uryuxmvvqesq6rusq0, age1vf8h7s8mqsn2q5eadgpdupsj4mwn8zguc77d85ws3xj40sl9rgksx2rxw6, age1z62ff2ak9zj5ctcvaxwyyhedwjvlwgm2dkn9nk3wrwk8fkavcpmsqwc2vs, age1s07zs83ehtlg8jtwvr75ltc3c4cdlemfwjuxrwjtwkqxkl9tpggsyrzn2h, age1rtwvdct6avjkr3cyxv3vue3vqx4d524fjfr3vk7xrnvyrylnry5sm54sn4 - path_regex: ^secrets/gitea-pat\.yaml$ # Write-scoped Gitea PAT (dtoro user). Same recipient list as hello.yaml # since every enrolled client should be able to push (homelab client # add/remove, wiki edits, etc.). age: >- age1xkklkvnk5z0fsnh6cfgv70hy9ksfy8rdprwerzw4yk3p4p7cxcqs2yvpz6, age1duyl8mkpgu80uv934dy8q7enqjms6yvdz264hme8uryuxmvvqesq6rusq0, age1vf8h7s8mqsn2q5eadgpdupsj4mwn8zguc77d85ws3xj40sl9rgksx2rxw6, age1z62ff2ak9zj5ctcvaxwyyhedwjvlwgm2dkn9nk3wrwk8fkavcpmsqwc2vs, age1s07zs83ehtlg8jtwvr75ltc3c4cdlemfwjuxrwjtwkqxkl9tpggsyrzn2h, age1rtwvdct6avjkr3cyxv3vue3vqx4d524fjfr3vk7xrnvyrylnry5sm54sn4 - path_regex: ^secrets/gitea-tokens\.yaml$ # Workstations only. age: >- # placeholder — fill with age_pubkey of: republic-laptop, mac-mini, strong, hubris - path_regex: ^secrets/webhook-hmacs\.yaml$ # LXCs that run a webhook receiver. age: >- # placeholder — fill with age_pubkey of: apps, caddy - path_regex: ^secrets/turn-shared-secret\.yaml$ # coturn TURN long-term-credential password. Consumed by hubris (which # renders /etc/turnserver.conf + /opt/management.json on the VPS via # `homelab render-vps-configs`). Other recipients are convenience for # operator debugging — only hubris's pubkey is strictly required. age: >- age1xkklkvnk5z0fsnh6cfgv70hy9ksfy8rdprwerzw4yk3p4p7cxcqs2yvpz6, age1duyl8mkpgu80uv934dy8q7enqjms6yvdz264hme8uryuxmvvqesq6rusq0, age1vf8h7s8mqsn2q5eadgpdupsj4mwn8zguc77d85ws3xj40sl9rgksx2rxw6, age1z62ff2ak9zj5ctcvaxwyyhedwjvlwgm2dkn9nk3wrwk8fkavcpmsqwc2vs, age1s07zs83ehtlg8jtwvr75ltc3c4cdlemfwjuxrwjtwkqxkl9tpggsyrzn2h - path_regex: ^secrets/netbird-authentik-oidc\.yaml$ # Authentik OIDC client secret for the netbird-dashboard provider. # Consumed by hubris to render /opt/management.json on the VPS # (PKCEAuthorizationFlow.ProviderConfig.ClientSecret). age: >- age1xkklkvnk5z0fsnh6cfgv70hy9ksfy8rdprwerzw4yk3p4p7cxcqs2yvpz6, age1duyl8mkpgu80uv934dy8q7enqjms6yvdz264hme8uryuxmvvqesq6rusq0, age1vf8h7s8mqsn2q5eadgpdupsj4mwn8zguc77d85ws3xj40sl9rgksx2rxw6, age1z62ff2ak9zj5ctcvaxwyyhedwjvlwgm2dkn9nk3wrwk8fkavcpmsqwc2vs, age1s07zs83ehtlg8jtwvr75ltc3c4cdlemfwjuxrwjtwkqxkl9tpggsyrzn2h - path_regex: ^secrets/netbird-pat\.yaml$ # NetBird API Personal Access Token. Consumed by the dns-sync job on the # `dns` LXC (107) to reconcile Technitium -> NetBird managed DNS zone. # (When 107 is enrolled, add its age_pubkey here and updatekeys.) age: >- age1xkklkvnk5z0fsnh6cfgv70hy9ksfy8rdprwerzw4yk3p4p7cxcqs2yvpz6, age1duyl8mkpgu80uv934dy8q7enqjms6yvdz264hme8uryuxmvvqesq6rusq0, age1vf8h7s8mqsn2q5eadgpdupsj4mwn8zguc77d85ws3xj40sl9rgksx2rxw6, age1z62ff2ak9zj5ctcvaxwyyhedwjvlwgm2dkn9nk3wrwk8fkavcpmsqwc2vs - path_regex: ^secrets/openrouter-api-key\.yaml$ # OpenRouter API key consumed by the `hermes` wrapper (bin/hermes) when # spawning a Goose session. Recipients are any host that should run a # Nous-Hermes agent. Add a host's age_pubkey here, then # `sops updatekeys -y secrets/openrouter-api-key.yaml`. # See operations/hermes-agent.md. age: >- age1xkklkvnk5z0fsnh6cfgv70hy9ksfy8rdprwerzw4yk3p4p7cxcqs2yvpz6, age1vf8h7s8mqsn2q5eadgpdupsj4mwn8zguc77d85ws3xj40sl9rgksx2rxw6, age1z62ff2ak9zj5ctcvaxwyyhedwjvlwgm2dkn9nk3wrwk8fkavcpmsqwc2vs, age1s07zs83ehtlg8jtwvr75ltc3c4cdlemfwjuxrwjtwkqxkl9tpggsyrzn2h - path_regex: ^secrets/yuvomi-api-token\.yaml$ # Named Bearer token for the Yuvomi REST API, consumed by yuvomi-mcp on # LXC 129 (house). age: >- age1xkklkvnk5z0fsnh6cfgv70hy9ksfy8rdprwerzw4yk3p4p7cxcqs2yvpz6, age1vf8h7s8mqsn2q5eadgpdupsj4mwn8zguc77d85ws3xj40sl9rgksx2rxw6, age1z62ff2ak9zj5ctcvaxwyyhedwjvlwgm2dkn9nk3wrwk8fkavcpmsqwc2vs, age1s07zs83ehtlg8jtwvr75ltc3c4cdlemfwjuxrwjtwkqxkl9tpggsyrzn2h - path_regex: ^secrets/hermes-house-users\.yaml$ # Signal number → Yuvomi user_id mapping (PII). Consumed by hermesd on LXC 129. age: >- age1xkklkvnk5z0fsnh6cfgv70hy9ksfy8rdprwerzw4yk3p4p7cxcqs2yvpz6, age1vf8h7s8mqsn2q5eadgpdupsj4mwn8zguc77d85ws3xj40sl9rgksx2rxw6, age1z62ff2ak9zj5ctcvaxwyyhedwjvlwgm2dkn9nk3wrwk8fkavcpmsqwc2vs, age1s07zs83ehtlg8jtwvr75ltc3c4cdlemfwjuxrwjtwkqxkl9tpggsyrzn2h # webhook noop 2026-05-20T18:16:57+02:00