diff --git a/docs/changelog.md b/docs/changelog.md index 7eab9aa6..2db017eb 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -19,6 +19,26 @@ docstring gives: it is a record, not a claim about now. ## 2026-11-09 +- **The in-house ntfy topics are renamed so a phone can tell them apart.** + The iOS ntfy app shows a subscription by its topic name and has no display + name ([binwiederhier/ntfy#1314](https://github.com/binwiederhier/ntfy/issues/1314)), + so the three `make gen-secret` names read as three random strings on the + iPhone. Each name is now its channel's word, a dash, and twelve hex + characters: `alerts-…`, `urgent-…`, `security-…`, in + `secrets/sensitive.sops.yaml` and at the end of the three receiver URLs in + `secrets/observability.sops.yaml`, changed in the same PR. A bare word was + declined. [#136](https://github.com/Gerrrt/HomeLab/issues/136) asked that + the names be kept like a credential. And `upstream-base-url` sends ntfy.sh + the SHA-256 of each topic's URL to wake the iPhone, so `…/urgent` would let + anyone compute that hash, subscribe to it on ntfy.sh, and see when a page + is sent. The ntfy.sh pair keep their names, because there the name alone is + the credential. Android's app gets display names instead + (`stacks/sensitive/README.md`). The same day, `ScheduledJobNeverRan` for + `household-copy` and `household-proof` was silenced for ninety days under + [#455](https://github.com/Gerrrt/HomeLab/issues/455): it is correct while + no holder is chosen, and it was repeating every twelve hours on the + in-house channel. + - **[#421](https://github.com/Gerrrt/HomeLab/issues/421), [#790](https://github.com/Gerrrt/HomeLab/issues/790): `gandalf` is ready for `tpl-kali`'s build, `build-the-lab-templates.md` §5 step 2's `gandalf` diff --git a/docs/runbooks/build-the-sensitive-tier-host.md b/docs/runbooks/build-the-sensitive-tier-host.md index aacab391..6f3cecfc 100644 --- a/docs/runbooks/build-the-sensitive-tier-host.md +++ b/docs/runbooks/build-the-sensitive-tier-host.md @@ -354,7 +354,7 @@ what each key is for. The values: | `NTFY_ALERTMANAGER_TOKEN` | the pinned image's `ntfy token generate` — the command is beside the key | No. The monitoring host's `ALERTMANAGER_NTFY_TOKEN` is the other copy | | `NTFY_ALERTMANAGER_PASSWORD_HASH` | `make gen-secret`, then `make hash-password` on it | No — the password is thrown away; this user logs in by token | | `NTFY_PHONE_PASSWORD_HASH` | `make hash-password` | **The password** — each phone's ntfy app logs in with it | -| `NTFY_TOPIC_ALERTS`, `_URGENT`, `_SECURITY` | `make gen-secret`, three times | No. The monitoring host's receiver URLs end in the same three | +| `NTFY_TOPIC_ALERTS`, `_URGENT`, `_SECURITY` | The channel's word, a dash and `openssl rand -hex 6`: `alerts-…`, `urgent-…`, `security-…` — the example file says why | No. The monitoring host's receiver URLs end in the same three | | `MINIFLUX_DBPASS` | `make gen-secret` — never typed: it is spliced into a connection string | No | | `MINIFLUX_ADMIN_PASSWORD` | `make gen-secret` | **Yes**, it is a login | | `LINKDING_SUPERUSER_PASSWORD` | `make gen-secret` | **Yes**, it is a login, and the only thing guarding the list ([ADR-0061](../adr/0061-add-linkding-to-the-sensitive-tier-behind-one-factor.md)) | diff --git a/secrets/observability.example.yaml b/secrets/observability.example.yaml index fd869f19..28f3043c 100644 --- a/secrets/observability.example.yaml +++ b/secrets/observability.example.yaml @@ -100,9 +100,9 @@ SNMP_PRIVPASS_NEO: change-me-neo-priv # shows a title and one line instead of JSON. Nothing about the # token goes in the URL — it is ALERTMANAGER_NTFY_TOKEN below, sent as a # header, because Caddy's access log records the URL. -ALERTMANAGER_WEBHOOK_URL: https://ntfy.matrix.elysium/change-me-alerts-topic?template=homelab -ALERTMANAGER_URGENT_WEBHOOK_URL: https://ntfy.matrix.elysium/change-me-urgent-topic?template=homelab -ALERTMANAGER_SECURITY_WEBHOOK_URL: https://ntfy.matrix.elysium/change-me-security-topic?template=homelab +ALERTMANAGER_WEBHOOK_URL: https://ntfy.matrix.elysium/alerts-changeme0000?template=homelab +ALERTMANAGER_URGENT_WEBHOOK_URL: https://ntfy.matrix.elysium/urgent-changeme0000?template=homelab +ALERTMANAGER_SECURITY_WEBHOOK_URL: https://ntfy.matrix.elysium/security-changeme0000?template=homelab # The same urgent and security channels, AGAIN, on ntfy.sh — for a phone that # is not on the home network and so cannot reach the in-house server (#136). diff --git a/secrets/observability.sops.yaml b/secrets/observability.sops.yaml index 7760a4d0..69c07500 100644 --- a/secrets/observability.sops.yaml +++ b/secrets/observability.sops.yaml @@ -28,9 +28,9 @@ SNMP_AUTHPASS_ILO: ENC[AES256_GCM,data:SEcb8Q7E6aCbgyDzxxgMx7Ch/j6wmb5I,iv:yfOpf SNMP_PRIVPASS_ILO: ENC[AES256_GCM,data:9p47YaJSds6YfcKkbNFEBPqoTXlkwKZG,iv:SWOVZIyiqoxWEt/arM+ffyY0dF7Ry3BMyfNPWISSqlo=,tag:Lvw3Wqap/ts3Kj7a8p3Njg==,type:str] #ENC[AES256_GCM,data:KYm60Zx9WHuw0PObbmuV5uOxqGJG51YHztUtmrAPocdqvPmnbSQJthKe3+PngPrfFfn7G8RfRANrDTgboVgQOWbwtvIlhK8CutPr16gq2rM=,iv:elgWymJ/VyQzT63VSPBtWYIsJY26GeG2T4MYZCmInWY=,tag:Px8SEziU2qyNYMMI0B1WAg==,type:comment] #ENC[AES256_GCM,data:c+QE2sE9agdh20ZSaWSTdnENoeFagYWbpy9D7oVKofDsi9oBM8rxxrlp4s8CfB3KcNv7uFBD2SZdMBVDltjfkJICEjKgfJCBQ8A=,iv:PQBt/eUj95BdLusTJc5o3ZwyqIZGy9/XEG/AQTHk/IU=,tag:spc+wLic1oKSlHgvBjiLSg==,type:comment] -ALERTMANAGER_WEBHOOK_URL: ENC[AES256_GCM,data:q4l2VKC7cMagPDrdB8L9wUdLXufLWKdEHyuKivCiOoeRqZ6L7SXGyWor/mNCTYCRTWkbSahRX8nWRYTPZpuSlX1MuZ5l,iv:+RywBWb3PL+hqutP36aYvREDWyWPDww870b87P2xYFc=,tag:pKz2SSMgL/A+flKEbWZzkg==,type:str] -ALERTMANAGER_URGENT_WEBHOOK_URL: ENC[AES256_GCM,data:5tpgO2n7maKWVTOgUzOI2xkJn1Sm+lXBApfWSfJG9F78rdbPNLe7ObIPYaYGqnP6aDZHjmFZJ+ufRU9m1rQFsxZzBAXz,iv:ciBrtVhs2k7KEHipQGm5vNBGUnK3fXKCcx1TWFOjeE8=,tag:cuFEDnIXNuqd7SlVLdQEkw==,type:str] -ALERTMANAGER_SECURITY_WEBHOOK_URL: ENC[AES256_GCM,data:Ptb5MQlvZluQMil9v/XMPVoBeWTvr/anRaRriTk2XwxbI/oUcswsvIDXI453Wt9xplrz8G+xpAnSdOkug2SH/7IQRglA,iv:kp98mXHmGKJDYgujqAo4AaobPGDyZJUDMoeM+gz4VXI=,tag:zx0XHHVj3WJ0CrMBSXdBYw==,type:str] +ALERTMANAGER_WEBHOOK_URL: ENC[AES256_GCM,data:NDX9rt9ZeJ+gpOerj1bFi++ZEmIanxe9MHxmFpUXVlHRUVE/7d0U5Unyfx5on5ktkoagSpYCYGfJ5bJJF4jleQ==,iv:aTLqUpoDczUvUGI2M1UfyuVx9oXanW+D/cL+BhTxm+M=,tag:BJUNPVNUiyUYBad30iLxVg==,type:str] +ALERTMANAGER_URGENT_WEBHOOK_URL: ENC[AES256_GCM,data:zAmWXMTzLuWLTx1GAv5CKe57dnJ08PdoeAOltaQg5sP0ROkZetTkJpRcEEqjUUCbT8i9v511yKDikCZMPOvbvA==,iv:ZTLjWxUycqqI8u/JQJ3Z5WRY/zYRS09TJUvkRNIjLPg=,tag:xJEcbMhP9Xwp0aSMQoPMdw==,type:str] +ALERTMANAGER_SECURITY_WEBHOOK_URL: ENC[AES256_GCM,data:tkdWGyemtcC7LIMQVnMAcdXsr6DalDnM/Y8r9uhQZPnBbrJ+S+y7LIZRniDNVlB8tafj+jy7+Gw2F2cjczu6zSSN,iv:4kqqu0aMbmDMyndy3RfPRfPmkWFIFnjJnKCVl0qLxC8=,tag:RqkfSWcoLumcBek38Fzdzg==,type:str] ALERTMANAGER_HEARTBEAT_URL: ENC[AES256_GCM,data:MLyUW0Il41PdYdQGJ8gP3/1tS5hF7RuFK6s+gC5uGjonhzR+oci17pfUmxWGKR8gq8v2kPgR9oc=,iv:R6MFSHEa8VlsMubSwnssfWnNV4rZj1o4KnV87yr5ZhU=,tag:2MkqtXOL7nZOZ3BJxxZ9Ag==,type:str] #ENC[AES256_GCM,data:ibikwgcTWigPNcgg0t3XIZXw9hH35iOL0wCrZT+igu9AwKq4gnI6jXkB6uoGtiVkbrZcHKi4i3flEG8=,iv:4Io1MYaGR3B2hBwC850ZcCYS+JbefgpkwIPtgkdTgcE=,tag:4GPC0EJpVymFIYU/oItxgQ==,type:comment] GRAFANA_RENDERER_TOKEN: ENC[AES256_GCM,data:Di7QsFgUnTpafqP8HMDBC8VcrjrU6co9,iv:6NvJz7n2UxORywAd/PvjmEf8hpeTWyqTXMyJ6GuITw0=,tag:fkskNXA66wNSyhLOmCUJcg==,type:str] @@ -68,8 +68,8 @@ sops: NGhGVmx4eDU3R0l1bHRPM0t0NS82dEUKFrC+ts3UB8bm+oj+EviyTW6nVIlwFOIV 25J6YSdIP+IbThGqA8j+yKPXrMaGv2PWVPADpTpmMg8nZJRx8Wv1XA== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-11-07T05:40:31Z" - mac: ENC[AES256_GCM,data:3rtiU3+sEwKodIaDn+8qzGhOecPyKesjAPzws62gr1rdZSOGmxQNX2WUlLGmpAuaJtQbCyN0+B9DYN4AQArw7toS3xkYADivjFctHL7nPcGHQ6AjgPyqaImMLguBXGcnDAxojIbL3Hqjh58tL8cauWrpgaoYDv9RMjx/BoSF2hs=,iv:7vXTWvIjAgOZ2I91VjC6FhaYrHPKbKnj4vSHXOWvQ3Q=,tag:+oCITNhb2/F9m060FpBt6g==,type:str] + lastmodified: "2026-11-09T18:06:33Z" + mac: ENC[AES256_GCM,data:qjDSln/C60uUX3ruTnvq4/zAO0LpoelFnGF8uNFPn8Lo8p6Ls2uY45zvdr030ar4EgNODlaCtnwduPaSBndWy8jdiFjwlxn4PUGKiparyHTTcdwcE403DH19zEOhEHL0eiAKT8ta1yG5hYMTy/xnN9KJlgn/ss+x/6vh2o5z6Bg=,iv:wD5FK7ZF1bRDXyighKRd8MKJbCdYZET1ENL5D732PkY=,tag:2KTocf207HyEYXHX+gOl8Q==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.9.4 diff --git a/secrets/sensitive.example.yaml b/secrets/sensitive.example.yaml index 80216484..16959fde 100644 --- a/secrets/sensitive.example.yaml +++ b/secrets/sensitive.example.yaml @@ -211,21 +211,30 @@ MQTT_RING_PASSWORD: change-me # `phone` (`make hash-password`). The # password goes in the password manager. # NTFY_TOPIC_ALERTS / _URGENT / _SECURITY -# three topic names, each `make gen-secret` -# output. The same three names end the URLs -# in secrets/observability.sops.yaml. With -# deny-all a name grants nothing by itself, -# but #136 asked that they be kept like a -# credential, and they are. +# three topic names, each the channel's own +# word, a dash, and `openssl rand -hex 6`: +# alerts-…, urgent-…, security-…. The same +# three names end the URLs in +# secrets/observability.sops.yaml. The word +# is for the iPhone, whose ntfy app shows +# the topic name and has no display name +# (2026-11-09). The random tail is kept +# because #136 asked that the names be kept +# like a credential, and because ntfy.sh +# receives the SHA-256 of each topic's URL +# to wake the iPhone: a bare `urgent` would +# let anyone compute that hash and watch +# when a page is sent. Letters, digits and +# dashes only. # # Both hashes carry `$`; paste them as they are — render-config.sh escapes them # for compose's .env, as it does AdGuard's. NTFY_ALERTMANAGER_TOKEN: tk_changemechangemechangeme00 NTFY_ALERTMANAGER_PASSWORD_HASH: change-me-to-the-output-of-make-hash-password NTFY_PHONE_PASSWORD_HASH: change-me-to-the-output-of-make-hash-password -NTFY_TOPIC_ALERTS: change-me-to-something-long-and-random -NTFY_TOPIC_URGENT: change-me-to-something-long-and-random -NTFY_TOPIC_SECURITY: change-me-to-something-long-and-random +NTFY_TOPIC_ALERTS: alerts-changeme0000 +NTFY_TOPIC_URGENT: urgent-changeme0000 +NTFY_TOPIC_SECURITY: security-changeme0000 # Miniflux (#147, ADR-0057). Both generated (`make gen-secret`), none typed: # diff --git a/secrets/sensitive.sops.yaml b/secrets/sensitive.sops.yaml index abbabfc0..d2225874 100644 --- a/secrets/sensitive.sops.yaml +++ b/secrets/sensitive.sops.yaml @@ -101,9 +101,9 @@ PAPERLESS_ADMIN_PASSWORD: ENC[AES256_GCM,data:T8KRQtakbdjI8hrY+OKaB9vY1EkLT8RS,i NTFY_ALERTMANAGER_TOKEN: ENC[AES256_GCM,data:RNAM3K22PmpQiuZSfkVO7Hu8QdyuCCdXKfSOTcxZDnw=,iv:9Ijr/9D952aMoPOAHWS81Wp7QSFK7DRKX7ln4KOx0JM=,tag:N0YOlC/V7gE/ARoeQWAXOw==,type:str] NTFY_ALERTMANAGER_PASSWORD_HASH: ENC[AES256_GCM,data:ORDfCxUdjwMzZ9NSEYtgM1w4pFWxeVlrp0RlP+tMAef49PUdnsebgnceqSYwDGlJvQVCBzWJmSQsUvKQ,iv:P39Qfz774REjOms70R7DmORXa3QTVJM2oS7R2AptVo8=,tag:dveLyCaCAZfq5hqR+JiW4g==,type:str] NTFY_PHONE_PASSWORD_HASH: ENC[AES256_GCM,data:H+a+vnHDilp6R5GzZ5w3O3T4hjdKzCENO7tJ6VsD2IIDNFcMnbpPSva0ZgdyDKK8QnYaNuZiSyPDXYJu,iv:04S4saMbYjSJExNHl7KW+MgrC5U17lIGW9ZDaUEPMg4=,tag:flXr36yJecNafbaBgykrBw==,type:str] -NTFY_TOPIC_ALERTS: ENC[AES256_GCM,data:/sd4w3Hn+0SpDNiynm7el3P6d8KouQh0,iv:pQDlGB0q3gCeC0WsqLh4Syfh6oR/ektEzwdpNu5HXOc=,tag:3iwQw4V+71g2ACjtNS59qw==,type:str] -NTFY_TOPIC_URGENT: ENC[AES256_GCM,data:V0lKvEko5ukpqPZUDeEhKqDzJdWtXMNA,iv:y5IHLDN1ONc/3/X0JFEBh3eyKpx81ia+5JFjR7SD6Ow=,tag:K7JcvqILFVFyLI9m75vBBg==,type:str] -NTFY_TOPIC_SECURITY: ENC[AES256_GCM,data:nzdGp87bMsDH6J0OAqdiEeVxg+CaL+Zf,iv:az6fiirnR7yBYcjuEO7osYA7rDJh13gB3ggl9EkX1VI=,tag:03LR/6ewhhQMS1dLrLGJEg==,type:str] +NTFY_TOPIC_ALERTS: ENC[AES256_GCM,data:nMiZWCZE08B62kBL99zecgfQCQ==,iv:5kD7bA6a4VKZSqXUhJHa/rJiflJAIBco5VLW77DmOnc=,tag:H14YSU6KzVw4Beda3GUFRQ==,type:str] +NTFY_TOPIC_URGENT: ENC[AES256_GCM,data:Q4WsVxnAWCGTTsOjIUZKEz3XfA==,iv:JQDqZbLKprvRUs555d2g/ns1c6DnA1kBu9bFess7G3g=,tag:aLqDuOHNa4JS/8gCZTa4dA==,type:str] +NTFY_TOPIC_SECURITY: ENC[AES256_GCM,data:/c+jNLDvZ65FWUmBATG5b+ad1BJS,iv:f1PWfR3j0jjbgkCMiHEgQ9WnYjF9ZnAVSW8e+9frNFQ=,tag:gFq8WTJ3Dy17h04GriRgFw==,type:str] GLANCE_IMMICH_API_KEY: ENC[AES256_GCM,data:Z46+ZCHNrjtsIUU8DcvFafr6Usweryclv2TDYBM9sVNZPdrqKQvLHws=,iv:IeCnK3/Tf/aUt2ZeEL5GnrjkfAQ0TkohoHkOPZXViOE=,tag:FJDHraiLBbnMajTaJDwszg==,type:str] GLANCE_PAPERLESS_TOKEN: ENC[AES256_GCM,data:vf1VGOSgxUFiiSsmKkf87RMdLJsS34t9iusqQU2mWpcHyEcAzwaLRw==,iv:GiO2jD9ehOt3mz6n2Fqow/7QJVtXKhWMKLpmDOVYfD0=,tag:eC4UmvCw+DOv5/WpbeUYQQ==,type:str] MINIFLUX_DBPASS: ENC[AES256_GCM,data:OdnXudf3/cIN5rlSiHXvI7Z/TeSlLo19,iv:QoLjAWrDS6oX5f8o7rT051MrLxnZZYSSrMUz7sQ64ws=,tag:iYrO+4FSFhClk4cZSq2BJg==,type:str] @@ -145,8 +145,8 @@ sops: RGFiYUlWUUxSYWpVbzNaR0RSaUpLYzQKRssWILF29DQ57eS6Rcnz8TF4qSPrLj4Q 0coqwkg00uzmjaINDwnl9WAvXPBzSL7eEih2BKTVBRfhJjvDJ+tRWQ== -----END AGE ENCRYPTED FILE----- - lastmodified: "2026-10-22T20:39:23Z" - mac: ENC[AES256_GCM,data:q+5JhoBWOJ0zPcT0gHbSEj4XujKK12qrlQ+LI8/mk9re2bQWqHw16gwNPiuoadDMNuWytvhuQmVltcrYyjvw644KoLQRp3EGVzELB+aMaaEniyeyIDuv6rbMIUqhsZRX6SLIvSWD5zlOrjuP280f6s/QrGzdv0Rh6eKmaMCVfJA=,iv:5Jok8vhR2zaDM+iCKsGOQL+EP5Ac4IDa561BW1YEPs4=,tag:8AvUn6Q+tX0V2h/+EuYDqw==,type:str] + lastmodified: "2026-11-09T17:57:55Z" + mac: ENC[AES256_GCM,data:b3nztB8xsYuy5xS6Way0hhZTyPdKFmuqv3q9tmKeNaajOjCoOoEW332VYYHUvG3fGaQsuKkGi3v3lH+H/GCk2U0yZk+Zzj90Ser7l00a9g1yPv66Hp/H5nbSXrWePWAyXUv21cGtQ3oAjDq/OVlvEXyrDA79Cm8eDGKaTrFgik0=,iv:wCQiLX4xbFNjxfdTTEIiPg4B1f95HlU/zSPJOlMq+Ws=,tag:jpBwCBAtrwvIvx/ZQKvweg==,type:str] pgp: [] unencrypted_suffix: _unencrypted version: 3.9.4 diff --git a/stacks/sensitive/README.md b/stacks/sensitive/README.md index 4d14d9c6..34f89f17 100644 --- a/stacks/sensitive/README.md +++ b/stacks/sensitive/README.md @@ -745,6 +745,10 @@ here. 1. Add the three in-house topics, with server `https://ntfy.matrix.elysium` and user `phone`. The password is in the password manager; the topic names are in `secrets/sensitive.sops.yaml`. + Each begins with its channel's word, because the iOS app shows the + topic name and cannot rename a subscription. Android's can: give every + subscription, the ntfy.sh pair included, a *Display name* in its + settings. 2. Keep the two ntfy.sh subscriptions. They are the off-network pager. 3. On iOS, leave the app's *default server* at `ntfy.sh`. The upstream wake-ups arrive through it.