From 7832978ff732208f2f29f04ef446c7c51076c6d1 Mon Sep 17 00:00:00 2001
From: lilly
Date: Sun, 24 May 2026 11:55:31 +0200
Subject: [PATCH 01/14] update ccchh.net dns zone after club proxmox migration
---
.../chaosknoten/auth-dns/zones/ccchh.net.zone | 135 ++++++++----------
1 file changed, 63 insertions(+), 72 deletions(-)
diff --git a/resources/chaosknoten/auth-dns/zones/ccchh.net.zone b/resources/chaosknoten/auth-dns/zones/ccchh.net.zone
index bb5c16f..0360f81 100644
--- a/resources/chaosknoten/auth-dns/zones/ccchh.net.zone
+++ b/resources/chaosknoten/auth-dns/zones/ccchh.net.zone
@@ -1,73 +1,64 @@
-$ORIGIN .
-$TTL 900 ; 15 minutes
-ccchh.net IN SOA auth-dns.hamburg.ccc.de. noc.hamburg.ccc.de. (
- 2026042801 ; serial
- 86400 ; refresh (1 day)
- 7200 ; retry (2 hours)
- 3600000 ; expire (5 weeks 6 days 16 hours)
- 7200 ; minimum (2 hours)
- )
- NS auth-dns.hamburg.ccc.de.
- NS ns.vie.ccc.de.
+$TTL 60 ; 1 minutes
+@ SOA auth-dns.hamburg.ccc.de. noc.hamburg.ccc.de. (
+ 1 ; serial (overwritten by knot automatically)
+ 86400 ; refresh (1 day)
+ 7200 ; retry (2 hours)
+ 3600000 ; expire (5 weeks 6 days 16 hours)
+ 60 ; minimum/negative ttl (1 minute)
+ )
-$ORIGIN ccchh.net.
-aes A 212.12.48.125
-club-assistant AAAA 2a07:c481:1:d0::a
-;_acme-challenge.club-assistant CNAME d50ad73a-f82d-4244-87f0-6f5195b37d21.auth.acmedns.hamburg.ccc.de
-club-assistant.z9 AAAA 2a07:c481:1:d0::a
-;_acme-challenge.club-assistant.z9 CNAME 0efa74d1-7dcd-478b-bdc5-5b76d0f07642.auth.acmedns.hamburg.ccc.de
-esphome AAAA 2a07:c481:1:d0::66
-esphome.z9 AAAA 2a07:c481:1:d0::66
-zigbee2mqtt A 185.161.129.132
-light AAAA 2a07:c481:1:d0::16
-_acme-challenge.light CNAME e59f55ee-9013-469d-a146-a159721b6fea.auth.acmedns.hamburg.ccc.de.
-light.z9 AAAA 2a07:c481:1:d0::16
-_acme-challenge.light.z9 CNAME 3bc9e7ce-03dd-4533-a059-b5d38407eaa5.auth.acmedns.hamburg.ccc.de.
-light-werkstatt AAAA 2a07:c481:1:d0::16
-_acme-challenge.light-werkstatt CNAME f408acc0-d9f5-4525-bb01-28938e3bb7d0.auth.acmedns.hamburg.ccc.de.
-mailserver-endpoint A 82.165.121.46
-ns1 A 185.161.129.133
-send-only-mail MX 10 send-only-mailserver
- TXT "v=spf1 mx -all"
-send-only-mailserver A 82.165.121.46
-send-only-mailserver-access A 185.161.129.132
-thinkcccore0 AAAA 2a07:c481:1:f2::3
-thinkcccore0.z9 AAAA 2a07:c481:1:f2::3
-thinkcccore1 AAAA 2a07:c481:1:f2::4
-thinkcccore1.z9 AAAA 2a07:c481:1:f2::4
-opnsense AAAA 2a07:c481:1:f2::1
-opnsense.z9 AAAA 2a07:c481:1:f2::1
-pbs AAAA 2a07:c481:1:f2::4
-thinkcccore2 AAAA 2a07:c481:1:f2::5
-thinkcccore2.z9 AAAA 2a07:c481:1:f2::5
-thinkcccore3 AAAA 2a07:c481:1:f2::6
-thinkcccore3.z9 AAAA 2a07:c481:1:f2::6
-miniscccore0 AAAA 2a07:c481:1:f2::9
-miniscccore0.z9 AAAA 2a07:c481:1:f2::9
-uptime-kuma A 185.161.129.132
-status AAAA 2a07:c481:1:ce::a
-status.z9 AAAA 2a07:c481:1:ce::a
-wiki A 212.12.48.125
-hmdooris-ccu A 10.31.208.202
-buba A 10.31.211.137
-buba.z9 A 10.31.211.137
-dooris AAAA 2a07:c481:1:d0::1c
-_acme-challenge.dooris CNAME 37caae1f-b77f-4eb1-aa71-dc3f7ed24360.auth.acmedns.hamburg.ccc.de.
-waybackproxy A 10.31.208.99
-yate A 10.31.208.12
-staubiv2 A 10.31.210.233
-staubiv2.z9 A 10.31.210.233
-; Mail: hosts.z9.ccchh.net
-hosts.z9 MX 10 cow.hamburg.ccc.de
- TXT "v=spf1 mx -all"
-dkim._domainkey.hosts.z9 TXT ("v=DKIM1;k=rsa;t=s;s=email;"
- "p=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAvsdypQ/tlrzto5KVP"
- "5o7tEblXK/hOVRFB683uODzo26XTFMSRGjumMuo/tej59GMePdUu0uIsdq8hfj8"
- "ot0R2OQNazdyp4NW4TUWfFGJ4S2f6LR3lE3I5Lw7fHiYHz0GnCGTqZIItkHK+xQ"
- "i5Fdhwd1YbFJtO0XiZ0jY5w6pvny6pEH8WaKX85rEmz2zqCtpiYPRPmoK/Tn+rV"
- "2e8fVioMRm9W8E4PU42WLds66qOkFR0KjKIavE6y7JahESEoVGcVnSPdtMOX0Ln"
- "KbSMQNrTvNbBoPdLYvNaXOw7TmVPKjDV+FRCIIdK+m0fL82/vm5jPBvDr5+WlM1"
- "xV/P/KlSnQIDAQAB")
-$ORIGIN send-only-mail.ccchh.net.
-_dmarc TXT "v=DMARC1;p=quarantine;"
-key._domainkey TXT "v=DKIM1;k=rsa;p=MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDqduM4+SQ+IQ2uAxbjFkd+0hAjohTgT3nM76jyrWGHJ8TizNU2PGkta0NjCq+m9VLBZUjIJphW2vrnlJsnN0JkGAdoLBL3Qs0kShT6V+xsxslZG2KHApihnJUp34tPSMES+aTnD+jEPGyxFLeoiK+3gywNhCGalHSQ+G88Z2n59wIDAQAB"
+@ NS auth-dns.hamburg.ccc.de.
+@ NS ns.vie.ccc.de.
+
+
+;
+; Network-Infrastructure
+;
+rt-wan A 185.161.129.134
+ AAAA 2a07:c481::1:2
+sw-rack-1 A 10.89.213.2
+ AAAA 2a07:c481:1:36::2
+sw-rack-2-poe A 10.89.213.3
+ AAAA 2a07:c481:1:36::3
+sw-main-1 A 10.89.213.4
+ AAAA 2a07:c481:1:36::4
+sw-main-2 A 10.89.213.5
+ AAAA 2a07:c481:1:36::5
+sw-shop-1 A 10.89.213.6
+ AAAA 2a07:c481:1:36::6
+sw-shop-2-poe A 10.89.213.7
+ AAAA 2a07:c481:1:36::7
+sw-shop-3-poe A 10.89.213.8
+ AAAA 2a07:c481:1:36::8
+pve01 A 10.89.213.11
+ AAAA 2a07:c481:1:36::11
+pve02 A 10.89.213.12
+ AAAA 2a07:c481:1:36::12
+pve03 A 10.89.213.13
+ AAAA 2a07:c481:1:36::13
+pve04 A 10.89.213.14
+ AAAA 2a07:c481:1:36::14
+pbs A 10.89.213.15
+ AAAA 2a07:c481:1:36::15
+unifi A 10.89.213.21
+
+
+;
+; Club-Services
+;
+xr18 A 172.31.200.21
+
+;club-assistant AAAA 2a07:c481:1:d0::a
+;;_acme-challenge.club-assistant CNAME d50ad73a-f82d-4244-87f0-6f5195b37d21.auth.acmedns.hamburg.ccc.de
+;esphome AAAA 2a07:c481:1:d0::66
+;zigbee2mqtt A 185.161.129.132
+;light AAAA 2a07:c481:1:d0::16
+;_acme-challenge.light CNAME e59f55ee-9013-469d-a146-a159721b6fea.auth.acmedns.hamburg.ccc.de.
+;light-werkstatt AAAA 2a07:c481:1:d0::16
+;_acme-challenge.light-werkstatt CNAME f408acc0-d9f5-4525-bb01-28938e3bb7d0.auth.acmedns.hamburg.ccc.de.
+;hmdooris-ccu A 10.31.208.202
+;buba A 10.31.211.137
+;dooris AAAA 2a07:c481:1:d0::1c
+;_acme-challenge.dooris CNAME 37caae1f-b77f-4eb1-aa71-dc3f7ed24360.auth.acmedns.hamburg.ccc.de.
+;yate A 10.31.208.12
+;staubiv2 A 10.31.210.233
From 2fc93e6e626067703ebbfbda9692e134e355495b Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Sat, 23 May 2026 23:46:00 +0200
Subject: [PATCH 02/14] rt1(z9 host): create host and configure networkd and
nftables
---
inventories/z9/host_vars/rt1.sops.yaml | 198 ++++++++++++++++++
inventories/z9/host_vars/rt1.yaml | 6 +
inventories/z9/hosts.yaml | 11 +
resources/z9/rt1/nftables/nftables.conf | 111 ++++++++++
.../z9/rt1/systemd_networkd/00-netlan.link | 6 +
.../z9/rt1/systemd_networkd/00-netwan.link | 6 +
.../rt1/systemd_networkd/10-netlan.51.netdev | 7 +
.../rt1/systemd_networkd/10-netlan.52.netdev | 7 +
.../rt1/systemd_networkd/10-netlan.53.netdev | 7 +
.../rt1/systemd_networkd/10-netlan.54.netdev | 7 +
.../rt1/systemd_networkd/10-netwan.400.netdev | 7 +
.../z9/rt1/systemd_networkd/10-wg55.netdev | 90 ++++++++
.../z9/rt1/systemd_networkd/20-netlan.network | 12 ++
.../z9/rt1/systemd_networkd/20-netwan.network | 9 +
.../z9/rt1/systemd_networkd/20-wg55.network | 6 +
.../21-netlan.51-clients.network | 27 +++
.../systemd_networkd/21-netlan.52-iot.network | 27 +++
.../21-netlan.53-public.network | 27 +++
.../21-netlan.54-management.network | 27 +++
.../21-netwan.400-fux_uplink.network | 26 +++
.../rt1/systemd_networkd_global_config.conf | 3 +
21 files changed, 627 insertions(+)
create mode 100644 inventories/z9/host_vars/rt1.sops.yaml
create mode 100644 inventories/z9/host_vars/rt1.yaml
create mode 100644 resources/z9/rt1/nftables/nftables.conf
create mode 100644 resources/z9/rt1/systemd_networkd/00-netlan.link
create mode 100644 resources/z9/rt1/systemd_networkd/00-netwan.link
create mode 100644 resources/z9/rt1/systemd_networkd/10-netlan.51.netdev
create mode 100644 resources/z9/rt1/systemd_networkd/10-netlan.52.netdev
create mode 100644 resources/z9/rt1/systemd_networkd/10-netlan.53.netdev
create mode 100644 resources/z9/rt1/systemd_networkd/10-netlan.54.netdev
create mode 100644 resources/z9/rt1/systemd_networkd/10-netwan.400.netdev
create mode 100644 resources/z9/rt1/systemd_networkd/10-wg55.netdev
create mode 100644 resources/z9/rt1/systemd_networkd/20-netlan.network
create mode 100644 resources/z9/rt1/systemd_networkd/20-netwan.network
create mode 100644 resources/z9/rt1/systemd_networkd/20-wg55.network
create mode 100644 resources/z9/rt1/systemd_networkd/21-netlan.51-clients.network
create mode 100644 resources/z9/rt1/systemd_networkd/21-netlan.52-iot.network
create mode 100644 resources/z9/rt1/systemd_networkd/21-netlan.53-public.network
create mode 100644 resources/z9/rt1/systemd_networkd/21-netlan.54-management.network
create mode 100644 resources/z9/rt1/systemd_networkd/21-netwan.400-fux_uplink.network
create mode 100644 resources/z9/rt1/systemd_networkd_global_config.conf
diff --git a/inventories/z9/host_vars/rt1.sops.yaml b/inventories/z9/host_vars/rt1.sops.yaml
new file mode 100644
index 0000000..f4141fd
--- /dev/null
+++ b/inventories/z9/host_vars/rt1.sops.yaml
@@ -0,0 +1,198 @@
+secrets__secrets:
+ - name: ENC[AES256_GCM,data:MmqDXUKy+U67JZFmKJTGLYAJcYPClQ8M2w==,iv:/eDx++bJCzdKXYB8YipB/GB6aM421JR3sy8i5trBKxk=,tag:/zTklys9bN839iT1qOH0UQ==,type:str]
+ content: ENC[AES256_GCM,data:2ljp324rAsF2zk2631TI7bV1xKxdFr4u4NxrsPYnjWsL0PX0n0KhJ1qvJCs=,iv:0+DxsTTiNLOg5iH83bFT/d+0uW2rn6bATSm3xc5PEdE=,tag:XbBDrrjriXPedyT4+sBBwA==,type:str]
+ - name: ENC[AES256_GCM,data:9i4hZU7Hv/IMlI/1oYthx8g57nrst9LHZQk=,iv:IQanD/CA64A+hVyTQBiTvWdXyY8qNF9BpehWZxI5a9c=,tag:RiY0OJe2xbFPG6wfe5XjiA==,type:str]
+ content: ENC[AES256_GCM,data:lrwHaNvHkh5E94ziiQsd8ua9YvuwmhZ6iIGZS0oFnZdYKuyNh7egWOoii2o=,iv:LLRKhbiJl1GwK/SfqNdNrrJuDF17YXw3hHmuhlyI87w=,tag:DbR/a7jfy1+4yswSdYfOFA==,type:str]
+ - name: ENC[AES256_GCM,data:2lJUcDJ7ECJ1bF4Fg1VwOR2tBIQ77ZvDAbFF8w==,iv:HrPWIetjN/lOyQ7Mvk0sM1w+bWldlNfWhvw7/sfqKN8=,tag:AJL0s+f0O/yR4G3RVd1IHQ==,type:str]
+ content: ENC[AES256_GCM,data:68GUwG1Q2s2jH92HS0FQWrcMHJP8fHjrOqr21gsdswxKekQrpxX5B3BBFfM=,iv:HOsNUAKE5rOmKgZft2JK1NnZUuhk261d9WYWJS22nLM=,tag:3husFvB57AGVFzF7hKzLpw==,type:str]
+ - name: ENC[AES256_GCM,data:ESxpEp9k9BdD1GJv+af+U3ny0+RPuaJjWDhQ,iv:DxsZLiDF8F+ixepbUdlitMJ7DLHjGNFNuxRwLl7efo8=,tag:STnv/oLzbchdiwXfKP3fow==,type:str]
+ content: ENC[AES256_GCM,data:W2h5AcoT85OkekPeRkrf1m0bDdBjG/YNSbWlrcZtP7FjaPh/F+cx+J6oRRI=,iv:CLVXTqfstpIU3BX/Zdcnp9w0gWxeGDI/G1MNl6xr4ZU=,tag:yCqN4r1MV/VTWQvZ6COfIw==,type:str]
+ - name: ENC[AES256_GCM,data:IRwwy+WQxgQ8cDpB8HaCLpKwJj7oC87p0XOxWRo=,iv:BLXNMcigvaOeY6y4NlLPMMWQt9XFi6nodRwIYFgAAnU=,tag:OdQalmujOgrzW8oi64xMRg==,type:str]
+ content: ENC[AES256_GCM,data:C5oIcuEYtODsvjQZnbqbWVfP63mQzcRuh8f5rlBCyjwSq2mZiYGQe9t0T78=,iv:sITUDo9SKZTSwPfsMv4m4U0ruuVCcaxu7SUT52U4FSE=,tag:4CsSMJWQQPAIeK8DwUDBqg==,type:str]
+ - name: ENC[AES256_GCM,data:r0sbpjaGjezoNlyl1khy+Dly+8xbbfQZNB8om/E4/tj9lmM=,iv:MLrglBJA6BrHGmFRprlQcf5/Hqh952e5OyQQ9nPxumY=,tag:Se05kMBkSQ7TRxzij7Fo8A==,type:str]
+ content: ENC[AES256_GCM,data:/c1nRf1eZhbUmoQWvcj8yDaVPtyAN7Uu+S054q3C1/kXlQ7CgOe4CrMXnmk=,iv:ppar0aCKuIU3DOjwAoliZ5TOL199Z+Ffo4pCktjs0W8=,tag:nfaGutK+5KnlWBKU1MTxkQ==,type:str]
+ - name: ENC[AES256_GCM,data:7mwuykEqbGISOa2n+pWb6INLsHYdjyf2HxTtWpAr5xP1,iv:NMcg+L2DFtBO1nhyPid31yzLr+ZX7DUGl/WxV1MnrqU=,tag:65/BiUEI8v5oMlQqpKNDRg==,type:str]
+ content: ENC[AES256_GCM,data:SObbA3D/sGN5/i5ps4Zz3alygIXKbSgptFjfPHlwC8G588O+gKAkvKQwU/s=,iv:PY2vLfI3gInFeQbse49KC2/zZ9O4jeXAQ0fpP84GHHE=,tag:214Mb8hIYDkQ4+UkRWtc9w==,type:str]
+ - name: ENC[AES256_GCM,data:bES9O6JI4wTnuZsup9gflfaozeUDkfjVGNIFn8RnZQ==,iv:98kigM3KZIN5qXNdgfLg5WLmxzAsYCjNqVzyUPco/BI=,tag:1fwEtwQ6i9QQC3OCewN0eA==,type:str]
+ content: ENC[AES256_GCM,data:flO3Nb4u2WfWNVhn8k5Bgo3LmsHo2cVnLCsrz8ST9Ip7gO9FY9d27FQgphM=,iv:aiDoq+41cSjwcCZRaIPLtbltkOpc7FeuNN7swPqkHXQ=,tag:OhzcY2xKKJF2jZVRseXCFg==,type:str]
+ - name: ENC[AES256_GCM,data:ERsggezMBbs1YwbIgwzKSAEHWWOWYxap8IDdn2YtEKvZexqu,iv:XbObLp2QERgt57tc/Cpha1CWXi+GttcIU8hJFGSp8e8=,tag:FqCuSbvLRERpVnQTzQsfpQ==,type:str]
+ content: ENC[AES256_GCM,data:QPoZA71CwE8EFE0I+6z0z0O1bUCMQDDDG7wGNoxXKt3ovLkFt21r8WG7VhA=,iv:InX6A71f3DGTg1wO4G0ECf488+FnKgTHffVwvJ9hHQ0=,tag:EVxwJlneN1CbMLXto7uLFw==,type:str]
+sops:
+ lastmodified: "2026-05-23T21:19:38Z"
+ mac: ENC[AES256_GCM,data:Ded0VfGn8H2qGMk5LDyqF1gW8hajKc9FgvCynHPQkWkhMSdaHYbFwf//gWi2TjIO22HD5sPw1w9KAjPy53b57RwBCjXfMMq0JCPvuePLK40NC8uCAi+wr5Er0fAWz1JiaA+dowposoi6RxBtyHCaNHMDVGMLh1j+IL+pTOyi6fk=,iv:gssOMmR0DDQC4WjMVXTD/zqbQa8qlBr9ZZWF15W0WnE=,tag:DORTxQfCmpVjDjyGSNH7dw==,type:str]
+ pgp:
+ - created_at: "2026-05-23T20:58:22Z"
+ enc: |-
+ -----BEGIN PGP MESSAGE-----
+
+ hQIMAxK/JaB2/SdtAQ//bbr0oza/X6GG43ay9coZbb+0aptj3pGzQqT1ND6nsI34
+ iY3IZaMZIti+j/BS5kEfmRn56WZSx6EcbSrlbiyL5NZw9R4/bGRd848rOLwMvuYO
+ 8Usei9jHdpHiPvKBZnZXaXGU8E27L0Y/LCxSIFOXbyHzHogjz3JmtJQsYpSC+ue6
+ mIRrSAJPALrqEL+DZ2bl5UYlBIRXdtIe/jL1CFCJhULt+EjJw72T62DZK/jaNZTj
+ eint63+IFZSxx5e5vrAeQB+p2EDsp6c5NbDrlgQWb8/J1q/G5bG4KxBs/0hum7OW
+ /sSsIDb4Qb8U/axt5LduV6AkMXXsclNLQU/LbFAbBRcV8Lvh11f0U3V/UnqUdmvp
+ efesb5VQh1x0uWjzobxaioLEV/YYbWx8binvuJ3MBHKp6E2xj7IrBTVl0MWgjEou
+ ZbQDF8DvxA49xEnJyOviL2/zjnV1kXy+Q+BKZga3pr8AnBHA8Ftbsvmk6CyDEM0R
+ i4FAUOVa9VWiszoOaqyn1Fl02YlweFmgzuFjd3wi74Tbi6RE37rN/vBKySbnRQYl
+ rFUU3SQlztxd4UBAXBo6gQKTz5B4rehvKVye2mmqEE9bas/lCWAKVJ7+3+0NQdA2
+ lp/X7h7DRSD2Qkd35SzxkJz7P86rd0LM1aOu87psxYavEWw6vFs2ErDkSeqDn1DU
+ aAEJAhDb1s+jpDUa3GvVZjoiiCyutI018jfJU1vi12PGktg4KJcXBx66R/nLItO2
+ ba6o66scIiAJZ+jYymW6RbJTI7XRHJp4Cs8COhpMRQeOGwEHFGGL2rpGd3KrOLQe
+ 0/C6EmrJvGpl
+ =atNE
+ -----END PGP MESSAGE-----
+ fp: EF643F59E008414882232C78FFA8331EEB7D6B70
+ - created_at: "2026-05-23T20:58:22Z"
+ enc: |-
+ -----BEGIN PGP MESSAGE-----
+
+ hQEMA1QflAioE8i3AQf+NkUGCBrTCkkyl+iBb6P1IWLDGqAY8s20mBZ7G3plKE/J
+ UrIe947letj/8EA+yoN0uzjwEkh3rDLtZrOLTSgflq1GMpdVhdaTbS71fD3kghJQ
+ P9tz0zDQEgXHBi+2q7iRrEETx/cu7UDNkSCNvQbWvDmo8MfbSBy+VFCknfupdQxj
+ 9hlq4kBA0pckPCY8V7E05nDhQntS8wpXIEO1SWiSuiGg+p4yFlvNzWNfhLyEFHxL
+ BZHVVIU/mzyClMajjLJWjKI1LSgHXXIa28tgdrtiBZOsF+CWveYqJlRJh9NUepJI
+ ZSeFNhyWmnS9ZkQu5BUyb7+oRxfq2NY51T76Xbo8gNJeAZWwyr1sj1wjubuVeNMF
+ aU6FiynYWr3I35JRVghTMJ93CnPl+NTpWnQuHpq1bzEGe2u8BMFhgrTu2yMD23VQ
+ eGien6SqfEbA/wAiz9ZaUgTQH8UyHpliteZ8/SQgkw==
+ =UJvq
+ -----END PGP MESSAGE-----
+ fp: 21C9579E6503CA815A68ABD8541F9408A813C8B7
+ - created_at: "2026-05-23T20:58:22Z"
+ enc: |-
+ -----BEGIN PGP MESSAGE-----
+
+ hQIMAz5uSgHG2iMJAQ/+O5JOJfDp/BuBCuXDQVUgJagspQO6LZ/MLrl9qH282AMf
+ MdgN5M/WjbOv6WZDCMg4nfXps1XgzUEiaA/1m4PxHlMmxjEoQHAE51GMcxsXg+B1
+ lM+8uJ1+js1sdDX4xsZtJpbVxJKIbPuhF7oM950oDlL2+UKhUbPlCoxeOihlkVGa
+ RqHJ/M74xkyKH281oRI5bllJaAroBnXVSFIvbCxA7ts/O7YJPKBowTIj62Kye9Ra
+ aHC11bPy2RlJCcFZJjPSdnXvzUMpfzEd6O72VUtMBBQZn/in7efutC8FwpRYuUW7
+ vSofxUN5n6Mtb8A1XSMFD/nfXVc/pM6Cu7kdtHSwSKgbKKf6mrCeVgaM9xcG0t2W
+ 9yEtWvkdvOOSqz/vd1vkftbBWcCejX7bktfmD408CJAs1bjzz5CyrDoWcnYmbxFY
+ 6N4rhMDRMTe19VH2UQ4EvSjQjmmYCspnUW3/78zi5kU1ijyQy13UpbgwulU7tSGc
+ KKtBjPoy6mLIVl0YhnEJZWD/XPIRWyW+0s+7m70YXCWSVipvCelEE8oPWjf8PLaE
+ J85crlZGkSRcRO7yOP/YtB9ZnajgaF33zJU3ZWr0C/IXj2TeepZp/JUteD2H/LRf
+ 9YJzOFYDOFIWcdmaTzJLBEaefWcDjT6wkIf6TBqQRMLsu8JUwy9VwFcsi/d5aMXS
+ XgEQqSxYb1B39OR0sS1Xpw0/CFe4imBPuG3w0tOAyM3DbPWYY1kZYIRZenV1ZIOS
+ aRZJh086kuWgHYB76VoNzDK3QperWvHL/8CT2g3HuPiVGSrrXwxCYXk5+UXB9bQ=
+ =Xx91
+ -----END PGP MESSAGE-----
+ fp: 18DFCE01456DAB52EA38A6584EDC64F35FA1D6A5
+ - created_at: "2026-05-23T20:58:22Z"
+ enc: |-
+ -----BEGIN PGP MESSAGE-----
+
+ hF4DsZXvxFXTXoQSAQdA0rZTVdySF9nUiz7ZyFJgq1tojyLojGTgE4UIEJzFSTUw
+ 9y4kbGn1cWMpAqr+sE3WHV9p7v6kgm/XdUjXGN4DadpUbiYx6sQW2Jov6Km2EYhq
+ 0l4BawupjX25wi7c2yR5iGdxYS8oCYVmGgcAB3T96v8VsXpkAOYQAOOh7B9GQIxm
+ hB3cFQLCy2un3VvBsiKGFMA2FhZYBOuaEwP/KmWnPv0IPIRH4by6LDB0xgq8MUNz
+ =xoVE
+ -----END PGP MESSAGE-----
+ fp: 9633412309CCB83BFA39BA5F2FEF746201D7FCFE
+ - created_at: "2026-05-23T20:58:22Z"
+ enc: |-
+ -----BEGIN PGP MESSAGE-----
+
+ hF4DerEtaFuTeewSAQdAgcGcZ3BT6lsJ8FxkMghxg5/PZLtIzNeJaEUbxN0EFhsw
+ uM+Lec3k9BJSUJK8GeVmesYxQh8vP6Yi/+m2LnGjHXzkQg8Bx1HJzuC/Ap36rC6N
+ 0l4Bxj1URTsRD4yILEA3TY4Dn9St9uOtodJcf5YdAKvmeb3Uwy//huNnA1eK7b+v
+ WRHcU2K+GgkSzLiRLZTc/nMrrCQ/P5HzwYHmP2rypFX7kxXlPd3K6yMZWTiSgYZd
+ =gZLQ
+ -----END PGP MESSAGE-----
+ fp: 057870A2C72CD82566A3EC983695F4FCBCAE4912
+ - created_at: "2026-05-23T20:58:22Z"
+ enc: |-
+ -----BEGIN PGP MESSAGE-----
+
+ hQIMAxjNhCKPP69fAQ//YGOLOFtORNbOu+KFCtGcJBXQMy6Ej3/tePVuDi2vmqLD
+ 3Dz6stB9D+BmBbcgbFlDA+g7Vi6DD+zcze9wM10iuc9t9ucAuQ7B/ymSvJc4MrYn
+ MJFvQv5IYgWJmzXLYEFYYpmZPGG3hSHSgWIPs+574wEA/L867ktguW6ZD3ZuMn3E
+ yjCTeT/ZkGjuIpGqMu2/o9Wvc+RYgWlCB69D8kTHtnbFzbqEzvKU5/zte5ThchA+
+ QZwFd/gk3o1G/7WOYJJ6CbBSOQaSrfm0mnb6sppNPdOAQtqHVSFVX5vX96gXsht/
+ AkrvD6/2R5eNzbqRaU83cg7c5far49xoBbL6czreWY3D56yK4BJbrrg9mK7oCEfO
+ GaRDFFD7R4LJPfVx2xDoIQ3Hyp4E3dz4nyJx0Kg7NSEt7soOb5MnZ+04LLAiHbaT
+ qZr618V530uw3qaCsYcgHy+WsZXXlqXQey3A7jphi3u9Kvn9UjeegjNvpOrMk6g1
+ RhGzv72G0wjZnzjTjPlzeROHaQ6RPgfpkZjEcVZNZkfAgAbB3XPgCFGKz4qvx9MP
+ 4eHIlBSJizLzSi519o+0i5PwrZdEf9L4RUVxgQgdJXMh1JaydVh5DOU+xomdStD5
+ Maymkt8fSgYgDaS953YA2e04PrkXCH0EHZ62T9EMxreEoU3nYTmw/TGx7RfU+wzS
+ XgEuQkLWSToJ40/Ir3obDA246yv7J2FpmPwG4oFypkM5xe1WjlMlk90b9RBhUgXk
+ ylRXXLBzau6mtbPOa7LGdVyVs2DClWQo9BoK+dxEsnW+TR144O4UmZEfifJXvgQ=
+ =ympd
+ -----END PGP MESSAGE-----
+ fp: F38C9D4228FC6F674E322D9C3326D914EB9B8F55
+ - created_at: "2026-05-23T20:58:22Z"
+ enc: |-
+ -----BEGIN PGP MESSAGE-----
+
+ hQIMA46L6MuPqfJqARAAshm2x7wX/9g3XJtSN0AnSeCwSHO1I4+ebLKOsB7zcXh8
+ hrVO3694jQcU9L01H7jGYw4lNNzBd61/uVE5AvMq4Sqn9iH3MFNESbAEOWVV+TRf
+ 53JMg9C/aZfde8gHgHPaiVXlCBVEVY9CqHpUXUKDmEE7iRb5P4DuMxOmybDYZGzY
+ 4c5Ke1MFMkGRmAtsT1qLrT2vh+F0CX4JwpMkxCmOzSWAXbwrVOigJ35l5zM6vme4
+ 5EQu9jI8FApTxVchZbr0v3UOKxp5OebqC0jGeznZNf4qb0qnsvuowY6IIw5Tl3/q
+ H4TLq5EUOVqTC1voIWY/gMjieiW1gtr6vASy4MvbswsZLc26YVE9IbHzAOUWDN2o
+ f2iQ3aZYuINvniD23XtM0TKepDXWq5eF+AJpmyP/LL8sYvSnWFD+muK3O657djEu
+ yGZs2EFTrkiUvhBq3apOOYiU0eOi4Aq6UeEbOsLENnQrBRXuHEm4KUSwzOitVwJ1
+ ByxQTu7wzY727SOR2hzjMC0LI602WGpEQU7ech5L4uWqtMFwaBP9HnUamcofKqqt
+ 1vI2BevsJfQ0rtTE6GWseHt702lllTGe3RnHWc6YsMWLwUfRdBPggMW37hAPPcfO
+ ytbU3RJIxx4vImRtXhkI5yvbpFQrooz1zSeXWaitPE5jmmiKe9IRStLnfiq9E2TS
+ XgFVuQM8K0LgUYEoAipvafhnC3ohfGsM2AYd36EoaMNLeQ2ZZEiV06/Y3EWoI0iM
+ aqRLwyBvTuDOc5BK32nCbAgUbbPJjPhqWaoNp5ymCBV76oW613gApkzoUF+OIUU=
+ =KKaI
+ -----END PGP MESSAGE-----
+ fp: 8996B62CBD159DCADD3B6DC08BB33A8ABCF7BC4A
+ - created_at: "2026-05-23T20:58:22Z"
+ enc: |-
+ -----BEGIN PGP MESSAGE-----
+
+ hF4DQrf1tCqiJxoSAQdA8YKD21h5POTLPf04KvGN93omFgkYO+Y8Kc0jM0vdqm8w
+ 3zYRaLsDjdh8Zd89/HhHJUfLrTp/IJ0n81sK0ZjznbXKxgkseGthMzof+L7BnPAp
+ 0l4BnAs9iZS4q2LZVS7ySBP89xLmF97qhK2jagMNSAwq8Afxbcw8oQAVQmeyYfxx
+ X59irIHjI1ugO4o1WnTN67nTQjU5msbVBs0eALrw3jobzFHRL67fS0a4Soa59LTY
+ =ZHIU
+ -----END PGP MESSAGE-----
+ fp: B71138A6A8964A3C3B8899857B4F70C356765BAB
+ - created_at: "2026-05-23T20:58:22Z"
+ enc: |-
+ -----BEGIN PGP MESSAGE-----
+
+ hF4DzAGzViGx4qcSAQdAN7rRlv3dMoFOfj9eHgf+0H8521b32nWqySUdriEy6Tcw
+ gjuReMBpKQOgUfuhIiWkHIKNtNgMrYWiC20ESOXX5b9uYZNpqHCgHQPlX0lEeGim
+ 0lgBOieL7mSEq4wkWLCSv4sBAmkQA+dnugBeF+TrlqKQTZsbe/Z+jNG4ZrHRvdqi
+ 4I5It+uaRV9Vrul1c6H7fNreRPUd4hNyJwU7gZQ+vU2WyAmgqerxE1Wb
+ =gplT
+ -----END PGP MESSAGE-----
+ fp: D2E9C0807BF681F5E164DAFC5EE1B61CD90954CD
+ - created_at: "2026-05-23T20:58:22Z"
+ enc: |-
+ -----BEGIN PGP MESSAGE-----
+
+ hQIMA2pVdGTIrZI+ARAAjWK8mU99VcnM/Ckzm+YsZFTwnz4PDAenDDdZ1OOz5IXe
+ tS4SQPcQlSSOuXEkFLJMmm8QVxtUC3Gh4nF7o+7OygT+0ZXOrB7jFgg10+v/KVA9
+ hSlqBdsMxcC0OzBtkGyAOXOxqnTVubuHEGyGpIryHt1/lthUUZHBbjgw7P0Tw2/U
+ sYK5j5YbqhyBl20gyZorkTTq7pHfVXDVtpe75+ZkqbOg4S6HgW3/dl+v6N0TLfRs
+ GVl0fUlWIK/akGCB71zdwJs2I1qTeMTlL6v+XSUdXj0YV+5fjh3wf8qzN9geIjQK
+ ybxGFWDKCAgTMnqoFF5BCL23hFtnCbTtLN1wQT7/m7zpjaBKHOBXZOGXYZCMGZui
+ sBsUvPANgNdfOse9H2aABQvUQh8WqFw8S73GasvrZHAwEmvnXzocMJd+kUovzmQu
+ 9FBk5UkcgXfmxeamoP8C700vh4zI+sKz6uEW0+AuVtLlLVqlb2w21kTc+ArZW52n
+ HLolH5q3Wj6pKuuFCWKr6UgLFcq2w4QngB2p+UABHU3RbwXIra7prDXCUcNC5iCn
+ ElRFY7OZ3nbHOf9oaW/MitcfszVLyl0ueoay6qxdlIGdXKRGpqxHqqr+92INV/iz
+ 6CRoAsTqVq1a7ZuAaUdJPvfKVAHHEHjPwlrOc9cXvykG0iQKsRzgqiOtPiGQShnU
+ aAEJAhDSqCwywHDnQ7X9ZWIzPjwvqyHpEVez8zYh3vpgKpsLb9uL+JizZjV02HMe
+ nhiL+4o/aNjJgGJWph1uPFhU4wO4AavnNBsHbJSiL/1yTS96hdf8d+gB41yVLU3e
+ kBkDFLKkIBkU
+ =aRLd
+ -----END PGP MESSAGE-----
+ fp: 878FEA3CB6A6F6E7CD80ECBE28506E3585F9F533
+ - created_at: "2026-05-23T20:58:22Z"
+ enc: |-
+ -----BEGIN PGP MESSAGE-----
+
+ hF4DKKbvh61jX5USAQdABId/P8ozRgJ4ItF1zvxp98aH+g3LZ6UGnxjYjtDxjEIw
+ VmyerznjOLnpz0EobXRRoot1Lo82Va64HQmXt26LG3gFY1HVp0WOnIZXa/CUoUb8
+ 1GgBCQIQloFxKcgFTiRidaJfN7hSeQLleiEe3aifZUyJj8niTmBaY29t+CSoA46N
+ xZzX1AlxVjfmputhYdTyOYSJtGrj7otmnUN2P+55pjz4L2qCYAEKi1+ibqgpmJh/
+ bETQsT6WKJ8FXA==
+ =Ci7L
+ -----END PGP MESSAGE-----
+ fp: 41FFAF3D519CF5C039FBD8414BCC213729AF0E49
+ unencrypted_suffix: _unencrypted
+ version: 3.13.1
diff --git a/inventories/z9/host_vars/rt1.yaml b/inventories/z9/host_vars/rt1.yaml
new file mode 100644
index 0000000..218f4c4
--- /dev/null
+++ b/inventories/z9/host_vars/rt1.yaml
@@ -0,0 +1,6 @@
+systemd_networkd__config_dir: 'resources/z9/rt1/systemd_networkd/'
+systemd_networkd__global_config: "{{ lookup('ansible.builtin.file', 'resources/z9/rt1/systemd_networkd_global_config.conf') }}"
+nftables__config: "{{ lookup('ansible.builtin.file', 'resources/z9/rt1/nftables/nftables.conf') }}"
+ansible_pull__timer_on_calendar: "*-*-* 04:00:00 Europe/Berlin"
+ansible_pull__timer_randomized_delay_sec: 0min
+unbound_access_control: [ "10.89.208.0/20" ]
diff --git a/inventories/z9/hosts.yaml b/inventories/z9/hosts.yaml
index eab3880..d4c4ff4 100644
--- a/inventories/z9/hosts.yaml
+++ b/inventories/z9/hosts.yaml
@@ -14,6 +14,9 @@ all:
yate:
ansible_host: yate.ccchh.net
ansible_user: chaos
+ rt1:
+ ansible_host: rt1.ccchh.net
+ ansible_user: chaos
certbot_hosts:
hosts:
dooris:
@@ -35,6 +38,7 @@ infrastructure_authorized_keys_hosts:
light:
waybackproxy:
yate:
+ rt1:
nginx_hosts:
hosts:
dooris:
@@ -46,6 +50,12 @@ ola_hosts:
proxmox_vm_template_hosts:
hosts:
thinkcccore0:
+systemd_networkd_hosts:
+ hosts:
+ rt1:
+nftables_hosts:
+ hosts:
+ rt1:
alloy_hosts:
hosts:
light:
@@ -59,3 +69,4 @@ ansible_pull_hosts:
yate:
secrets_hosts:
hosts:
+ rt1:
diff --git a/resources/z9/rt1/nftables/nftables.conf b/resources/z9/rt1/nftables/nftables.conf
new file mode 100644
index 0000000..21bfbd1
--- /dev/null
+++ b/resources/z9/rt1/nftables/nftables.conf
@@ -0,0 +1,111 @@
+#!/usr/sbin/nft -f
+
+## Variables
+
+# Hosts
+
+
+# Interfaces
+define if_netwan = "netwan"
+define if_netlan = "netlan"
+define if_wg55_management = "wg55"
+define if_netwan_400_fux_uplink = "netwan.400"
+define if_netlan_51_clients = "netlan.51"
+define if_netlan_52_iot = "netlan.52"
+define if_netlan_53_public = "netlan.53"
+define if_netlan_54_management = "netlan.54"
+
+# Interface Groups
+define wan_ifs = { $if_netwan_400_fux_uplink }
+define lan_ifs = { $if_netlan_51_clients,
+ $if_netlan_52_iot,
+ $if_netlan_53_public,
+ $if_netlan_54_management }
+define v4_exposed_ifs = { $if_netlan_53_public }
+define v6_exposed_ifs = { $if_netlan_53_public }
+define v4_nat_ifs = { $if_netlan_51_clients,
+ $if_netlan_52_iot,
+ $if_netlan_54_management }
+
+
+## Rules
+
+table inet reverse-path-forwarding {
+ chain rpf-filter {
+ type filter hook prerouting priority mangle + 10; policy drop;
+
+ # Only allow packets if their source address is routed via their incoming interface.
+ # https://github.com/NixOS/nixpkgs/blob/d9d87c51960050e89c79e4025082ed965e770d68/nixos/modules/services/networking/firewall-nftables.nix#L100
+ fib saddr . mark . iif oif exists accept
+ }
+}
+
+table inet host {
+ chain input {
+ type filter hook input priority filter; policy drop;
+
+ iifname "lo" accept comment "allow loopback"
+
+ ct state invalid drop
+ ct state established,related accept
+
+ ip protocol icmp accept
+ # ICMPv6
+ # https://datatracker.ietf.org/doc/html/rfc4890#autoid-24
+ # Allowlist consisting of: "Traffic That Must Not Be Dropped" and "Traffic That Normally Should Not Be Dropped"
+ # Error messages that are essential to the establishment and maintenance of communications:
+ icmpv6 type { destination-unreachable, packet-too-big } accept
+ icmpv6 type { time-exceeded } accept
+ icmpv6 type { parameter-problem } accept
+ # Connectivity checking messages:
+ icmpv6 type { echo-request, echo-reply } accept
+ # Address Configuration and Router Selection messages:
+ icmpv6 type { nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert } accept
+ # Link-Local Multicast Receiver Notification messages:
+ icmpv6 type { mld-listener-query, mld-listener-report, mld-listener-done, mld2-listener-report } accept
+ # SEND Certificate Path Notification messages:
+ icmpv6 type { 148, 149 } accept
+ # Multicast Router Discovery messages:
+ icmpv6 type { 151, 152, 153 } accept
+
+ # Allow SSH access.
+ tcp dport 22 accept comment "allow ssh access"
+
+ # Allow WireGuard access.
+ udp dport 51820 accept comment "allow WireGuard access"
+
+ # Allow DHCP server access.
+ iifname { $lan_ifs } udp dport 67 accept comment "allow dhcp server access"
+ }
+}
+
+table ip v4nat {
+ chain prerouting {
+ type nat hook prerouting priority dstnat; policy accept;
+ }
+
+ chain postrouting {
+ type nat hook postrouting priority srcnat; policy accept;
+
+ iifname { $v4_nat_ifs, $if_wg55_management } oifname $wan_ifs masquerade
+ }
+}
+
+table inet forward {
+ chain forward {
+ type filter hook forward priority filter; policy drop;
+
+ ct state invalid drop
+ ct state established,related accept
+
+ # Allow internet access.
+ iifname { $lan_ifs, $if_wg55_management } oifname $wan_ifs accept comment "allow internet access"
+
+ # Allow access to exposed networks from internet.
+ meta nfproto ipv4 oifname $v4_exposed_ifs accept comment "allow v4 exposed network access"
+ meta nfproto ipv6 oifname $v6_exposed_ifs accept comment "allow v6 exposed network access"
+
+ # Allow clients and managment to most
+ iifname { $if_netlan_51_clients, $if_netlan_54_management, $if_wg55_management } oifname $lan_ifs accept comment "allow clients and managment to lan_ifs"
+ }
+}
diff --git a/resources/z9/rt1/systemd_networkd/00-netlan.link b/resources/z9/rt1/systemd_networkd/00-netlan.link
new file mode 100644
index 0000000..c2e2470
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/00-netlan.link
@@ -0,0 +1,6 @@
+[Match]
+MACAddress=BC:24:11:72:A3:27
+Type=ether
+
+[Link]
+Name=netlan
diff --git a/resources/z9/rt1/systemd_networkd/00-netwan.link b/resources/z9/rt1/systemd_networkd/00-netwan.link
new file mode 100644
index 0000000..523e18a
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/00-netwan.link
@@ -0,0 +1,6 @@
+[Match]
+MACAddress=BC:24:11:CF:65:57
+Type=ether
+
+[Link]
+Name=netwan
diff --git a/resources/z9/rt1/systemd_networkd/10-netlan.51.netdev b/resources/z9/rt1/systemd_networkd/10-netlan.51.netdev
new file mode 100644
index 0000000..b951ecc
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/10-netlan.51.netdev
@@ -0,0 +1,7 @@
+[NetDev]
+Name=netlan.51
+Kind=vlan
+
+[VLAN]
+Id=51
+
diff --git a/resources/z9/rt1/systemd_networkd/10-netlan.52.netdev b/resources/z9/rt1/systemd_networkd/10-netlan.52.netdev
new file mode 100644
index 0000000..1f345c7
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/10-netlan.52.netdev
@@ -0,0 +1,7 @@
+[NetDev]
+Name=netlan.52
+Kind=vlan
+
+[VLAN]
+Id=52
+
diff --git a/resources/z9/rt1/systemd_networkd/10-netlan.53.netdev b/resources/z9/rt1/systemd_networkd/10-netlan.53.netdev
new file mode 100644
index 0000000..c6dab81
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/10-netlan.53.netdev
@@ -0,0 +1,7 @@
+[NetDev]
+Name=netlan.53
+Kind=vlan
+
+[VLAN]
+Id=53
+
diff --git a/resources/z9/rt1/systemd_networkd/10-netlan.54.netdev b/resources/z9/rt1/systemd_networkd/10-netlan.54.netdev
new file mode 100644
index 0000000..6271e6c
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/10-netlan.54.netdev
@@ -0,0 +1,7 @@
+[NetDev]
+Name=netlan.54
+Kind=vlan
+
+[VLAN]
+Id=54
+
diff --git a/resources/z9/rt1/systemd_networkd/10-netwan.400.netdev b/resources/z9/rt1/systemd_networkd/10-netwan.400.netdev
new file mode 100644
index 0000000..e0b6afc
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/10-netwan.400.netdev
@@ -0,0 +1,7 @@
+[NetDev]
+Name=netwan.400
+Kind=vlan
+
+[VLAN]
+Id=400
+
diff --git a/resources/z9/rt1/systemd_networkd/10-wg55.netdev b/resources/z9/rt1/systemd_networkd/10-wg55.netdev
new file mode 100644
index 0000000..b3e41a6
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/10-wg55.netdev
@@ -0,0 +1,90 @@
+[NetDev]
+Description=Admin-Wireguard
+Kind=wireguard
+Name=wg55
+
+[WireGuard]
+ListenPort=51820
+PrivateKeyFile=/etc/ansible_secrets/wireguard_wg55_privat_key
+
+# WireGuard Peers
+
+[WireGuardPeer]
+# friendly_name = stb
+AllowedIPs = 10.89.214.2/32,2a07:c481:1:37::2/128
+PublicKey = vILSL4dbaC5IaTsRhJviamV18ssxWSj+qLVyowLQ214=
+PersistentKeepalive = 30
+
+[WireGuardPeer]
+# friendly_name = fi
+AllowedIPs = 10.89.214.3/32,2a07:c481:1:37::3/128
+PublicKey = UHi/if5uW2V3+8Q3R+uk6/XpRi4fPXbw7chsKI4xlkI=
+PresharedKeyFile = /etc/ansible_secrets/wireguard_wg55_peer_fi_psk
+
+[WireGuardPeer]
+# friendly_name = jtbx
+AllowedIPs = 10.89.214.4/32,2a07:c481:1:37::4/128
+PublicKey = NyyEqdWgScgsnTF8Zz/Om4Lc84fdFMwVtvaCmLEkUlQ=
+
+[WireGuardPeer]
+# friendly_name = June
+AllowedIPs = 10.89.214.6/32,2a07:c481:1:37::6/128
+PublicKey = 6jAEB+f9przBGxPhuvv9U9gvZDEBQNqpQSD0BoGqXQQ=
+PresharedKeyFile = /etc/ansible_secrets/wireguard_wg55_peer_June_psk
+
+[WireGuardPeer]
+# friendly_name = Max
+AllowedIPs = 10.89.214.7/32,2a07:c481:1:37::7/128
+PublicKey = oC1hJjtlAgLX/CmbwTC+LPmd1uwluQTwsN8RaMNmHn0=
+PresharedKeyFile = /etc/ansible_secrets/wireguard_wg55_peer_Max_psk
+
+[WireGuardPeer]
+# friendly_name = dario
+AllowedIPs = 10.89.214.9/32,2a07:c481:1:37::9/128
+PublicKey = bYF2EGRGpEGjiKcasi/oaWoWeLsgqsF6FGaq3Z4ERww=
+PresharedKeyFile = /etc/ansible_secrets/wireguard_wg55_peer_dario_psk
+
+[WireGuardPeer]
+# friendly_name = June-mobile
+AllowedIPs = 10.89.214.11/32,2a07:c481:1:37::11/128
+PublicKey = 6edjXykegUgGjbkIG1aJyBlX1SgTKcqXXaSBVPHdKDc=
+PresharedKeyFile = /etc/ansible_secrets/wireguard_wg55_peer_June-mobile_psk
+
+[WireGuardPeer]
+# friendly_name = djerun_at_ferrum.local
+AllowedIPs = 10.89.214.12/32,2a07:c481:1:37::12/128
+PublicKey = aHbdkTHhPkd+o7wWfTua9nd72aF4OVp66zGtpaoD8Fg=
+
+[WireGuardPeer]
+# friendly_name = c6ristian
+AllowedIPs = 10.89.214.13/32,2a07:c481:1:37::13/128
+PublicKey = 6ndwj3Ur6AqfUPWuyPYXIaGZs2ujJKawSQ9LEvlYzEc=
+PresharedKeyFile = /etc/ansible_secrets/wireguard_wg55_peer_c6ristian_psk
+
+[WireGuardPeer]
+# friendly_name = langoor
+AllowedIPs = 10.89.214.14/32,2a07:c481:1:37::14/128
+PublicKey = qTnVQlQa1m4SucFFNli/xM6QWfsdWx2baRAit7Cg8RM=
+PresharedKeyFile = /etc/ansible_secrets/wireguard_wg55_peer_langoor_psk
+
+[WireGuardPeer]
+# friendly_name = langoor_home
+AllowedIPs = 10.89.214.15/32,2a07:c481:1:37::15/128
+PublicKey = NeMDs2+5rHuKO5ZYXVUR76GorgdesFUnDOFECQ3RzG4=
+PresharedKeyFile = /etc/ansible_secrets/wireguard_wg55_peer_langoor_home_psk
+
+[WireGuardPeer]
+# friendly_name = lilly-lillysLaptop
+AllowedIPs = 10.89.214.16/32 #,2a07:c481:1:37::/128
+PublicKey = IBsI+N8qUNpQnDc5HnqQ2Zo/1graFM0RMIecHmAF+Vk=
+
+[WireGuardPeer]
+# friendly_name = bitwhisker
+AllowedIPs = 10.89.214.17/32,2a07:c481:1:37::a/128
+PublicKey = DvEGvQPGi+IxeRTIA72Gx3WNINcrV9HRNB1v7mHnhjA=
+
+[WireGuardPeer]
+# friendly_name = forestcat
+AllowedIPs = 10.89.214.18/32,2a07:c481:1:37::b/128
+PublicKey = PdJ7KlIeASizj0WTY87d7oSi14/MebrhRa+L8YiPoQE=
+
diff --git a/resources/z9/rt1/systemd_networkd/20-netlan.network b/resources/z9/rt1/systemd_networkd/20-netlan.network
new file mode 100644
index 0000000..3aed715
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/20-netlan.network
@@ -0,0 +1,12 @@
+[Match]
+Name=netlan
+
+[Link]
+RequiredForOnline=no
+
+[Network]
+VLAN=netwan.51
+VLAN=netwan.52
+VLAN=netwan.53
+VLAN=netwan.54
+
diff --git a/resources/z9/rt1/systemd_networkd/20-netwan.network b/resources/z9/rt1/systemd_networkd/20-netwan.network
new file mode 100644
index 0000000..89a8494
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/20-netwan.network
@@ -0,0 +1,9 @@
+[Match]
+Name=netwan
+
+[Link]
+RequiredForOnline=no
+
+[Network]
+VLAN=netwan.400
+
diff --git a/resources/z9/rt1/systemd_networkd/20-wg55.network b/resources/z9/rt1/systemd_networkd/20-wg55.network
new file mode 100644
index 0000000..750e844
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/20-wg55.network
@@ -0,0 +1,6 @@
+[Match]
+Name=wg55
+
+[Network]
+Address=10.89.214.1/24
+Address=2a07:c481:1:37::1/64
diff --git a/resources/z9/rt1/systemd_networkd/21-netlan.51-clients.network b/resources/z9/rt1/systemd_networkd/21-netlan.51-clients.network
new file mode 100644
index 0000000..5e9635f
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/21-netlan.51-clients.network
@@ -0,0 +1,27 @@
+[Match]
+Name=netlan.51
+Type=vlan
+
+[Link]
+RequiredForOnline=no
+
+[Network]
+Description=clients
+
+# Masquerading done in nftables (nftables.conf).
+IPv6SendRA=yes
+
+[Address]
+Address=10.89.208.1/22
+
+[IPv6SendRA]
+UplinkInterface=netwan.400
+EmitDomains=true
+Domains=ccchh.net
+Managed=true
+
+[IPv6Prefix]
+Prefix=2a07:c481:1:33::/64
+Assign=true
+Token=static:::1
+
diff --git a/resources/z9/rt1/systemd_networkd/21-netlan.52-iot.network b/resources/z9/rt1/systemd_networkd/21-netlan.52-iot.network
new file mode 100644
index 0000000..5b58610
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/21-netlan.52-iot.network
@@ -0,0 +1,27 @@
+[Match]
+Name=netlan.52
+Type=vlan
+
+[Link]
+RequiredForOnline=no
+
+[Network]
+Description=IoT
+
+# Masquerading done in nftables (nftables.conf).
+IPv6SendRA=yes
+
+[Address]
+Address=10.89.212.1/24
+
+[IPv6SendRA]
+UplinkInterface=netwan.400
+EmitDomains=true
+Domains=ccchh.net
+Managed=true
+
+[IPv6Prefix]
+Prefix=2a07:c481:1:34::/64
+Assign=true
+Token=static:::1
+
diff --git a/resources/z9/rt1/systemd_networkd/21-netlan.53-public.network b/resources/z9/rt1/systemd_networkd/21-netlan.53-public.network
new file mode 100644
index 0000000..f544a5b
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/21-netlan.53-public.network
@@ -0,0 +1,27 @@
+[Match]
+Name=netlan.53
+Type=vlan
+
+[Link]
+RequiredForOnline=no
+
+[Network]
+Description=public
+
+# Masquerading done in nftables (nftables.conf).
+IPv6SendRA=yes
+
+[Address]
+Address=185.161.130.65/28
+
+[IPv6SendRA]
+UplinkInterface=netwan.400
+EmitDomains=true
+Domains=ccchh.net
+Managed=true
+
+[IPv6Prefix]
+Prefix=2a07:c481:1:35::/64
+Assign=true
+Token=static:::1
+
diff --git a/resources/z9/rt1/systemd_networkd/21-netlan.54-management.network b/resources/z9/rt1/systemd_networkd/21-netlan.54-management.network
new file mode 100644
index 0000000..2396da0
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/21-netlan.54-management.network
@@ -0,0 +1,27 @@
+[Match]
+Name=netlan.54
+Type=vlan
+
+[Link]
+RequiredForOnline=no
+
+[Network]
+Description=Management
+
+# Masquerading done in nftables (nftables.conf).
+IPv6SendRA=yes
+
+[Address]
+Address=10.89.213.0/24
+
+[IPv6SendRA]
+UplinkInterface=netwan.400
+EmitDomains=true
+Domains=ccchh.net
+Managed=true
+
+[IPv6Prefix]
+Prefix=2a07:c481:1:36::/64
+Assign=true
+Token=static:::1
+
diff --git a/resources/z9/rt1/systemd_networkd/21-netwan.400-fux_uplink.network b/resources/z9/rt1/systemd_networkd/21-netwan.400-fux_uplink.network
new file mode 100644
index 0000000..1657c40
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd/21-netwan.400-fux_uplink.network
@@ -0,0 +1,26 @@
+[Match]
+Name=netwan.400
+Type=vlan
+
+[Link]
+RequiredForOnline=no
+
+[Network]
+Description=fux-uplink
+
+DNS=185.161.128.66
+DNS=2a07:c481:0:4::2
+DNS=185.161.128.67
+DNS=2a07:c481:0:4::3
+
+IPv6AcceptRA=no
+# Masquerading done in nftables (nftables.conf).
+IPv6SendRA=no
+
+[Address]
+Address=185.161.129.134/25
+Address=2a07:c481::1:2/64
+
+[Route]
+Gateway=185.161.129.129
+Gateway=2a07:c481::1
diff --git a/resources/z9/rt1/systemd_networkd_global_config.conf b/resources/z9/rt1/systemd_networkd_global_config.conf
new file mode 100644
index 0000000..2d3d8a3
--- /dev/null
+++ b/resources/z9/rt1/systemd_networkd_global_config.conf
@@ -0,0 +1,3 @@
+[Network]
+IPv4Forwarding=true
+IPv6Forwarding=true
From bbf45e91f452c901dc317f30e43a31fa4ce9a066 Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Sun, 24 May 2026 04:01:11 +0200
Subject: [PATCH 03/14] rt1(z9 host) unbound(role) kea_dhcp(role): create
unbound and kea_dhcp role for rt1
- create unbound role
- create kea_dhcp role
- configure unbound and keadhcp on rt1(z9 host)
---
inventories/z9/host_vars/rt1.yaml | 1 +
inventories/z9/hosts.yaml | 7 +
playbooks/deploy.yaml | 14 +
resources/z9/rt1/kea_dhcp.yaml | 293 ++++++++++++++++++
resources/z9/rt1/nftables/nftables.conf | 3 +
roles/kea_dhcp/defaults/main.yaml | 69 +++++
roles/kea_dhcp/handlers/main.yml | 30 ++
roles/kea_dhcp/meta/argument_specs.yaml | 125 ++++++++
roles/kea_dhcp/tasks/install_archlinux.yml | 8 +
roles/kea_dhcp/tasks/install_debian.yml | 22 ++
roles/kea_dhcp/tasks/kea.yaml | 51 +++
roles/kea_dhcp/tasks/main.yml | 19 ++
roles/kea_dhcp/tasks/stork-agent.yaml | 76 +++++
.../kea_dhcp/templates/kea-ctrl-agent.conf.j2 | 20 ++
roles/kea_dhcp/templates/kea-dhcp4.conf.jinja | 27 ++
roles/kea_dhcp/templates/kea-dhcp6.conf.jinja | 27 ++
.../kea_dhcp/templates/stork-agent.env.jinja | 44 +++
roles/unbound/README.md | 19 ++
roles/unbound/defaults/main.yml | 7 +
roles/unbound/files/no-resolved.resolv.conf | 1 +
roles/unbound/handlers/main.yml | 27 ++
roles/unbound/tasks/main.yml | 63 ++++
roles/unbound/tasks/prometheus-exporter.yml | 17 +
roles/unbound/templates/unbound.conf.j2 | 73 +++++
24 files changed, 1043 insertions(+)
create mode 100644 resources/z9/rt1/kea_dhcp.yaml
create mode 100644 roles/kea_dhcp/defaults/main.yaml
create mode 100644 roles/kea_dhcp/handlers/main.yml
create mode 100644 roles/kea_dhcp/meta/argument_specs.yaml
create mode 100644 roles/kea_dhcp/tasks/install_archlinux.yml
create mode 100644 roles/kea_dhcp/tasks/install_debian.yml
create mode 100644 roles/kea_dhcp/tasks/kea.yaml
create mode 100644 roles/kea_dhcp/tasks/main.yml
create mode 100644 roles/kea_dhcp/tasks/stork-agent.yaml
create mode 100644 roles/kea_dhcp/templates/kea-ctrl-agent.conf.j2
create mode 100644 roles/kea_dhcp/templates/kea-dhcp4.conf.jinja
create mode 100644 roles/kea_dhcp/templates/kea-dhcp6.conf.jinja
create mode 100644 roles/kea_dhcp/templates/stork-agent.env.jinja
create mode 100644 roles/unbound/README.md
create mode 100644 roles/unbound/defaults/main.yml
create mode 100644 roles/unbound/files/no-resolved.resolv.conf
create mode 100644 roles/unbound/handlers/main.yml
create mode 100644 roles/unbound/tasks/main.yml
create mode 100644 roles/unbound/tasks/prometheus-exporter.yml
create mode 100644 roles/unbound/templates/unbound.conf.j2
diff --git a/inventories/z9/host_vars/rt1.yaml b/inventories/z9/host_vars/rt1.yaml
index 218f4c4..876776a 100644
--- a/inventories/z9/host_vars/rt1.yaml
+++ b/inventories/z9/host_vars/rt1.yaml
@@ -4,3 +4,4 @@ nftables__config: "{{ lookup('ansible.builtin.file', 'resources/z9/rt1/nftables/
ansible_pull__timer_on_calendar: "*-*-* 04:00:00 Europe/Berlin"
ansible_pull__timer_randomized_delay_sec: 0min
unbound_access_control: [ "10.89.208.0/20" ]
+kea_dhcp__include_vars: resources/z9/rt1/kea_dhcp.yaml
diff --git a/inventories/z9/hosts.yaml b/inventories/z9/hosts.yaml
index d4c4ff4..407aa2f 100644
--- a/inventories/z9/hosts.yaml
+++ b/inventories/z9/hosts.yaml
@@ -56,11 +56,18 @@ systemd_networkd_hosts:
nftables_hosts:
hosts:
rt1:
+unbound_hosts:
+ hosts:
+ rt1:
+kea_dhcp_hosts:
+ hosts:
+ rt1:
alloy_hosts:
hosts:
light:
yate:
dooris:
+ rt1:
ansible_pull_hosts:
hosts:
dooris:
diff --git a/playbooks/deploy.yaml b/playbooks/deploy.yaml
index b7ce104..54d4098 100644
--- a/playbooks/deploy.yaml
+++ b/playbooks/deploy.yaml
@@ -27,6 +27,20 @@
tags:
- nftables
+- name: Ensure unbound deployment on unbound_hosts
+ hosts: unbound_hosts
+ roles:
+ - unbound
+ tags:
+ - unbound
+
+- name: Ensure kea_dhcp deployment on kea_dhcp_hosts
+ hosts: kea_dhcp_hosts
+ roles:
+ - kea_dhcp
+ tags:
+ - kea_dhcp
+
- name: Ensure deployment of infrastructure authorized keys
hosts: infrastructure_authorized_keys_hosts
roles:
diff --git a/resources/z9/rt1/kea_dhcp.yaml b/resources/z9/rt1/kea_dhcp.yaml
new file mode 100644
index 0000000..d191881
--- /dev/null
+++ b/resources/z9/rt1/kea_dhcp.yaml
@@ -0,0 +1,293 @@
+kea_dhcp__dns_servers:
+ v4:
+ - 185.161.129.134
+ v6:
+ - 2a07:c481::1:2
+
+kea_dhcp__dhcp4:
+ enable: true
+ interfaces: [ "netlan.51", "netlan.52", "netlan.54" ]
+ control-sockets:
+ - socket-name: /var/run/kea-dhcp4-ctrl-agent.sock
+ socket-type: unix
+ lease-database:
+ type: memfile
+ persist: true
+ option-data:
+ - name: "domain-name-servers"
+ code: 6
+ csv-format: true
+ data: "{{ kea_dhcp__dns_servers.v4 | join(',') }}"
+ subnets:
+ - id: 1
+ subnet: 10.89.208.0/22
+ pools:
+ - pool: "10.89.208.32 - 10.89.211.250"
+ reservations:
+ - ip-address: 10.89.208.11
+ hostname: beamer
+ hw-address: "ac:87:a3:18:9e:01"
+ - ip-address: 10.89.208.12
+ hostname: Brother-CCCHH
+ hw-address: "00:80:77:04:3a:55"
+ - ip-address: 10.89.208.13
+ hostname: muzak
+ hw-address: "00:11:24:5f:4f:80"
+ - ip-address: 10.89.208.14
+ hostname: Big-Room-Beamer
+ hw-address: "64:d2:c4:db:08:5c"
+ - ip-address: 10.89.208.16
+ hostname: dooris
+ hw-address: "bc:24:11:b3:93:9c"
+ - ip-address: 10.89.208.17
+ hostname: hmdooris-ccu
+ hw-address: "bc:24:11:5f:2d:b1"
+ - ip-address: 10.89.208.27
+ hostname: cisco-slm248p
+ hw-address: "00:23:eb:b0:fc:3f"
+ - ip-address: 10.89.208.47
+ hw-address: "6c:df:fb:0b:34:21"
+ - ip-address: 10.89.208.48
+ hw-address: "6c:df:fb:0d:91:63"
+ - ip-address: 10.89.209.28
+ hostname: hp-color
+ hw-address: "3c:52:82:29:21:79"
+ - ip-address: 10.89.209.29
+ hostname: dooris-ng
+ hw-address: "6c:4b:90:19:21:a1"
+ - ip-address: 10.89.209.166
+ hostname: encoder-ccchh
+ hw-address: "00:4e:01:a2:40:d7"
+ - ip-address: 10.89.209.254
+ hostname: ki10
+ hw-address: "dc:a6:32:a9:ff:82"
+ option-data:
+ - name: routers,
+ csv-format: true
+ data: 10.89.208.1
+ - id: 2
+ subnet: 10.89.212.0/24
+ pools:
+ - pool: "10.89.212.32 - 10.89.212.250"
+ reservations:
+ - ip-address: 10.89.212.3
+ hostname: prusamk3
+ hw-address: "10:9c:70:2e:59:3e"
+ - ip-address: 10.89.212.4
+ hostname: prusamk4
+ hw-address: "10:9c:70:2e:6e:f0"
+ - ip-address: 10.89.212.11
+ hostname: Ziggy
+ hw-address: "44:17:93:53:65:57"
+ - ip-address: 10.89.212.12
+ hostname: legacy
+ hw-address: "00:15:65:a1:ed:98"
+ - ip-address: 10.89.212.23
+ hostname: foobarpay
+ hw-address: "f4:f2:6d:09:a6:73"
+ - ip-address: 10.89.212.24
+ hostname: foobackup
+ hw-address: "bc:24:11:20:1a:a8"
+ - ip-address: 10.89.212.27
+ hostname: ender3v2-sonic-pad
+ hw-address: "fc:ee:91:00:0e:14"
+ - ip-address: 10.89.212.31
+ hostname: octopi
+ hw-address: "b8:27:eb:0f:d8:09"
+ - ip-address: 10.89.212.32
+ hostname: 433mhz-bridge
+ hw-address: "0c:b8:15:fe:e3:34"
+ - ip-address: 10.89.212.33
+ hostname: wled-kueche
+ hw-address: "30:ae:a4:7a:8d:a0"
+ - ip-address: 10.89.212.34
+ hostname: wled-serverschrank
+ hw-address: "18:fe:34:a6:64:76"
+ - ip-address: 10.89.212.35
+ hostname: wled-couch
+ hw-address: "64:b7:08:40:ab:c0"
+ - ip-address: 10.89.212.36
+ hostname: laser
+ hw-address: "b8:27:eb:be:38:fa"
+ - ip-address: 10.89.212.37
+ hostname: laser-eth
+ hw-address: "b8:27:eb:eb:6d:af"
+ - ip-address: 10.89.212.42
+ hostname: t-mix
+ hw-address: "40:a5:ef:d9:eb:93"
+ - ip-address: 10.89.212.86
+ hostname: fritz-fon
+ hw-address: "00:1f:3f:c9:e5:b2"
+ - ip-address: 10.89.212.211
+ hostname: hauptraum-esphome
+ hw-address: "e8:db:84:e8:18:d2"
+ - ip-address: 10.89.212.212
+ hostname: werkstatt-esphome
+ hw-address: "3c:71:bf:26:42:32"
+ - ip-address: 10.89.212.213
+ hostname: ir-bridge-beamer
+ hw-address: "8c:ce:4e:51:93:dd"
+ - ip-address: 10.89.212.215
+ hostname: pi-dmx-werkstatt
+ hw-address: "b8:27:eb:65:e5:31"
+ - ip-address: 10.89.212.227
+ hostname: SIP-T46S
+ hw-address: "80:5e:c0:09:bf:55"
+ - ip-address: 10.89.212.230
+ hostname: SIP-T46S
+ hw-address: "80:5e:c0:22:33:08"
+ - ip-address: 10.89.212.232
+ hostname: staubi
+ hw-address: "b8:4d:43:98:51:2b"
+ - ip-address: 10.89.212.233
+ hostname: staubiv2
+ hw-address: "70:c9:32:82:25:b2"
+ - ip-address: 10.89.212.234
+ hostname: AtemMini
+ hw-address: "7c:2e:0d:13:72:a8"
+ - ip-address: 10.89.212.235
+ hostname: okilaser
+ hw-address: "2c:ff:65:22:b4:63"
+ - ip-address: 10.89.212.236
+ hw-address: "b8:27:eb:29:bd:77"
+ option-data:
+ - name: routers,
+ csv-format: true
+ data: 10.89.212.1
+ - id: 3
+ subnet: 10.89.213.0/24
+ pools:
+ - pool: "10.89.213.32 - 10.89.213.250"
+ reservations:
+ - ip-address: 10.89.213.2
+ hostname: sw-rack-1
+ hw-address: "F0:9F:C2:10:C3:AA"
+ - ip-address: 10.89.213.3
+ hostname: sw-rack-2-peo
+ hw-address: "44:d9:e7:06:69:5d"
+ - ip-address: 10.89.213.4
+ hostname: sw-main-1
+ hw-address: "a8:9c:6c:16:df:cc"
+ - ip-address: 10.89.213.5
+ hostname: sw-main-2
+ hw-address: "a8:9c:6c:16:e8:86"
+ - ip-address: 10.89.213.6
+ hostname: sw-shop-1
+ hw-address: "C0:4A:00:FB:DA:C5"
+ - ip-address: 10.89.213.7
+ hostname: sw-shop-2-peo
+ hw-address: "f4:e2:c6:bf:20:ee"
+ - ip-address: 10.89.213.8
+ hostname: sw-shop-3-peo
+ hw-address: "d8:b3:70:85:72:76"
+ - ip-address: 10.89.213.11
+ hostname: pve01
+ hw-address: "38:05:25:30:80:35"
+ - ip-address: 10.89.213.12
+ hostname: pve02
+ hw-address: "b8:85:84:b1:57:b6"
+ - ip-address: 10.89.213.13
+ hostname: pve03
+ hw-address: "98:fa:9b:a2:ed:e8"
+ - ip-address: 10.89.213.15
+ hostname: pbs
+ hw-address: "BC:24:11:D6:2C:81"
+ - ip-address: 10.89.213.21
+ hostname: unifi
+ hw-address: "BC:24:11:25:77:60"
+ - ip-address: 10.89.213.22
+ hostname: club-assistant
+ hw-address: "7a:55:61:c3:a2:89"
+ - ip-address: 10.89.213.23
+ hostname: automation
+ hw-address: "f2:20:75:5a:2f:8c"
+ - ip-address: 10.89.213.24
+ hostname: yate
+ hw-address: "bc:24:11:73:3e:f7"
+ - ip-address: 10.89.213.25
+ hostname: ptouch-print-server
+ hw-address: "bc:24:11:f2:cf:8f"
+ - ip-address: 10.89.213.26
+ hostname: mqtt
+ hw-address: "bc:24:11:48:85:73"
+ - ip-address: 10.89.213.27
+ hostname: factorio
+ hw-address: "bc:24:11:a3:43:7f"
+ - ip-address: 10.89.213.28
+ hostname: light
+ hw-address: "72:61:ea:e6:49:e3"
+ - ip-address: 10.89.213.29
+ hostname: homematic
+ hw-address: "fe:3a:42:77:3a:be"
+ - ip-address: 10.89.213.30
+ hostname: proxmox-backup-server
+ hw-address: "8a:48:dd:a3:22:40"
+ option-data:
+ - name: routers,
+ csv-format: true
+ data: 10.89.213.1
+
+kea_dhcp__dhcp6:
+ enable: true
+ interfaces: [ "netlan.51", "netlan.52", "netlan.54" ]
+ control-sockets:
+ - socket-name: /var/run/kea-dhcp6-ctrl-agent.sock
+ socket-type: unix
+ lease-database:
+ type: memfile
+ persist: true
+ option-data:
+ - name: "dns-servers"
+ code: 23
+ csv-format: true
+ data: "{{ kea_dhcp__dns_servers.v6 | join(',') }}"
+ subnets:
+ - id: 1
+ subnet: "2a07:c481:1:33::/64"
+ pools:
+ - pool: "2a07:c481:1:33::1:1 - 2a07:c481:1:33::FFFF:FFFF"
+ - id: 2
+ subnet: "2a07:c481:1:34::/64"
+ pools:
+ - pool: "2a07:c481:1:34::1:1 - 2a07:c481:1:34::FFFF:FFFF"
+ - id: 3
+ subnet: "2a07:c481:1:36::/64"
+ pools:
+ - pool: "2a07:c481:1:36::1:1 - 2a07:c481:1:36::FFFF:FFFF"
+ reservations:
+ - ip-address: "2a07:c481:1:36::2"
+ hostname: sw-rack-1
+ hw-address: "F0:9F:C2:10:C3:AA"
+ - ip-address: "2a07:c481:1:36::3"
+ hostname: sw-rack-2-peo
+ hw-address: "44:d9:e7:06:69:5d"
+ - ip-address: "2a07:c481:1:36::4"
+ hostname: sw-main-1
+ hw-address: "a8:9c:6c:16:df:cc"
+ - ip-address: "2a07:c481:1:36::5"
+ hostname: sw-main-2
+ hw-address: "a8:9c:6c:16:e8:86"
+ - ip-address: "2a07:c481:1:36::6"
+ hostname: sw-shop-1
+ hw-address: "C0:4A:00:FB:DA:C5"
+ - ip-address: "2a07:c481:1:36::7"
+ hostname: sw-shop-2-peo
+ hw-address: "f4:e2:c6:bf:20:ee"
+ - ip-address: "2a07:c481:1:36::8"
+ hostname: sw-shop-3-peo
+ hw-address: "d8:b3:70:85:72:76"
+ - ip-address: "2a07:c481:1:36::b"
+ hostname: pve01
+ hw-address: "38:05:25:30:80:35"
+ - ip-address: "2a07:c481:1:36::c"
+ hostname: pve02
+ hw-address: "b8:85:84:b1:57:b6"
+ - ip-address: "2a07:c481:1:36::d"
+ hostname: pve03
+ hw-address: "98:fa:9b:a2:ed:e8"
+ - ip-address: "2a07:c481:1:36::f"
+ hostname: pbs
+ hw-address: "BC:24:11:D6:2C:81"
+ - ip-address: "2a07:c481:1:36::14"
+ hostname: unifi
+ hw-address: "BC:24:11:25:77:60"
diff --git a/resources/z9/rt1/nftables/nftables.conf b/resources/z9/rt1/nftables/nftables.conf
index 21bfbd1..842ca04 100644
--- a/resources/z9/rt1/nftables/nftables.conf
+++ b/resources/z9/rt1/nftables/nftables.conf
@@ -76,6 +76,9 @@ table inet host {
# Allow DHCP server access.
iifname { $lan_ifs } udp dport 67 accept comment "allow dhcp server access"
+
+ # Allow DNS server access from lan_ifs
+ iifname { $lan_ifs, $if_wg55_management } udp dport 53 accept comment "allow dns server access from lan_ifs"
}
}
diff --git a/roles/kea_dhcp/defaults/main.yaml b/roles/kea_dhcp/defaults/main.yaml
new file mode 100644
index 0000000..409f0a1
--- /dev/null
+++ b/roles/kea_dhcp/defaults/main.yaml
@@ -0,0 +1,69 @@
+kea_dhcp__stork_agent:
+ enable: false
+ prometheus_only: true
+kea_dhcp__version_repo: "kea-3-0"
+kea_dhcp__dns_servers:
+ v6:
+ - "2a07:c481:0:4::2"
+ - "2a07:c481:0:4::3"
+ v4:
+ - "185.161.128.66"
+ - "185.161.128.67"
+kea_dhcp__include_vars:
+
+kea_dhcp__dhcp4:
+ enable: false
+ interfaces: [ ]
+ control-sockets:
+ - socket-name: /var/run/kea-dhcp4-ctrl-agent.sock
+ socket-type: unix
+ lease-database:
+ type: memfile
+ persist: true
+ option-data:
+ - name: "domain-name-servers"
+ code: 6
+ csv-format: true
+ data: "{{ kea_dhcp__dns_servers.v4 | join(',') }}"
+ subnets:
+ - id: 0
+ subnet: nil
+ pools:
+ - pool: nil
+ reservations:
+ - ip-address: nil
+ hostname: beispiel.test
+ hw-address: "00:11:22:33:44:55"
+ option-data:
+ - name: nil,
+ code: nil,
+ csv-format: true
+ data: nil
+kea_dhcp__dhcp6:
+ enable: false
+ interfaces: [ ]
+ lease-database:
+ type: memfile
+ persist: true
+ control-sockets:
+ - socket-name: /var/run/kea-dhcp6-ctrl-agent.sock
+ socket-type: unix
+ option-data:
+ - name: "dns-servers"
+ code: 23
+ csv-format: true
+ data: "{{ kea_dhcp__dns_servers.v6 | join(',') }}"
+ subnets:
+ - id: 0
+ subnet: nil
+ pools:
+ - pool: nil
+ reservations:
+ - ip-address: nil
+ hostname: beispiel.test
+ hw-address: "00:11:22:33:44:55"
+ option-data:
+ - name: nil,
+ code: nil,
+ csv-format: true
+ data: nil
diff --git a/roles/kea_dhcp/handlers/main.yml b/roles/kea_dhcp/handlers/main.yml
new file mode 100644
index 0000000..5b44d6e
--- /dev/null
+++ b/roles/kea_dhcp/handlers/main.yml
@@ -0,0 +1,30 @@
+---
+- name: Systemd.daemon_reload
+ become: true
+ ansible.builtin.systemd_service:
+ daemon_reload: true
+
+- name: Kea_dhcp4.reloaded
+ ansible.builtin.service:
+ name: kea-dhcp4
+ state: restarted
+ enabled: true
+
+- name: Kea_dhcp6.reloaded
+ ansible.builtin.service:
+ name: kea-dhcp6
+ state: restarted
+ enabled: true
+
+- name: Kea_ctrl.reloaded
+ ansible.builtin.systemd:
+ name: kea-ctrl-agent
+ state: restarted
+ enabled: true
+
+- name: Stork_agent.restarted
+ become: true
+ ansible.builtin.systemd:
+ name: isc-stork-agent
+ state: restarted
+ enabled: true
diff --git a/roles/kea_dhcp/meta/argument_specs.yaml b/roles/kea_dhcp/meta/argument_specs.yaml
new file mode 100644
index 0000000..995b838
--- /dev/null
+++ b/roles/kea_dhcp/meta/argument_specs.yaml
@@ -0,0 +1,125 @@
+---
+argument_specs:
+ main:
+ short_description: "Role for managing Kea DHCP server"
+ options:
+ kea_dhcp__stork_agent:
+ type: "dict"
+ description: "Configuration for Stork Agent"
+ options:
+ enable:
+ type: "bool"
+ default: false
+ prometheus_only:
+ type: "bool"
+ default: true
+ kea_dhcp__version_repo:
+ type: "str"
+ description: "Version of Kea DHCP repository to use"
+ default: "kea-3-0"
+ kea_dhcp__dns_servers:
+ type: "dict"
+ description: "Default DNS servers for DHCP clients"
+ options:
+ v6:
+ type: "list"
+ elements: "str"
+ v4:
+ type: "list"
+ elements: "str"
+ kea_dhcp__dhcp4:
+ type: "dict"
+ description: "Configuration for DHCPv4 service"
+ options:
+ enable:
+ type: "bool"
+ default: false
+ interfaces:
+ type: "list"
+ elements: "str"
+ default: []
+ control-sockets:
+ type: "list"
+ elements: "dict"
+ lease-database:
+ type: "dict"
+ option-data:
+ type: "list"
+ elements: "dict"
+ subnets:
+ type: "list"
+ elements: "dict"
+ options:
+ id:
+ type: "int"
+ subnet:
+ type: "str"
+ pools:
+ type: "list"
+ elements: "dict"
+ options:
+ pool:
+ type: "str"
+ reservations:
+ type: "list"
+ elements: "dict"
+ options:
+ ip-address:
+ type: "str"
+ hostname:
+ type: "str"
+ hw-address:
+ type: "str"
+ duid:
+ type: "str"
+ option-data:
+ type: "list"
+ elements: "dict"
+ kea_dhcp__dhcp6:
+ type: "dict"
+ description: "Configuration for DHCPv6 service"
+ options:
+ enable:
+ type: "bool"
+ default: false
+ interfaces:
+ type: "list"
+ elements: "str"
+ default: []
+ control-sockets:
+ type: "list"
+ elements: "dict"
+ lease-database:
+ type: "dict"
+ option-data:
+ type: "list"
+ elements: "dict"
+ subnets:
+ type: "list"
+ elements: "dict"
+ options:
+ id:
+ type: "int"
+ subnet:
+ type: "str"
+ pools:
+ type: "list"
+ elements: "dict"
+ options:
+ pool:
+ type: "str"
+ reservations:
+ type: "list"
+ elements: "dict"
+ options:
+ ip-address:
+ type: "str"
+ hostname:
+ type: "str"
+ hw-address:
+ type: "str"
+ duid:
+ type: "str"
+ option-data:
+ type: "list"
+ elements: "dict"
diff --git a/roles/kea_dhcp/tasks/install_archlinux.yml b/roles/kea_dhcp/tasks/install_archlinux.yml
new file mode 100644
index 0000000..7bdb140
--- /dev/null
+++ b/roles/kea_dhcp/tasks/install_archlinux.yml
@@ -0,0 +1,8 @@
+---
+- name: Install Kea on Archlinux
+ when: ansible_facts['distribution'] == "Archlinux"
+ become: true
+ community.general.pacman:
+ name: kea
+ state: present
+ update_cache: false
diff --git a/roles/kea_dhcp/tasks/install_debian.yml b/roles/kea_dhcp/tasks/install_debian.yml
new file mode 100644
index 0000000..2ac2346
--- /dev/null
+++ b/roles/kea_dhcp/tasks/install_debian.yml
@@ -0,0 +1,22 @@
+---
+- name: Register isc-kea apt repository
+ become: true
+ register: kea_dhcp_repo
+ when: ansible_facts['distribution'] == "Debian"
+ ansible.builtin.deb822_repository:
+ name: "isc-{{ kea_dhcp__version_repo }}"
+ uris: "https://dl.cloudsmith.io/public/isc/{{ kea_dhcp__version_repo }}/deb/debian"
+ suites: any-version
+ components: main
+ signed_by: "https://dl.cloudsmith.io/public/isc/{{ kea_dhcp__version_repo }}/gpg.key"
+
+- name: Install Kea packages
+ become: true
+ when: ansible_facts['distribution'] == "Debian"
+ ansible.builtin.apt:
+ name:
+ - isc-kea-dhcp4
+ - isc-kea-dhcp6
+ - isc-kea-ctrl-agent
+ - isc-kea-admin
+ update_cache: "{{ kea_dhcp_install_repo.changed }}"
diff --git a/roles/kea_dhcp/tasks/kea.yaml b/roles/kea_dhcp/tasks/kea.yaml
new file mode 100644
index 0000000..a4fd3b5
--- /dev/null
+++ b/roles/kea_dhcp/tasks/kea.yaml
@@ -0,0 +1,51 @@
+---
+- name: Include config vars
+ tags: [ kea, include_vars ]
+ when: kea_dhcp__include_vars is not None
+ ansible.builtin.include_vars:
+ file: "{{ kea_dhcp__include_vars }}"
+
+- name: Deploy kea-dhcp4 configuration file
+ tags: [ kea, dhcp4 ]
+ become: true
+ when: kea_dhcp__dhcp4.enable
+ ansible.builtin.template:
+ src: kea-dhcp4.conf.jinja
+ dest: /etc/kea/kea-dhcp4.conf
+ backup: true
+ owner: root
+ group: kea
+ mode: "u=rw,g=r,o="
+ validate: kea-dhcp4 -T %s
+ notify:
+ - Kea_dhcp4.reloaded
+
+- name: Deploy kea-dhcp6 configuration file
+ tags: [ kea, dhcp6 ]
+ become: true
+ when: kea_dhcp__dhcp6.enable
+ ansible.builtin.template:
+ src: kea-dhcp6.conf.jinja
+ dest: /etc/kea/kea-dhcp6.conf
+ backup: true
+ owner: root
+ group: kea
+ mode: "u=rw,g=r,o="
+ validate: kea-dhcp6 -T %s
+ notify:
+ - Kea_dhcp6.reloaded
+
+- name: Copy kea-ctrl-agent configuration file
+ tags: [ kea, ctrl-agent ]
+ become: true
+ when: kea_dhcp__stork_agent.enable
+ ansible.builtin.template:
+ src: kea-ctrl-agent.conf.j2
+ dest: /etc/kea/kea-ctrl-agent.conf
+ owner: root
+ group: kea
+ mode: "u=rw,g=r,o="
+ validate: kea-ctrl-agent -t %s
+ notify:
+ - Kea_ctrl.reloaded
+ - Stork_agent.restarted
diff --git a/roles/kea_dhcp/tasks/main.yml b/roles/kea_dhcp/tasks/main.yml
new file mode 100644
index 0000000..a3478fa
--- /dev/null
+++ b/roles/kea_dhcp/tasks/main.yml
@@ -0,0 +1,19 @@
+---
+- name: Setup Kea DHCP
+ tags: [kea, dhcp]
+ block:
+ - name: Install Kea on Archlinux
+ when: ansible_facts['distribution'] == "Archlinux"
+ ansible.builtin.import_tasks: install_archlinux.yml
+
+ - name: Install Kea on Debian
+ when: ansible_facts['distribution'] == "Debian"
+ ansible.builtin.import_tasks: install_debian.yml
+
+ - name: Configure Kea
+ ansible.builtin.include_tasks: kea.yaml
+
+- name: Run stork-agent tasks
+ tags: [stork-agent, monitoring]
+ when: kea_dhcp__stork_agent.enable
+ ansible.builtin.include_tasks: stork-agent.yaml
diff --git a/roles/kea_dhcp/tasks/stork-agent.yaml b/roles/kea_dhcp/tasks/stork-agent.yaml
new file mode 100644
index 0000000..916760c
--- /dev/null
+++ b/roles/kea_dhcp/tasks/stork-agent.yaml
@@ -0,0 +1,76 @@
+---
+- name: Install stork-agent
+ tags: [stork-agent]
+ block:
+ - name: Install stork-agent on Archlinux
+ when: ansible_facts['distribution'] == "Archlinux"
+ tags: [stork-agent, archlinux]
+ block:
+ - name: Create stork-agent user
+ ansible.builtin.user:
+ name: stork-agent
+ create_home: false
+ home: "/var/lib/stork-agent"
+ shell: "/usr/bin/nologin"
+ system: true
+ groups: ["kea"]
+ append: true
+
+ - name: Install stork-agent with aur_pkg_install
+ ansible.builtin.include_role:
+ name: aur_pkg_install
+ vars:
+ aur_pkg_install__pkg_name: "stork-agent"
+ aur_pkg_install__git_clone_url: "https://ansible:{{ secret__ansible_git_token }}@git.fux-eg.net/aur-mirror/stork-agent.git"
+ aur_pkg_install__git_ref: "bf96e34"
+
+ - name: Install stork-agent on Debian
+ when: ansible_facts['distribution'] == "Debian"
+ tags: [stork-agent, debian]
+ block:
+ - name: Register isc-stork apt repository
+ become: true
+ register: "kea_dhcp_install_repo"
+ ansible.builtin.deb822_repository:
+ name: isc-stork
+ uris: https://dl.cloudsmith.io/public/isc/stork/deb/debian
+ suites: any-version
+ components: main
+ signed_by: https://dl.cloudsmith.io/public/isc/stork/gpg.key
+
+ - name: Install isc-stork-agent
+ become: true
+ ansible.builtin.apt:
+ name: isc-stork-agent
+ update_cache: "{{ kea_dhcp_install_repo.changed }}"
+
+ - name: Add stork-agent user to _kea group on Debian
+ when: ansible_facts['distribution'] == "Debian"
+ become: true
+ ansible.builtin.user:
+ name: stork-agent
+ groups: ["_kea"]
+ append: true
+
+ - name: Config for stork-agent
+ ansible.builtin.template:
+ src: stork-agent.env.jinja
+ dest: /etc/stork/agent.env
+ owner: root
+ group: root
+ mode: "0660"
+ notify:
+ - Systemd_daemon_reload
+ - Stork_agent.restarted
+
+ - name: Flush handlers
+ ansible.builtin.meta: flush_handlers
+
+ - name: Ensure that stork kea exporter is working
+ ansible.builtin.uri:
+ url: "http://localhost:9547/metrics"
+ method: GET
+ register: kea_dhcp_stork_status_code
+ retries: 6
+ delay: 5
+ until: kea_dhcp_stork_status_code.status == 200
diff --git a/roles/kea_dhcp/templates/kea-ctrl-agent.conf.j2 b/roles/kea_dhcp/templates/kea-ctrl-agent.conf.j2
new file mode 100644
index 0000000..5ac1473
--- /dev/null
+++ b/roles/kea_dhcp/templates/kea-ctrl-agent.conf.j2
@@ -0,0 +1,20 @@
+{
+"Control-agent": {
+ "http-host": "127.0.0.1",
+ "http-port": 8000,
+ "control-sockets": {
+ {% if kea_dhcp__dhcp4.enable | default(false) %}
+ "dhcp4": {
+ "socket-type": "{{ kea_dhcp__dhcp4['control-sockets'][0]['socket-type'] }}",
+ "socket-name": "{{ kea_dhcp__dhcp4['control-sockets'][0]['socket-name'] }}"
+ }{% if kea_dhcp__dhcp6.enable %},{% endif %}
+ {% endif %}
+ {% if kea_dhcp__dhcp6.enable | default(false) %}
+ "dhcp6": {
+ "socket-type": "{{ kea_dhcp__dhcp6['control-sockets'][0]['socket-type'] }}",
+ "socket-name": "{{ kea_dhcp__dhcp6['control-sockets'][0]['socket-name'] }}"
+ },
+ {% endif %}
+ }
+}
+}
diff --git a/roles/kea_dhcp/templates/kea-dhcp4.conf.jinja b/roles/kea_dhcp/templates/kea-dhcp4.conf.jinja
new file mode 100644
index 0000000..78f06ae
--- /dev/null
+++ b/roles/kea_dhcp/templates/kea-dhcp4.conf.jinja
@@ -0,0 +1,27 @@
+{
+ "Dhcp4": {
+ "interfaces-config": {
+ "interfaces": {{ kea_dhcp__dhcp4.interfaces | to_nice_json }}
+ },
+ "control-sockets": {{ kea_dhcp__dhcp4['control-sockets'] | to_nice_json }},
+ "lease-database": {{ kea_dhcp__dhcp4['lease-database'] | to_nice_json }},
+ {% if kea_dhcp__dhcp4['option-data'] is defined and kea_dhcp__dhcp4['option-data'] %}
+ "option-data": {{ kea_dhcp__dhcp4['option-data'] | to_nice_json }},
+ {% endif %}
+ "subnet4": [
+ {% for subnet in kea_dhcp__dhcp4.subnets %}
+ {
+ "id": {{ subnet.id }},
+ "subnet": "{{ subnet.subnet }}",
+ "pools": {{ subnet.pools | to_nice_json }},
+ {% if subnet.reservations is defined and subnet.reservations %}
+ "reservations": {{ subnet.reservations | to_nice_json }},
+ {% endif %}
+ {% if subnet['option-data'] is defined and subnet['option-data'] %}
+ "option-data": {{ subnet['option-data'] | to_nice_json }}
+ {% endif %}
+ }{% if not loop.last %},{% endif %}
+ {% endfor %}
+ ]
+ }
+}
diff --git a/roles/kea_dhcp/templates/kea-dhcp6.conf.jinja b/roles/kea_dhcp/templates/kea-dhcp6.conf.jinja
new file mode 100644
index 0000000..da1929a
--- /dev/null
+++ b/roles/kea_dhcp/templates/kea-dhcp6.conf.jinja
@@ -0,0 +1,27 @@
+{
+ "Dhcp6": {
+ "interfaces-config": {
+ "interfaces": {{ kea_dhcp__dhcp6.interfaces | to_nice_json }}
+ },
+ "control-sockets": {{ kea_dhcp__dhcp6['control-sockets'] | to_nice_json }},
+ "lease-database": {{ kea_dhcp__dhcp6['lease-database'] | to_nice_json }},
+ {% if kea_dhcp__dhcp6['option-data'] is defined and kea_dhcp__dhcp6['option-data'] %}
+ "option-data": {{ kea_dhcp__dhcp6['option-data'] | to_nice_json }},
+ {% endif %}
+ "subnet6": [
+ {% for subnet in kea_dhcp__dhcp6.subnets %}
+ {
+ "id": {{ subnet.id }},
+ "subnet": "{{ subnet.subnet }}",
+ "pools": {{ subnet.pools | to_nice_json }},
+ {% if subnet.reservations is defined and subnet.reservations %}
+ "reservations": {{ subnet.reservations | to_nice_json }},
+ {% endif %}
+ {% if subnet['option-data'] is defined and subnet['option-data'] %}
+ "option-data": {{ subnet['option-data'] | to_nice_json }}
+ {% endif %}
+ }{% if not loop.last %},{% endif %}
+ {% endfor %}
+ ]
+ }
+}
diff --git a/roles/kea_dhcp/templates/stork-agent.env.jinja b/roles/kea_dhcp/templates/stork-agent.env.jinja
new file mode 100644
index 0000000..bdfa4d2
--- /dev/null
+++ b/roles/kea_dhcp/templates/stork-agent.env.jinja
@@ -0,0 +1,44 @@
+### the IP or hostname to listen on for incoming Stork server connections
+# STORK_AGENT_HOST=
+
+### the TCP port to listen on for incoming Stork server connections
+# STORK_AGENT_PORT=8081
+
+### listen for commands from the Stork server only, but not for Prometheus requests
+# STORK_AGENT_LISTEN_STORK_ONLY=true
+
+{% if kea_dhcp__stork_agent.prometheus_only %}
+### listen for Prometheus requests only, but not for commands from the Stork server
+STORK_AGENT_LISTEN_PROMETHEUS_ONLY=true
+{% endif %}
+
+### settings for exporting stats to Prometheus
+### the IP or hostname on which the agent exports Kea statistics to Prometheus
+# STORK_AGENT_PROMETHEUS_KEA_EXPORTER_ADDRESS=
+### the port on which the agent exports Kea statistics to Prometheus
+# STORK_AGENT_PROMETHEUS_KEA_EXPORTER_PORT=
+## enable or disable collecting per-subnet stats from Kea
+# STORK_AGENT_PROMETHEUS_KEA_EXPORTER_PER_SUBNET_STATS=true
+### the IP or hostname on which the agent exports BIND 9 statistics to Prometheus
+# STORK_AGENT_PROMETHEUS_BIND9_EXPORTER_ADDRESS=
+### the port on which the agent exports BIND 9 statistics to Prometheus
+# STORK_AGENT_PROMETHEUS_BIND9_EXPORTER_PORT=
+
+### Stork Server URL used by the agent to send REST commands to the server during agent registration
+# STORK_AGENT_SERVER_URL=
+
+### skip TLS certificate verification when the Stork Agent connects
+### to Kea over TLS and Kea uses self-signed certificates
+# STORK_AGENT_SKIP_TLS_CERT_VERIFICATION=true
+
+
+### Logging parameters
+
+### Set logging level. Supported values are: DEBUG, INFO, WARN, ERROR
+STORK_LOG_LEVEL=DEBUG
+### disable output colorization
+# CLICOLOR=false
+
+### path to the hook directory
+# STORK_AGENT_HOOK_DIRECTORY=
+
diff --git a/roles/unbound/README.md b/roles/unbound/README.md
new file mode 100644
index 0000000..806b9d8
--- /dev/null
+++ b/roles/unbound/README.md
@@ -0,0 +1,19 @@
+# Unbound DNS resolver
+
+Role fora a validating, recursive, caching DNS resolver based on [Unbound](https://nlnetlabs.nl/projects/unbound/about/).
+It is designed to be fast and lean and incorporates modern features based on open standards.
+
+- [Documentation](https://unbound.docs.nlnetlabs.nl/en/latest/)
+
+## Role Customization
+
+The following variables can be used to customize this role:
+
+| Variable | Type | Default | Description |
+|------------------------------------------|-----------------|-----------------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
+| unbound_install_prometheus_exporter | Boolean | `true` | Whether [Unbound Exporter](https://github.com/letsencrypt/unbound_exporter) should also be installed to expose resolver statistics in prometheus format. |
+| unbound_bind_interfaces | List of Strings | `[0.0.0.0, ::]` | List of interface names or IP addresses on which unbound will listen for dns queries |
+| unbound_enable_unbound_control | Boolean | `true` | Whether the [remote control](https://unbound.docs.nlnetlabs.nl/en/latest/getting-started/configuration.html#set-up-remote-control) feature of unbound should be configured. |
+| unbound_enable_dnssec | Boolean | `true` | Whether dnssec validation should be enabled |
+| unbound_access_control | List of Strings | `[]` | **Required** List of [unbound access control values](https://unbound.docs.nlnetlabs.nl/en/latest/manpages/unbound.conf.html#:~:text=access-control:%20%3CIP%20netblock%3E%20%3Caction%3E) |
+| unbound_disable_systemd_networkd | Boolean | `true` | If true, systemd-networkd is disabled and the local system is pointed towards the configured dns resolver. |
diff --git a/roles/unbound/defaults/main.yml b/roles/unbound/defaults/main.yml
new file mode 100644
index 0000000..fa6cb24
--- /dev/null
+++ b/roles/unbound/defaults/main.yml
@@ -0,0 +1,7 @@
+unbound_install_prometheus_exporter: true
+unbound_bind_interfaces: [ "0.0.0.0", "::" ]
+unbound_disable_systemd_networkd: true
+unbound_enable_unbound_control: true
+unbound_enable_dnssec: true
+unbound_access_control: [ ]
+unbound_private_domain: [ ]
diff --git a/roles/unbound/files/no-resolved.resolv.conf b/roles/unbound/files/no-resolved.resolv.conf
new file mode 100644
index 0000000..bbc8559
--- /dev/null
+++ b/roles/unbound/files/no-resolved.resolv.conf
@@ -0,0 +1 @@
+nameserver 127.0.0.1
diff --git a/roles/unbound/handlers/main.yml b/roles/unbound/handlers/main.yml
new file mode 100644
index 0000000..e1345bf
--- /dev/null
+++ b/roles/unbound/handlers/main.yml
@@ -0,0 +1,27 @@
+- name: unbound.restarted
+ tags: [ unbound, dns, dns_resolver ]
+ become: true
+ ansible.builtin.systemd:
+ name: unbound.service
+ state: restarted
+
+- name: unbound.reloaded
+ tags: [ unbound, dns, dns_resolver ]
+ become: true
+ ansible.builtin.systemd:
+ name: unbound.service
+ state: reloaded
+
+- name: prometheus-unbound-exporter.restarted
+ become: true
+ ansible.builtin.systemd:
+ name: prometheus-unbound-exporter.service
+ state: restarted
+ enabled: true
+
+- name: prometheus-unbound-exporter.enabled
+ become: true
+ ansible.builtin.systemd:
+ name: prometheus-unbound-exporter.service
+ enabled: true
+ daemon_reload: true
diff --git a/roles/unbound/tasks/main.yml b/roles/unbound/tasks/main.yml
new file mode 100644
index 0000000..7ed42cb
--- /dev/null
+++ b/roles/unbound/tasks/main.yml
@@ -0,0 +1,63 @@
+- name: unbound role main
+ tags: [ unbound, dns, dns_resolver ]
+ block:
+
+ - name: install unbound dns resolver
+ become: true
+ ansible.builtin.package:
+ name: unbound
+
+ - name: install extra dns tooling
+ become: true
+ ansible.builtin.package:
+ name: [ bind ] # the bind package includes tools like dig in archlinux
+
+ - name: ensure correct directory permissions
+ become: true
+ ansible.builtin.file:
+ path: /etc/unbound
+ state: directory
+ mode: u=rwX,g=rX,o=rX
+ recurse: true
+ owner: unbound
+ group: unbound
+
+ - name: configure unbound dns resolver
+ become: true
+ notify: unbound.restarted
+ ansible.builtin.template:
+ src: unbound.conf.j2
+ dest: /etc/unbound/unbound.conf
+ owner: unbound
+ group: unbound
+ mode: u=rw,g=r,o=r
+
+ - name: ensure unbound is running and enabled
+ become: true
+ ansible.builtin.systemd:
+ name: unbound.service
+ state: started
+ enabled: true
+
+ - name: disable systemd-resolved
+ become: true
+ when: unbound_disable_systemd_networkd
+ ansible.builtin.systemd:
+ name: systemd-resolved.service
+ state: stopped
+ enabled: false
+
+ - name: configure system resolver to point to local unbound
+ become: true
+ when: unbound_disable_systemd_networkd
+ ansible.builtin.copy:
+ src: no-resolved.resolv.conf
+ dest: /etc/resolv.conf
+ owner: unbound
+ group: unbound
+ mode: u=rw,g=r,o=r
+
+
+ - name: install and configure prometheus-exporter for unbound
+ ansible.builtin.import_tasks: prometheus-exporter.yml
+ when: unbound_install_prometheus_exporter
diff --git a/roles/unbound/tasks/prometheus-exporter.yml b/roles/unbound/tasks/prometheus-exporter.yml
new file mode 100644
index 0000000..d05b838
--- /dev/null
+++ b/roles/unbound/tasks/prometheus-exporter.yml
@@ -0,0 +1,17 @@
+---
+- name: install unbound prometheus exporter
+ become: true
+ ansible.builtin.package:
+ name: prometheus-unbound-exporter
+ notify: prometheus-unbound-exporter.enabled
+
+- name: configure unbound exporter
+ become: true
+ ansible.builtin.copy:
+ dest: /etc/conf.d/prometheus-unbound-exporter
+ content: |
+ UNBOUND_EXPORTER_ARGS="-unbound.ca "" -unbound.cert "" -unbound.host "unix:///run/unbound-control.sock"
+ owner: root
+ group: root
+ mode: '0660'
+ notify: prometheus-unbound-exporter.restarted
diff --git a/roles/unbound/templates/unbound.conf.j2 b/roles/unbound/templates/unbound.conf.j2
new file mode 100644
index 0000000..a1e310e
--- /dev/null
+++ b/roles/unbound/templates/unbound.conf.j2
@@ -0,0 +1,73 @@
+# ref: https://unbound.docs.nlnetlabs.nl/en/latest/manpages/unbound.conf.html
+# unbound.conf(5) man page
+server:
+ {% if unbound_enable_dnssec -%}
+ # disable chroot because unbound is the only thing running on the VM
+ # and because it has issues with how archlinux configures the systemd units write protection regarding the anchor file
+ chroot: ""
+
+ # location of the trust anchor file that enables DNSSEC
+ # this file is generated by the `unbound-anchor` command
+ auto-trust-anchor-file: "/etc/unbound/trusted-key.key"
+ {% endif -%}
+
+ # use all CPUs
+ num-threads: 2
+
+ # more cache memory
+ rrset-cache-size: 60m
+ msg-cache-size: 30m
+
+ # prefetch to keep the cache up to date
+ prefetch: yes
+
+ # fetch the DNSKEYs earlier in the validation process, when a DS record is encountered
+ prefetch-key: yes
+
+ # Faster UDP with multithreading (only on Linux).
+ so-reuseport: yes
+
+ # disable special large send buffer handling and just use kernel defaults
+ so-sndbuf: 0
+
+ # send minimal amount of information to upstream servers to enhance privacy
+ qname-minimisation: yes
+
+ # specify the interface to answer queries from by ip-address.
+ {% for i in unbound_bind_interfaces -%}
+ interface: "{{ i }}"
+ {% endfor %}
+
+ # addresses from the IP range that are allowed to connect to the resolver
+ {% for i in unbound_access_control -%}
+ access-control: {{ i }}
+ {% endfor -%}
+
+ {% for i in unbound_private_domain -%}
+ private-domain: {{ i }}
+ {% endfor -%}
+
+ # The number of seconds between printing statistics to the log for every thread.
+ statistics-interval: 0
+
+ # Extended statistics are printed, Keeping track of more statistics takes time.
+ extended-statistics: yes
+
+remote-control:
+ control-enable: {{ "yes" if unbound_enable_unbound_control else "no" }}
+ control-interface: /run/unbound-control.sock
+
+
+# configure some zones for which this resolver will act authoritatively
+# https://www.dns.icann.org/services/axfr/
+{% for i in [ ".", "in-addr.arpa.", "arpa.", "root-servers.net.", "ip6.arpa.", "ip6-servers.arpa.", "mcast.net." ] %}
+auth-zone:
+ name: "{{ i }}"
+ primary: "lax.xfr.dns.icann.org"
+ primary: "iad.xfr.dns.icann.org"
+ fallback-enabled: yes
+ for-downstream: no
+ for-upstream: yes
+
+
+{% endfor %}
From 3a091f7aa55d5ce1a1e4989ef82a7a986c75bd4b Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Mon, 25 May 2026 18:31:05 +0200
Subject: [PATCH 04/14] z9-router(host): rename rt1 to z9-router
---
.../{rt1.sops.yaml => z9-router.sops.yaml} | 8 ++++----
.../z9/host_vars/{rt1.yaml => z9-router.yaml} | 8 ++++----
inventories/z9/hosts.yaml | 18 +++++++++---------
resources/z9/{rt1 => z9-router}/kea_dhcp.yaml | 0
.../{rt1 => z9-router}/nftables/nftables.conf | 0
.../systemd_networkd/00-netlan.link | 0
.../systemd_networkd/00-netwan.link | 0
.../systemd_networkd/10-netlan.51.netdev | 0
.../systemd_networkd/10-netlan.52.netdev | 0
.../systemd_networkd/10-netlan.53.netdev | 0
.../systemd_networkd/10-netlan.54.netdev | 0
.../systemd_networkd/10-netwan.400.netdev | 0
.../systemd_networkd/10-wg55.netdev | 0
.../systemd_networkd/20-netlan.network | 0
.../systemd_networkd/20-netwan.network | 0
.../systemd_networkd/20-wg55.network | 0
.../21-netlan.51-clients.network | 0
.../systemd_networkd/21-netlan.52-iot.network | 0
.../21-netlan.53-public.network | 0
.../21-netlan.54-management.network | 0
.../21-netwan.400-fux_uplink.network | 0
.../systemd_networkd_global_config.conf | 0
22 files changed, 17 insertions(+), 17 deletions(-)
rename inventories/z9/host_vars/{rt1.sops.yaml => z9-router.sops.yaml} (94%)
rename inventories/z9/host_vars/{rt1.yaml => z9-router.yaml} (53%)
rename resources/z9/{rt1 => z9-router}/kea_dhcp.yaml (100%)
rename resources/z9/{rt1 => z9-router}/nftables/nftables.conf (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/00-netlan.link (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/00-netwan.link (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/10-netlan.51.netdev (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/10-netlan.52.netdev (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/10-netlan.53.netdev (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/10-netlan.54.netdev (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/10-netwan.400.netdev (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/10-wg55.netdev (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/20-netlan.network (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/20-netwan.network (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/20-wg55.network (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/21-netlan.51-clients.network (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/21-netlan.52-iot.network (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/21-netlan.53-public.network (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/21-netlan.54-management.network (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd/21-netwan.400-fux_uplink.network (100%)
rename resources/z9/{rt1 => z9-router}/systemd_networkd_global_config.conf (100%)
diff --git a/inventories/z9/host_vars/rt1.sops.yaml b/inventories/z9/host_vars/z9-router.sops.yaml
similarity index 94%
rename from inventories/z9/host_vars/rt1.sops.yaml
rename to inventories/z9/host_vars/z9-router.sops.yaml
index f4141fd..89f18e1 100644
--- a/inventories/z9/host_vars/rt1.sops.yaml
+++ b/inventories/z9/host_vars/z9-router.sops.yaml
@@ -1,8 +1,8 @@
secrets__secrets:
- - name: ENC[AES256_GCM,data:MmqDXUKy+U67JZFmKJTGLYAJcYPClQ8M2w==,iv:/eDx++bJCzdKXYB8YipB/GB6aM421JR3sy8i5trBKxk=,tag:/zTklys9bN839iT1qOH0UQ==,type:str]
+ - name: ENC[AES256_GCM,data:gt9BarzsfE/GJ5gQeelgePquW6KAgE3Exv4=,iv:IPpUQI+zkf8O+ej+ZxLFyWUOrxGGlZvmDRG0ut2cNsA=,tag:GP66MvcKyCqyKV814+uMYg==,type:str]
content: ENC[AES256_GCM,data:2ljp324rAsF2zk2631TI7bV1xKxdFr4u4NxrsPYnjWsL0PX0n0KhJ1qvJCs=,iv:0+DxsTTiNLOg5iH83bFT/d+0uW2rn6bATSm3xc5PEdE=,tag:XbBDrrjriXPedyT4+sBBwA==,type:str]
- name: ENC[AES256_GCM,data:9i4hZU7Hv/IMlI/1oYthx8g57nrst9LHZQk=,iv:IQanD/CA64A+hVyTQBiTvWdXyY8qNF9BpehWZxI5a9c=,tag:RiY0OJe2xbFPG6wfe5XjiA==,type:str]
- content: ENC[AES256_GCM,data:lrwHaNvHkh5E94ziiQsd8ua9YvuwmhZ6iIGZS0oFnZdYKuyNh7egWOoii2o=,iv:LLRKhbiJl1GwK/SfqNdNrrJuDF17YXw3hHmuhlyI87w=,tag:DbR/a7jfy1+4yswSdYfOFA==,type:str]
+ content: ENC[AES256_GCM,data:68GUwG1Q2s2jH92HS0FQWrcMHJP8fHjrOqr21gsdswxKekQrpxX5B3BBFfM=,iv:HOsNUAKE5rOmKgZft2JK1NnZUuhk261d9WYWJS22nLM=,tag:3husFvB57AGVFzF7hKzLpw==,type:str]
- name: ENC[AES256_GCM,data:2lJUcDJ7ECJ1bF4Fg1VwOR2tBIQ77ZvDAbFF8w==,iv:HrPWIetjN/lOyQ7Mvk0sM1w+bWldlNfWhvw7/sfqKN8=,tag:AJL0s+f0O/yR4G3RVd1IHQ==,type:str]
content: ENC[AES256_GCM,data:68GUwG1Q2s2jH92HS0FQWrcMHJP8fHjrOqr21gsdswxKekQrpxX5B3BBFfM=,iv:HOsNUAKE5rOmKgZft2JK1NnZUuhk261d9WYWJS22nLM=,tag:3husFvB57AGVFzF7hKzLpw==,type:str]
- name: ENC[AES256_GCM,data:ESxpEp9k9BdD1GJv+af+U3ny0+RPuaJjWDhQ,iv:DxsZLiDF8F+ixepbUdlitMJ7DLHjGNFNuxRwLl7efo8=,tag:STnv/oLzbchdiwXfKP3fow==,type:str]
@@ -18,8 +18,8 @@ secrets__secrets:
- name: ENC[AES256_GCM,data:ERsggezMBbs1YwbIgwzKSAEHWWOWYxap8IDdn2YtEKvZexqu,iv:XbObLp2QERgt57tc/Cpha1CWXi+GttcIU8hJFGSp8e8=,tag:FqCuSbvLRERpVnQTzQsfpQ==,type:str]
content: ENC[AES256_GCM,data:QPoZA71CwE8EFE0I+6z0z0O1bUCMQDDDG7wGNoxXKt3ovLkFt21r8WG7VhA=,iv:InX6A71f3DGTg1wO4G0ECf488+FnKgTHffVwvJ9hHQ0=,tag:EVxwJlneN1CbMLXto7uLFw==,type:str]
sops:
- lastmodified: "2026-05-23T21:19:38Z"
- mac: ENC[AES256_GCM,data:Ded0VfGn8H2qGMk5LDyqF1gW8hajKc9FgvCynHPQkWkhMSdaHYbFwf//gWi2TjIO22HD5sPw1w9KAjPy53b57RwBCjXfMMq0JCPvuePLK40NC8uCAi+wr5Er0fAWz1JiaA+dowposoi6RxBtyHCaNHMDVGMLh1j+IL+pTOyi6fk=,iv:gssOMmR0DDQC4WjMVXTD/zqbQa8qlBr9ZZWF15W0WnE=,tag:DORTxQfCmpVjDjyGSNH7dw==,type:str]
+ lastmodified: "2026-05-25T16:29:22Z"
+ mac: ENC[AES256_GCM,data:zxtV1xgjQuKNMvh6S8oAOxX5J6+iBRO6k3vGw3vWNlhah4Gu3S/lt+5v8lQHogz1Vyc+Zff0yMj1cn6RstDDj5AuOCljRQN0FYs0fjCo4Yrxx5sMMwcwBYquC77skEiZhRnqdXKkjiOM7EGE8qj8O3DJ29borIjm5NAsflH/qkA=,iv:7EUElg+gu8mk2Gq32JQMTf+A1+ZhZufoqt5bk4+Ca1E=,tag:XG+F/zlXizsc2B8THoXj4g==,type:str]
pgp:
- created_at: "2026-05-23T20:58:22Z"
enc: |-
diff --git a/inventories/z9/host_vars/rt1.yaml b/inventories/z9/host_vars/z9-router.yaml
similarity index 53%
rename from inventories/z9/host_vars/rt1.yaml
rename to inventories/z9/host_vars/z9-router.yaml
index 876776a..c9d2b6f 100644
--- a/inventories/z9/host_vars/rt1.yaml
+++ b/inventories/z9/host_vars/z9-router.yaml
@@ -1,7 +1,7 @@
-systemd_networkd__config_dir: 'resources/z9/rt1/systemd_networkd/'
-systemd_networkd__global_config: "{{ lookup('ansible.builtin.file', 'resources/z9/rt1/systemd_networkd_global_config.conf') }}"
-nftables__config: "{{ lookup('ansible.builtin.file', 'resources/z9/rt1/nftables/nftables.conf') }}"
+systemd_networkd__config_dir: 'resources/z9/z9-router/systemd_networkd/'
+systemd_networkd__global_config: "{{ lookup('ansible.builtin.file', 'resources/z9/z9-router/systemd_networkd_global_config.conf') }}"
+nftables__config: "{{ lookup('ansible.builtin.file', 'resources/z9/z9-router/nftables/nftables.conf') }}"
ansible_pull__timer_on_calendar: "*-*-* 04:00:00 Europe/Berlin"
ansible_pull__timer_randomized_delay_sec: 0min
unbound_access_control: [ "10.89.208.0/20" ]
-kea_dhcp__include_vars: resources/z9/rt1/kea_dhcp.yaml
+kea_dhcp__include_vars: resources/z9/z9-router/kea_dhcp.yaml
diff --git a/inventories/z9/hosts.yaml b/inventories/z9/hosts.yaml
index 407aa2f..90f2efd 100644
--- a/inventories/z9/hosts.yaml
+++ b/inventories/z9/hosts.yaml
@@ -14,8 +14,8 @@ all:
yate:
ansible_host: yate.ccchh.net
ansible_user: chaos
- rt1:
- ansible_host: rt1.ccchh.net
+ z9-router:
+ ansible_host: z9-router.ccchh.net
ansible_user: chaos
certbot_hosts:
hosts:
@@ -38,7 +38,7 @@ infrastructure_authorized_keys_hosts:
light:
waybackproxy:
yate:
- rt1:
+ z9-router:
nginx_hosts:
hosts:
dooris:
@@ -52,22 +52,22 @@ proxmox_vm_template_hosts:
thinkcccore0:
systemd_networkd_hosts:
hosts:
- rt1:
+ z9-router:
nftables_hosts:
hosts:
- rt1:
+ z9-router:
unbound_hosts:
hosts:
- rt1:
+ z9-router:
kea_dhcp_hosts:
hosts:
- rt1:
+ z9-router:
alloy_hosts:
hosts:
light:
yate:
dooris:
- rt1:
+ z9-router:
ansible_pull_hosts:
hosts:
dooris:
@@ -76,4 +76,4 @@ ansible_pull_hosts:
yate:
secrets_hosts:
hosts:
- rt1:
+ z9-router:
diff --git a/resources/z9/rt1/kea_dhcp.yaml b/resources/z9/z9-router/kea_dhcp.yaml
similarity index 100%
rename from resources/z9/rt1/kea_dhcp.yaml
rename to resources/z9/z9-router/kea_dhcp.yaml
diff --git a/resources/z9/rt1/nftables/nftables.conf b/resources/z9/z9-router/nftables/nftables.conf
similarity index 100%
rename from resources/z9/rt1/nftables/nftables.conf
rename to resources/z9/z9-router/nftables/nftables.conf
diff --git a/resources/z9/rt1/systemd_networkd/00-netlan.link b/resources/z9/z9-router/systemd_networkd/00-netlan.link
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/00-netlan.link
rename to resources/z9/z9-router/systemd_networkd/00-netlan.link
diff --git a/resources/z9/rt1/systemd_networkd/00-netwan.link b/resources/z9/z9-router/systemd_networkd/00-netwan.link
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/00-netwan.link
rename to resources/z9/z9-router/systemd_networkd/00-netwan.link
diff --git a/resources/z9/rt1/systemd_networkd/10-netlan.51.netdev b/resources/z9/z9-router/systemd_networkd/10-netlan.51.netdev
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/10-netlan.51.netdev
rename to resources/z9/z9-router/systemd_networkd/10-netlan.51.netdev
diff --git a/resources/z9/rt1/systemd_networkd/10-netlan.52.netdev b/resources/z9/z9-router/systemd_networkd/10-netlan.52.netdev
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/10-netlan.52.netdev
rename to resources/z9/z9-router/systemd_networkd/10-netlan.52.netdev
diff --git a/resources/z9/rt1/systemd_networkd/10-netlan.53.netdev b/resources/z9/z9-router/systemd_networkd/10-netlan.53.netdev
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/10-netlan.53.netdev
rename to resources/z9/z9-router/systemd_networkd/10-netlan.53.netdev
diff --git a/resources/z9/rt1/systemd_networkd/10-netlan.54.netdev b/resources/z9/z9-router/systemd_networkd/10-netlan.54.netdev
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/10-netlan.54.netdev
rename to resources/z9/z9-router/systemd_networkd/10-netlan.54.netdev
diff --git a/resources/z9/rt1/systemd_networkd/10-netwan.400.netdev b/resources/z9/z9-router/systemd_networkd/10-netwan.400.netdev
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/10-netwan.400.netdev
rename to resources/z9/z9-router/systemd_networkd/10-netwan.400.netdev
diff --git a/resources/z9/rt1/systemd_networkd/10-wg55.netdev b/resources/z9/z9-router/systemd_networkd/10-wg55.netdev
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/10-wg55.netdev
rename to resources/z9/z9-router/systemd_networkd/10-wg55.netdev
diff --git a/resources/z9/rt1/systemd_networkd/20-netlan.network b/resources/z9/z9-router/systemd_networkd/20-netlan.network
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/20-netlan.network
rename to resources/z9/z9-router/systemd_networkd/20-netlan.network
diff --git a/resources/z9/rt1/systemd_networkd/20-netwan.network b/resources/z9/z9-router/systemd_networkd/20-netwan.network
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/20-netwan.network
rename to resources/z9/z9-router/systemd_networkd/20-netwan.network
diff --git a/resources/z9/rt1/systemd_networkd/20-wg55.network b/resources/z9/z9-router/systemd_networkd/20-wg55.network
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/20-wg55.network
rename to resources/z9/z9-router/systemd_networkd/20-wg55.network
diff --git a/resources/z9/rt1/systemd_networkd/21-netlan.51-clients.network b/resources/z9/z9-router/systemd_networkd/21-netlan.51-clients.network
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/21-netlan.51-clients.network
rename to resources/z9/z9-router/systemd_networkd/21-netlan.51-clients.network
diff --git a/resources/z9/rt1/systemd_networkd/21-netlan.52-iot.network b/resources/z9/z9-router/systemd_networkd/21-netlan.52-iot.network
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/21-netlan.52-iot.network
rename to resources/z9/z9-router/systemd_networkd/21-netlan.52-iot.network
diff --git a/resources/z9/rt1/systemd_networkd/21-netlan.53-public.network b/resources/z9/z9-router/systemd_networkd/21-netlan.53-public.network
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/21-netlan.53-public.network
rename to resources/z9/z9-router/systemd_networkd/21-netlan.53-public.network
diff --git a/resources/z9/rt1/systemd_networkd/21-netlan.54-management.network b/resources/z9/z9-router/systemd_networkd/21-netlan.54-management.network
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/21-netlan.54-management.network
rename to resources/z9/z9-router/systemd_networkd/21-netlan.54-management.network
diff --git a/resources/z9/rt1/systemd_networkd/21-netwan.400-fux_uplink.network b/resources/z9/z9-router/systemd_networkd/21-netwan.400-fux_uplink.network
similarity index 100%
rename from resources/z9/rt1/systemd_networkd/21-netwan.400-fux_uplink.network
rename to resources/z9/z9-router/systemd_networkd/21-netwan.400-fux_uplink.network
diff --git a/resources/z9/rt1/systemd_networkd_global_config.conf b/resources/z9/z9-router/systemd_networkd_global_config.conf
similarity index 100%
rename from resources/z9/rt1/systemd_networkd_global_config.conf
rename to resources/z9/z9-router/systemd_networkd_global_config.conf
From 311a4114f984cfab42abe55217a65da733919a46 Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Mon, 25 May 2026 19:26:52 +0200
Subject: [PATCH 05/14] z9-router(host): add ansible pull
---
.sops.yaml | 7 +
inventories/z9/group_vars/all.sops.yaml | 298 ++++++++++---------
inventories/z9/host_vars/z9-router.sops.yaml | 251 ++++++++--------
inventories/z9/hosts.yaml | 1 +
4 files changed, 294 insertions(+), 263 deletions(-)
diff --git a/.sops.yaml b/.sops.yaml
index b517a43..bcb30f8 100644
--- a/.sops.yaml
+++ b/.sops.yaml
@@ -48,6 +48,7 @@ keys:
- &host_light_ansible_pull_age_key age1llkxtfx4dgnezmukj4ganx4ql9k4ga4ca9zuanf5r568jfp8peeqal490q
- &host_waybackproxy_ansible_pull_age_key age197tmckjll9999v5apqh5h70dktdxzxn92uyzce5j7jmesvnneecs9p7m5j
- &host_yate_ansible_pull_age_key age1yc9s8r7zt6tc7scfyxc3345khdwqrx0lwj4z6yp56h6rmauev50s5yqr22
+ - &host_z9_router_ansible_pull_age_key age1tx03yh67f052jzehvtvzmhe5ja6ca0rlugw8pr9v7q67z38w2ahs2a4alp
creation_rules:
## group vars
@@ -241,6 +242,12 @@ creation_rules:
*admin_gpg_keys
age:
- *host_yate_ansible_pull_age_key
+ - path_regex: "inventories/z9/host_vars/z9-router\\.sops\\..+"
+ key_groups:
+ - pgp:
+ *admin_gpg_keys
+ age:
+ - *host_z9_router_ansible_pull_age_key
# general
- path_regex: ".+\\.sops\\..+"
key_groups:
diff --git a/inventories/z9/group_vars/all.sops.yaml b/inventories/z9/group_vars/all.sops.yaml
index bc4c3f1..f5aed04 100644
--- a/inventories/z9/group_vars/all.sops.yaml
+++ b/inventories/z9/group_vars/all.sops.yaml
@@ -2,213 +2,225 @@ metrics__chaos_password: ENC[AES256_GCM,data:seOU504dZ9K21+NK1MBf9isee2L2rueP6Bl
msmtp__smtp_password: ENC[AES256_GCM,data:FAih8FghRYDx3QGFCjKoJ8Zq0TkeCIx4n1jTx4/sASgECqvucg==,iv:8NDn3wj/bXsbHbuce3ycJTBVWde6XAVxv4NuMUkMbIM=,tag:jeE2b0i/8JPtguLYQvdV1w==,type:str]
sops:
age:
- - recipient: age1j0876shgsn7f2thxh9kx9x5uwnh45z6sy2jlk2qz5jhgedm26g5srn9kax
- enc: |
+ - enc: |
-----BEGIN AGE ENCRYPTED FILE-----
- YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1VWJQWnBhcDc3VXh3TnMy
- RFljQU0vNS9iY3AvTWFraUxneHIremlDeUZvCmdzd0twWHZEdTZSbHpLbEpRRDNX
- aGI4ZlczN0tFbC94TzJ4bm9aUjkwcVEKLS0tIHRGSGdkQkN6ZEVTUjl1cGhMZzVI
- S2FtSktoWmF2TjZCZnNlYWpWYzQ4MzQKeK7f+UPSanQsOIXNjzZa9B5FafNFsN3W
- sjssDdbNQ1OEn2CLWRVQl1umKrADuvd85fMu3gUZrycZRDCCfsBzVg==
+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxTzAzaVFSRDQwN2llbmdl
+ alBBVDZwTWhWUkV2L3ZLZmNDUDRyTitDaFVzCkNRTEN4ODV5ekxRVlBZT3ZIM2pj
+ Z0JxYUlobHZCeGxxNE9PcENkR2h2VDAKLS0tIFZiVXJHSU5naXhSSEFobVZBN1Rl
+ NnVDUVRyVWxlUnMydVhiQ2s0bGMzTGcKh97/UOPxrKieK5dKdGyRqCRi8Sm5UNcT
+ I9jLCPqX8Utt0e2EEp+ivJwFxgo7QuNCYWu6jtPCO/Zmc5Q/2tJQ9Q==
-----END AGE ENCRYPTED FILE-----
- - recipient: age1llkxtfx4dgnezmukj4ganx4ql9k4ga4ca9zuanf5r568jfp8peeqal490q
- enc: |
+ recipient: age1j0876shgsn7f2thxh9kx9x5uwnh45z6sy2jlk2qz5jhgedm26g5srn9kax
+ - enc: |
-----BEGIN AGE ENCRYPTED FILE-----
- YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkSmVEVyt3OCtvUUNqV2FR
- QW5WaDBFcnZVMTV3QWdSLzhxRENCdGNaVFU0CmxqM0xIWUVCSUwvY1pBVjQ0RCtq
- T0psSG84VWdpY1dYa2doeFZXd2RKNVEKLS0tIGNFeDFRYzBDN3NWcnpUSVhEWitY
- RXhLRkp3ajdlNGY4R3hRcWVSUU04T0UKdprDhBpp0aMc733Wx/K7hS/nLVohvlft
- N9aSQdcRoqT3/iMGu/6xdqbeq0/7a/U+6JvhYyWLkLsrzw2mlVRoIw==
+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBuVUtpb0FmeUduNW9EdHJw
+ WEY0WllWdE8vRlVhODU1dUcxUnF3WE5mUG5vCnBQRlNkblNHbUFESXhvQ05YdGVW
+ UkhjdjdvclRmTk55UXRGRStXREFiVVkKLS0tIDlkMHhxVkxEK1BjV2orQUtndGc2
+ Mk8rZm14SzFWTjJTanVXaE53UmViS28KQmnPfzLhgLasSuu1Aflp/JDWo1hqvYjb
+ BijruPUZ3NuoZ4Wuo56FLlTLrch051fI3ottzy85FfX3lRnWZ2IK8g==
-----END AGE ENCRYPTED FILE-----
- - recipient: age197tmckjll9999v5apqh5h70dktdxzxn92uyzce5j7jmesvnneecs9p7m5j
- enc: |
+ recipient: age1llkxtfx4dgnezmukj4ganx4ql9k4ga4ca9zuanf5r568jfp8peeqal490q
+ - enc: |
-----BEGIN AGE ENCRYPTED FILE-----
- YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQWWM1WFdidkY4a2hLNm03
- TGdNNE9ZK2lvelhYQndTYy9sUzM4TkN5elRZClJwQU1qeCtwUlFzeVE2d0FSSCsz
- WTdzQWZLYXpqUHcxc3VEWHZvNmZibU0KLS0tIElCTWdraXRLcHNHMjR2eDVxVCta
- bHhVdFpOdDB0eUR5d2hhdWJlcmJDMjgKBbVkm7LNwnoUVrUF3NPI7d25b6tAIr1t
- HelMjQU5YFM7DvRYFOlNpgO7WmddNSq3C6WYa8AZDGpsjc6GypcLVw==
+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQSm9FZ1VmVWhadldRY0JU
+ c2R5d0tNMDV5U2tzbVorai91RTFyZFdUMWo0CmxLVUJYdVFUN296U3Q3MTJQM0JW
+ LzNTYlVVVitRYmk3azQ4VXBLWTZiZjQKLS0tIDhXdFZaK1BWVFp4M09jbk0zdGpF
+ dGxmUUZkQS9sMXZoeTJETGpvQW5VQ0EK9Y/trD7VhjQnqY+KryPfEv1J/D4NCWsx
+ CHv0R1ps6A0qoRJzS1UNxU5bLXDX1RGQiU/arhJ7LXFxHrNOdObsZQ==
-----END AGE ENCRYPTED FILE-----
- - recipient: age1yc9s8r7zt6tc7scfyxc3345khdwqrx0lwj4z6yp56h6rmauev50s5yqr22
- enc: |
+ recipient: age197tmckjll9999v5apqh5h70dktdxzxn92uyzce5j7jmesvnneecs9p7m5j
+ - enc: |
-----BEGIN AGE ENCRYPTED FILE-----
- YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzTmRaRXorMzBQZWwyNFp5
- VHdUUElyd1V2dUcvQ3k2STQ0d1QyMytsRG1BCm5CVCtRWU5FVmErQWl2N3Y4QTc1
- Mnh3K01QUnk2MGpSZk1NRVJWUlhFYWMKLS0tIEFOM0pMa3RVNUppS2xOakFVM1lR
- cnlBL29XQVlsL1ZCenBIYTQ3S3JxQjQKq09vbn1XOC1jIXDpv+ThFMk9k7SyYknr
- MBJRBp/0PrKBo/Xk+RCSWSLjgali5Cc8KTjDTJyBG8rFzzvLIazBRg==
+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBreTY4bzJ3T1FHOVdhS05v
+ dG40VWdVeWRpamdqd2ttajFJUjdYVHB0ZXdVCmk0UUJuRHdsUnE3ZThNakpwY3po
+ b3dtWXNNSUlvbzVHcXVIclNlaVNub00KLS0tIEMwL2FYcEZ1dkZ5MFl0S3pWSWFJ
+ NGdXVXA4UGJIOTN4UnhoMjRYaTRNWXMKGJNomXuB5TqXZKWk3Ub/rEc69CrfYABw
+ bBBidbCQBrv7cnsvjsVpHHGaTwyP9Nk1ceF/gbv9fD9gZ7dwt3SA1A==
-----END AGE ENCRYPTED FILE-----
+ recipient: age1yc9s8r7zt6tc7scfyxc3345khdwqrx0lwj4z6yp56h6rmauev50s5yqr22
+ - enc: |
+ -----BEGIN AGE ENCRYPTED FILE-----
+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrQWhjNHlDU0RKRmdKTzh0
+ M3dhOGcrc1N5SnozMHhSQWNUdERPSjRrZ3lZClBpd1lrbXY5OEVnMVgwTGl4YmUw
+ bWpJR0Z6RDZubG9lS1BIVnEvMWhEdlkKLS0tIFhSbVFhVnZIN2xETXlWNlh3TVVG
+ N1VTSWN3SEU5U2Uxc2lRUmwwaWc0L1UKfPWAEs93dF10GZdlQt3yeDltk/9Djmuh
+ 3ZeGLgkOjcJPXO2hFQMZoJY7a2ZRIxN5Oa8PGwuy7DEtmQ9PdP/mbg==
+ -----END AGE ENCRYPTED FILE-----
+ recipient: age1tx03yh67f052jzehvtvzmhe5ja6ca0rlugw8pr9v7q67z38w2ahs2a4alp
lastmodified: "2026-05-23T22:10:20Z"
mac: ENC[AES256_GCM,data:JbnKG1qyAkvFDXr2iHu+gk7nRjedmm+dEK8vBFW5YzndWE4QKoYWeaqRHBk7wdWO9kpZgU2rFiu4Be+ikotoMS8jKAcd5wWSrWtSreaZxxiD2TWMWX8HwPtETnYe0rjrEZ3kPcUj4QPyNTphfbH3ARLjthedRXNF70NDc+DIpAY=,iv:4LN3oslWUWqoY3rQNVDSmlJn1o0c8JQELzsWd5btn7Y=,tag:c8X1q9XMMUkXed93j9C6ww==,type:str]
pgp:
- - created_at: "2026-05-20T02:08:49Z"
+ - created_at: "2026-05-25T17:17:13Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hQIMAxK/JaB2/SdtAQ//VIMBtLL8lhncJeItw53fQW4Lia0hs84yuKLuSBucNXhy
- x3LT5r21C5CZ+JnucrGPxur4clsLnDnng2CgyWhksJNknk6smQIq3ZhyBd/OJzS4
- zNGUJIbitJsDaKjTrYDCdsQ3KVcRBDMu3ow7vzeP4wnL4qU5fUuQ7S2rK6a1hfMB
- eTQmn4wD/Rl+Q0AWEo2V/X8UgchwGPeuOXfju2t9+1UVE0kUJdXw/JIrGyR8XrYM
- 6ZGXB3mPnlZTZjqhXVSFSSOUTRYu/0g+s/JuDLpgl8gVP+oDvSCPrB2pDNK+o2Oo
- VbQbJMg6lMbIuewd0ZTTeCv/TFU9O51RtkFyxHIEW7dVelDrNkuciAG1mDUHFUUw
- MHeWDjngeCzr1hj1Z78P1bvR7I2pqBQiWT+d/e50S5quNRVjtLVEjuU7r1eKiPDu
- pL1lYJZZu5+uY1nWE4qeJiI1KambjP9/C+RUCF38yT1wNvxrbwsM9haXGbI3t2cU
- X/RRpK5VKKKwbBqyQmkZX7xaDR13hLF2vLtdVw6L9nYVVactfnFr9HKDV95HUnhO
- uevmzu+ShtAt9FMXz86dLYmBx90A2BSWxb6sKvZkG8UDY+vVT1K0gNK4kwxR9rKt
- LFzCq1a3ftx3UvrNMCwaboGQZLpRtiKr0lNQvGLpH/SRDZ2HksinV16FNVuN74HS
- XgG5HnRO9/lkL2Bn+ms7Q6+ki9QmC21FlLGJOBQIi+VHNVwy6J8XQlrs5NZPy6Ib
- LmWIV6BdIRejCAITlVeBRBpXymdUBicPLa/VQMK2s9L3SS7MUcv+4j+vje9YR5M=
- =IEFm
+ hQIMAxK/JaB2/SdtAQ//cayg/ELKtybgayA4z+xOUK10zQJDE/U43BcPRMrBN0+x
+ VLu/C96Eom/dJN62SM2QamThHu454HMZj1PjDynMUzgfVqXEg/eG45bBBweWrI65
+ s0tuzLmsqpdt9TJ5t0znliL2DYS3MPfmYRNbAsYsCbQd4I0YpxdzQwTvURdzjpUG
+ nVBUfzfcYH1Yqq8BVtR40MKfa/DbOsJGENHtpkQ9UDAa3gwVQs0NyZRQzg5w364C
+ UvItYlU77ZCKPkyOQuciLn4sM5poihu3UNWp855QsDK6fZVuxPTS4Cn54cfwdOTe
+ rL/ZQjLcHJ7PRmZUiWR6GVNDrY55u7zhORD4b8BgrpWW4hhxpp/ENjnRmNt8jKR2
+ dJ/5/uC4HBX0fM3mbfpUn19BxCk9+gFPmNUOUZ93UxpQ28l1lZxeiLBOHAw1srEs
+ 7ZfFrJ0osedPGHu8rVOe93DCAtb/oNxr1xvGuDK/licRkEh8t8cvuoVsVhYFjNBc
+ UKXIPrhvuSj69c3OiHa+u9fNZJX2XAi0oOcZqGp+sQCCgUCA15I5QiqTpalCSTKt
+ /Stoj9BsmlSiy8YD2XBjmzHHVxJHfl8XHcuONKc3e4UmVjKlzkzc0bI73Y6XiEvt
+ zRIUmWxfvAvqP/zPcMSwaZke5h7N7ywKcjM+RHB4NqRUVYlBNwIWXvi7f5BdLhrU
+ aAEJAhBcA//3NJxuDzlf1zoXGKOhGIwNv5/Qb1n13OKIT2s0nfbqEHgAUm+tX3gk
+ VKKMqFuVmq2mkAaxXWFq20VC6djTJJS1QOaNsc6x3bJ6iDtYV19Ddn/20jbmbqmn
+ XbCDvb50nubC
+ =ZByJ
-----END PGP MESSAGE-----
fp: EF643F59E008414882232C78FFA8331EEB7D6B70
- - created_at: "2026-05-20T02:08:49Z"
+ - created_at: "2026-05-25T17:17:13Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hQEMA1QflAioE8i3AQf7BB0RdJbe8Ro2Fv4Phw+VaR0rUIuQKWOb7zf3/9YCbV2w
- rICGVIx7V1vJF5R5RgSfk0RDrLN3Pfoq/7Jfkq6bMoHIVCHSFdryHfjG5Dgm49Xv
- gDZ2CPAHPn15mG0Rr/67YUWsC2Jy4y6/JY478wzYu4Og9IkxkeBd6ufBFB6bTn4H
- qB7B2hfkyQzA66zoxc0r2O1mchbJ3A4pVJw0v2I/sWCiZoJQKmt8ksoEK8BAQCWC
- E8sozb2opRzFaUCZSNEdhz/rnbV8u5wW378kd8kHSOlWxaFZNkWUP42YQiNTkd9/
- YpxxGvwCTIpHGAYFtU7CV7QfQHzTuAOz7ZElPZsYkdJeAZCwUFO24nzwpxYS43AV
- 29IHXvlKAQkjJunix0bPGcE3D6T8CUs0wXL2sUSDcvgOOQZSezRn4UNEqFCftjJ4
- Gmldo/baMO2Y054/iA0jvNmHRk6sJCY8aRYv9m5Fqg==
- =n7Qb
+ hQEMA1QflAioE8i3AQgAm+iazJdcOXiq08MvSGMQ9/NAvrgcDav4561Hew23n4Ms
+ tKC5VLXf3l1f6yjhBZy6mnslYOWWdJ+X4XK0OqWkRr/t7zxEK4M6PC6g1W5hkaFU
+ +9DrkBLKss8atz3EhexK6GeljTuRpVWM629BtvMPBo/41eyue78TLf81vCkbUJkC
+ UpeB4alsETvD9Oz0ZRT8fipuXzdpGSjobOIgQa9bKwFMXXGY2fwBuKW8gVtSgbXP
+ mKwqvGaSdHz30BxQExmLne5ERKHOvzac2woG5tOmKPaihg8pbvuq/VjS2K0mzS5q
+ cbwyq/u4d5fGEFQYqMARW1aiyo3NjYk4xWDcGo5Ql9JeAdwhj3Wgm1wccULt2Hj7
+ z/V1utNINoB0bPFb8ZQMmPpwAeH6nnoqjWmmoRSW0tL/EaPh5xQXdEuU+DloT5f+
+ k8c2KQC+v4bh6BMUcycAeIG/h4vKsgz/Jc6BWKKD2g==
+ =G51B
-----END PGP MESSAGE-----
fp: 21C9579E6503CA815A68ABD8541F9408A813C8B7
- - created_at: "2026-05-20T02:08:49Z"
+ - created_at: "2026-05-25T17:17:13Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hQIMAz5uSgHG2iMJARAA4zyDJtNqK5w6QPYMyEtjuoAmva91yLA4oAU/diRpFXHx
- D4UzksW8moYqmaiWblFy1HeQJFwZWrxnXeqg9B7PFOkhriIG7al4DpV2wXoCjami
- DIkewGoeZjTbPNxsDVl0SbDafCARQFnQ8LNTmM2hi2X/ACg+c8mSM7eK6C3mh8yG
- Bo2EsuCnIqzwzV6XbGCKnfOUh0QekWM7Jc/e3oYGSgCP2N5wb2PLVsW1220qdPvo
- 8D1l5cDVj2Pgq7fnfbxZGJYSfdgJb1YweH8mjHk3gHU68AGeeSkV+VwcBGV2HObg
- hKSbVWcyGAHrP1ppCNyXr5ZkBgyvdB/EjxjLqTLq7sdTnqjLLbMLgi9CCI0NuDMI
- jfgMjOdaImjUvvr8lCl7dOMyp9wc6ks0bwRbfG3AMLGKWeR+un3uaDYujD0bQLqZ
- m0g5mx1wHxNCJIb2ZQ6UVjDlnatTYGBnxEupqxr9PFyny0MRhaiYkuDIh4tHW3nH
- xyCHN9QIO2/EktLkM4wcfhOeVgdpfvKgT+cMG9kS/yfInZ5ZAGvXznzvfNZZtKDL
- fLvvF5AqYbN05c0h56WJa65tIT75P2wI6ZBncCSLqSAzyXWlZFV6UBP+5QLEkQaE
- WtY8y2907OAx1v8g6vc5v5oHMqfwfWC4nuFbkoJo/ZbfvtDWq4eFZfkUKY3Au5LS
- XgE/l6NTtWknF4nPYIRaibum4527ke053JdD/50eqfuRv8MFIHbRPfWE4lE6lgev
- +/j0Ef9sYRu726Sv3wAgT7K6PmCFsLN1319OmjkZpBAJiNsxx9qwXyqgTpTvb34=
- =Hr9J
+ hQIMAz5uSgHG2iMJAQ/+NjXRTghMiYErsXenuJRaWdwHZ+6DkkG8nC5b+Aigljgu
+ OJg5UQgYtX5W5T79uUuEh5BWKO5bMHBwDNHQC7Hn1FseYgrOxcoSYOsewlb8t2QH
+ fqGLLhv82nRnU0nTs8W/yvrBH/ub0kAtuko1jkPSAWnoonmeEW970iLVIF9lCVYJ
+ idF+DDSiic9RDpHd4Csuxdv+1Q8OcaOW1HVAUrfrKOvC17sawd1Cat2DWC8EcOVD
+ clNn6A91FBCTxVnxwM4j2J/NXP1JRIGnlxaa4lATQMiX8lfheu0LyEpsFZai55RC
+ dq20HWqPgYHiamp6eGQ+Uqe5edx6F5YX/25S2Jfrx4D5vRh0PFx6blY0kgZJp16a
+ ywNiMtLPh7HjOMbB1v7bcWtIDWrIhWDtyJ7axny8sMamCLCPOwPpPvdL/B5YOntm
+ +0wMXHXCLCaljzsa5GFIyVYj3pTY/6O0Fgkv+6ow08ndPjsViHNikufCSW0ueIFF
+ ehv0V2+AHhedoHChFZI/DEbGzIKVcr7JAA+GHAIWcklg7O5hss+/rr7nYxVB0A+t
+ Sfp5kVMInLpCPLRm2retun3zPF8+R0kN/ZrkLy02K7z4rrD8wVE5QUvSCWbpKdfS
+ deWIy4lp9wRXSunag1/CxqvrH3ZszlxSZPEQkC4hez+xOS//L/5QsiP52SavB9PS
+ XgHvkL3slXXsdnIgm3cYnHqEBf2rXLQR/ZTzusXMLEBaGCd9JB33T/Lz+TUftCUI
+ xxLwzFvm+dEvQ6bOB6/OvSMBIsvVzMZxaIblwZRdIYfQovEdKLCRc+F4lTqV8fE=
+ =1lXS
-----END PGP MESSAGE-----
fp: 18DFCE01456DAB52EA38A6584EDC64F35FA1D6A5
- - created_at: "2026-05-20T02:08:49Z"
+ - created_at: "2026-05-25T17:17:13Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hF4DsZXvxFXTXoQSAQdAp7TsXm2MaBAh0qB3eOjtFuegcEsmtdQHsMP0rs0N/m0w
- bbbzXLwq1TGL82l5Qon4NnX9Jg5gXnKydWOiKWhxCsQ0iHJ7eupJLxyfDD/kzga+
- 0l4BRUpbBFslWWa8Fb7zfNA7kslhkaQIJAmN92Yh/2NdkpmNEpMMaIrx2p2jK4Iz
- mwGUQlUz4ZkK10xy+9LMaAtmLhBJgBhDTKKzw7OAsRAnASq2gXA/4wqEVgBU9BxB
- =tBBK
+ hF4DsZXvxFXTXoQSAQdAJAr+RX2f5gW5PpXJ/WA+1qMPFjuWuDccIk1ecWzc4kEw
+ sNH69jVC0JL7l5RMrJTAaY0GRTMrJffoz28JxpVbUVFEpeHsd+myGCcD1jZyS1MX
+ 0l4BllCKEsOVnEKKxOscOIctaIw8/MDNnLSoP04JI2xVKKThor+UwUhRzg+fVwxH
+ uEiHsx0xA/q0HVXhTNIvIWn0CKx/4uV8JwVa9JqjSSyQVm8PBwU+UTfXMQ5VcuHv
+ =uxSy
-----END PGP MESSAGE-----
fp: 9633412309CCB83BFA39BA5F2FEF746201D7FCFE
- - created_at: "2026-05-20T02:08:49Z"
+ - created_at: "2026-05-25T17:17:13Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hF4DerEtaFuTeewSAQdAlBZhTjLL3YPqorSXq0jet/0CXmeZeLL8inGvm/HgmgIw
- aplmjWHB80err0ffZeRfcvqx9DGujpwlgoFGDxjqn4LIqoNg6YK/VfFb9pXUvIOv
- 0l4B9xQ4DlaYOX1egCQUBw3KcdcnNlcEZwTOwTKn0Hg3gXp0u3TYlJFZAchw2G+l
- XJjlWiwJN2gKfEG7hrtZ7MJkYJFsqMFa1aC1oWHduxU4jmdRdQqdIaQDsqkcqJc3
- =KNVY
+ hF4DerEtaFuTeewSAQdA2k3VLlMvCocHQ1ULFwTJKqscSb2FScq8A2I1TIdlfXAw
+ jWLzGphdsfHuNBEsocoixm4nKAdhjgBsud2rfYkuwxpqX2MlBr6ikpN73dXlHtt2
+ 0l4BkUvmqlioN961OV7nssbeQLzb49C9Gzm5S1dQqBQVCt/7qGodTHHiQON7bYJp
+ +OgUaI6bKZjd9Lhm/u98dTH2cdPm1B5bUQPDzptWX5vG8euzBQxXc7OrGsTFyYME
+ =e/rg
-----END PGP MESSAGE-----
fp: 057870A2C72CD82566A3EC983695F4FCBCAE4912
- - created_at: "2026-05-20T02:08:49Z"
+ - created_at: "2026-05-25T17:17:13Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hQIMAxjNhCKPP69fARAAhSBdgW04fKM8tAU8sC6h8/4e0Io3W/D2l6P7nZiD9WVR
- 2pUqS12mlNCoRt1I2empyJ5vm1wjor34BCuSCiyfLQ1WIlBJlDro96ygpsHZGmam
- tNcrgwc7y6rg4ycqUWr+H+WVZ0kw1IYYKbfAjMAJF5lQqzz+VMvET9BbmvA595MO
- l/dnMColnjxxBiYBIzO7mnli+uqRHB79rM2VVlrqoT+C2s9zuPfpJfY0PJaCbbdg
- BlffAMqs9m2JZdDr2r0lrN/jyLUB2d3l9NCcF6UYP6tjgZsKmHv/JxSgXLf6IklE
- wolO04qgDRK7jeO2UGEniweVQNi7hqA4vkp2TskGbfVsS10PyLYKw4N19GedLS3c
- ZxRGde42Fze/PrccWq8bGdOfWhPBo2/MEyqVW4lgTeCCwrFRO3UNyYcWo7cmaN1q
- lz7uaV6ffqbUDJSkjkphvxnJtuX62x9Uv/wcwrJuZUarSNclQ0nQV/e5wc7SzPgM
- B+GLeR4tnconDZGFq8q+KKuHe7MSx2uwiZsJIVXohcZwhkd9wk5YQBPc8i4aP0NQ
- wsb+QptuM8VpCEVAwKOUjp7IRRfUyqAIlmIRDkTijmHknSmI9HZXPyCvTLoy1Szf
- KDrN1MAma6b4gsru1fFnVizXQyZozl5RVZFP2Uv+ndugdvRE5sv5aevlzgaWFg3S
- XgFqaFwId78UDNTrxcs4EzjHmlwg4E05G9pUqbA9zBDdCqwlD4+6CfAgQ46A6ptY
- 5p2QQJ3KXgJXrtlJySq8piReyq3mpagtWZJfAazovJA/ZF4o/xs9ZIu/q3qxHSE=
- =nR8y
+ hQIMAxjNhCKPP69fAQ//VLyOILC6lpvlq0W7NeYfUzL7KtKYXVDF7aSQ/b6Vn7Of
+ ggc9n40n6FkMJqknhbvSnhhlFdzVOCZkLy/hinNk+jF2POBlLbzBjCuzQSP+ZDyC
+ Dll2UJ/khITd+tQ4zwrFLpixr518Fgcj8NOgtljUovxR1bGIzYogpmiVFJEd0cT4
+ k7ldv5WbZtB2UprhPPpNe+98BaUvuSvA9RWCogaBbuQpY2p3g9t9Zo58spOawbP4
+ ccz7Pu03Esy3cenlnCt3G7gl19viIh+wHKrIXPa8dGO6TEsrRMPT0tNEs8iUJyDO
+ TNEgo6+yxQ2p+08EzAh0BCRwljqnPLjS/h2s2s208Z5rBOCpLY9RuoXz7JRvZ06p
+ gBgPFSIH12VBGjfqCB1uZIatbtLQLjOo6+UU0evM65WhKw3//tUnLrox1reoiRzO
+ ro4JuytP+f4PylQRsr3jOYKRKCBzoZOOPZbVEpwQeBOe9zzxDgVQqHgVDDZQzCcw
+ VTHCrs4XVHxPH0aRMlS4A80xbH7VncYbcbf8a6VrTpnPflv0OryWMWDqLBzmIPgM
+ W1Bz/hq/o6br+g4uAKjt4GTdTwWYxptA5L84aMoihpXRu0MaPhG+7MRsXpEa/+Ll
+ +ybl2DLpm6zm0iixkJuxwtOdQOGjqJqC/GLw/EZJTt2aO+ZUb8dLrChNmR7HJAjS
+ XgGBpFYao1AQqLZU3c+5B2/9/3rtOoVX1DQXhUsji5NkaHyYO8usauj9evPUf4qx
+ FAQRWua5/zp/cTlNWU3GknqtJ1G0g1mrkiVeBZCRxIK2Iyvyav7RALJ1jlkyW5c=
+ =meb0
-----END PGP MESSAGE-----
fp: F38C9D4228FC6F674E322D9C3326D914EB9B8F55
- - created_at: "2026-05-20T02:08:49Z"
+ - created_at: "2026-05-25T17:17:13Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hQIMA46L6MuPqfJqARAAjpM3MO83b2EUtzyZs66HWH6Kd60rl3QODTqs4PQm1cH5
- HdzfVJ2IDo1y+FMTMmfJov6xBqnlalNaOvg8XFAkKTUkZgUHRW/q1WXP4FywTWmP
- aJV47x4dOQXQgj/i/ykMspUgsxA5049/nG1y06Wsm2agLO3KjL6KIJAx0LI28XPU
- qA/NFtfNuEAv7DGS2LGz1+X1hnRYcBX/oUgpihzActWmMORD6VS7xZGcMdF2/+Ex
- OCDAnwT0cBSAihBSLTmEMJ4xfmMG228nbLqm9r/gELgVIsIL5hXWz0CtxaewwLQQ
- XFMm/ZV/G6bZKRJzKPOR9EcPMF7Z+nnBts9wKNlE+WA32p7zu7hjvEFZhLiDKYlN
- +nFcx/rvyWB6sbFK0xn2x5MonxWNVUy58PnqGWmPi2VtXT1al1zSAoKAgg8Xdw21
- PQENtxqeUSLXXb0SZXFptMmYStwqoaFusLOCLW42DogFU246o14veDDtsS619T5G
- RrszsNg543i3ra7MIm99YRXyniUaDp5VlKufPkWRexIT5YZYalOLtdLcaTTzfr7J
- x4PNVOK2ddtmlKbbakvvmPWS3iBEUGMqw69dPhEdpY8yy7HJ2jpXX7TiezNqGJ9w
- XqtI9RJmWrr0/zSoim0EpHDwXZhSf7YVcwTs0XCtwrXcQT6DLaZJr8cny/G1ErLS
- XgEdnUqFpB1D0bacmRpfHA3PLZJd/x0QfwZ/b7gzz3f1xRfMXgnsM4iYu1S8+VAW
- Dy21iVFZledWfrmuXh/PkLFftLipYK6tc0n922kFFxCn/xSP0yx9qKlNwzyduNI=
- =4+Bv
+ hQIMA46L6MuPqfJqAQ/+NK0D10olgDK4KcArzoMtrJR7qwbrceSeKwaQGsUB1+RZ
+ xv6pZJ0zyw7McTuUV2I4bLYHy/TffSyJk5vLSSTGFXgHVdfKmjvm7VDEp5d2uKku
+ GW3Qh73quldfhd5GjO+F9V/S3rCysrNMpTmPnR5ha877FKGtc8168XRhIpe/1+mP
+ mvlE6h0Xizbx9myGR+ie17nHpoH+tjTtQFH640s38+xDgH6AozwWGUe/g5TdLaLJ
+ 8SKHyQnS8hOHQDkttvhWRbyhKa8WuGyOKSjuQ81HIv+/UPxh1fs7vovPHM8rtIyy
+ xGcWPzUeoKQiV2nyXUP3BqglhOhD1vokh3ejDcxwWWKuyASCSXhhvW7KMsV3Stdd
+ E3O1nyOi4+2I2E4TQo0NLt5mTJonPbvSn4IvV0LuatrG902UeNNZRRwQv3ZrVp6f
+ G2ZJ9HNSs+Tp9H8cJzBGjDBYjC6/d3GGWi7N/5G/n6C7T6W81BgO8UiQOleEDF1c
+ Bi6NPNeoGL8fivVGlGTHpLcpPpbYz+1ynsFs1ho4+v5bHS5w+UfvVvQC7dlDKmR0
+ fUAkllcxLSnzKkpKis1HF+Gp+lSNc75/BzOeTA2gS3c8H9jMuncRolndPX1rVJA3
+ mrLiQE/Mja9NaYHzUROKIHDEUOQ1ZzvpcRduggvfj6Gb2wzNdUdR5QrXnLeI2jbS
+ XgHO7Jr0HrHzr/+p+w89U+uH4b7onseYDiAjfLjAZpcYwkzuy7b2ZUmpLq1BjZRo
+ zs+rSqv4BP0Xa7LNIFrHj4OeL9ivwP7Kw/Tb36hU8DJ8xDfilx81n69Fer/cJ8Y=
+ =BNfm
-----END PGP MESSAGE-----
fp: 8996B62CBD159DCADD3B6DC08BB33A8ABCF7BC4A
- - created_at: "2026-05-20T02:08:49Z"
+ - created_at: "2026-05-25T17:17:13Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hF4DQrf1tCqiJxoSAQdActtZQL4KWrCP8UUZa/fLeDltuNV9JjxTYiI9upoH12Qw
- 6n8EBLgKKNw1Hsb40u9M5Ro7Xzbys7zwZsL5CxEgFGDBxthtcdaI/ykjU0W3poLE
- 0l4BcMpLoCyxxwIn49GpFxHiv84Q9xhouSMmCTe2p3bn5zCRBnKsetVHtEti4iRF
- sY9FipGcyiNHfkp8KsWeUxD/j1QUIkGODXt2RqYkO8ltA5QS3kUCPErmWYymEAEu
- =RFaD
+ hF4DQrf1tCqiJxoSAQdA7az9ylWMB3fWHwSVRmU8Gu4Qnd6HIyMuiG46weuS/Cww
+ QMCknkfCG06HtMrOcroNigaj7G6FEvDm64sUkpW/ggWkHUUEMuwi5jcKIdx7XdbJ
+ 0l4BDGUF81uOghQUq/JqDtiYPD8IzRHMXbJmXiO+4y6DE5b1t99wBUt3C5K5H91D
+ U3blcYO6GROPSkVp8ZIzfnWLvyVoWInd1ZiRs19n9MN6Yf8uWfx9/3xvN2kKQyvj
+ =4X+A
-----END PGP MESSAGE-----
fp: B71138A6A8964A3C3B8899857B4F70C356765BAB
- - created_at: "2026-05-20T02:08:49Z"
+ - created_at: "2026-05-25T17:17:13Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hF4DzAGzViGx4qcSAQdAoNdta1fDVjzrPWeSfKrmslkoFi86I2nWplPOli/gFXsw
- 2Cx+wmejLlc61RE5sqAaQJc+0ctRezwXzBJbkuqznZ2jWPCK2A1EQ7r3Q7USCCca
- 0lgB6XOo0ByOj/W4TrrGn7VmwLvEqIiWCt5zk4BEUSVc62Ffv48dcwL3hsB3HlRw
- 6FXyR+2zwyEU5fuddFO4nMi8AXB6cfU6F4ugFgwn92lCgTom7IULY1D7
- =Czq/
+ hF4DzAGzViGx4qcSAQdA/+jZ9/0jHioWKE2TK24OFDKjJ8futm2TP8z6Xat3uxww
+ DGwSznxagIkVgdTNKqAWmzGvOum8xDBqzP232CM8B/oxmwIjuIV8+FXtJuFHA/4b
+ 0lgBN9loSuX5uL5O4uWzPulEhqjFElrWRZXLHZn7uIWipW/7mP8CGu02wwV/lme5
+ jvtJ6EjgopmHrxyaJqRk+e65gxBYKvxTQ1H1iETCUq8lOnxSBZVY5m5K
+ =7H6g
-----END PGP MESSAGE-----
fp: D2E9C0807BF681F5E164DAFC5EE1B61CD90954CD
- - created_at: "2026-05-20T02:08:49Z"
+ - created_at: "2026-05-25T17:17:13Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hQIMA2pVdGTIrZI+AQ/7B7h5br3PMgum71smOTJMBfl4OaxkQAirJeG/z2fjqbAG
- l9q62H1cutGKS/IYOFLE0OQaRwmHtkdTkrdmf9yIuAktcdAGAeqwnYW3LwM3t7U1
- nfZRJH5Hi4xcSVVaWHn5mX0QpxzrCye1EIjHvPRx6/bWHD5sW9qnkZAlAvEJS3/K
- jdyBLLlK8AITpsX4eeVnmVLZBjbVEXPlXfFCh9PFyqrl+iyBBY9bO2aMzWldbQIr
- j1551Xe1wKAOn5SJTg2Mrm5ehBKfH53HY6ubCy9acbv5ZTe6JuStseWordtRNNXY
- 9eVmR3MRVoFWgK4Ccb9Qq8l+uEHRuQfG9K7dSnxQIJpHCOAQO9oi3/ykDt9Vgvo6
- WKPpvyuJpWc5Tn+WF1qhz5wDTRX6XY+cUoHkUqZXG0qMTIfMLIAFZ6MuslHU9f6J
- PlY0FTnwp5/v9rK/rjXZkfIxKjQtSWZwkZCszZ0WtNVuaY3KO6KYrd9rolFFYjqn
- I2xFGnTNZwh3tjG/3INoMwilOkIUNXr18k6FsPqVCAhj1Oo0iNxb3j+3pGJsH9iN
- ciTLeM8MsFW9MYXG23i65a5WVXi8hMTcyqCy9GyxLeFprt2DaH2HaBahF3RIWPop
- KTNsvW1aawy+lDUyr4mBy9F0TA8Z1/db3l950Gtuz5s9/7D6bbmRn72O++W1RD3S
- XgE3QuksqaIh7ZGt8tVPREEHpBWmPCskh35vLoqeO1QxGxzJcjrcuNeHtOH44EEj
- mHzYUydn0e1jwKZkATG23DiBCyMpcNAWmsMH45wmk0fgNLdQhuslhKLqOUDLpN0=
- =Ygd+
+ hQIMA2pVdGTIrZI+AQ//aZjaPgcAM6RSG6QCnYJgn8EDEhG7HDvXmb58G7VfxArr
+ m+K4Hc3hW0Hh/c7/bzu2QWniN1ie4apqFSvQmAIJ3zQZSyOsqhzvbmyTFRAyzpzO
+ lOAo/s0xMu8s5V055vC2KWnKuqb9+WtWgJPotkpOf7wQM3aqtvXKFnPa74ihjXdt
+ uuopRsOsZPiG8MLcqkCrTy+pd1PywrqwjKeva+mfgbM8zpypw4kwLwrljsxCThkZ
+ To4dH+K8oesvSeyVOKWtAwnjQsPa3Zn5CFWXNwPnn2kpjyMoNRo07xuRkfHYI4L/
+ 7D8zz07XdN47kJbEj2BYjChURtbxkFbAxq+IUDgbNDW+M7VQCKZW+vOFjwmFJAlT
+ CCco2I3lmrVX1j9BTMRr/3aQNbY/OzOxk0qjYZGnPqV1bH4IazaDFUB8pOdmit2t
+ KBzDt1L26V0Ek1CpOp1dcJxneITXX1j5IqjMbl0TzyoJ9CxsSaOWfZ6XsBBSXZNZ
+ VnDENbBAOGcJgatjmC2qH5FCNio7vMRRncX5j82sytDRWbj/7XHENFpfXyGPIuYg
+ AaHyxSVegFCeRUHpzXo+qeFpNFR4407v+otVaEdxbfj6MQfMZ7tDUOde+97NNRow
+ tAMUOAN9yhGuEPMPr4stQUz4lHseGMX3VdpJH8UQH+BxVdJhzKg0H/+6bAmnRi/U
+ aAEJAhAi7DZdrKpPPkDijPKnXCPJB+IzdAJdOCsnIhZFzaiDUo+RLvP9bEpoqv4m
+ ZFMtiF7P7bXyeNIObCCsgKhdX0thXI9lZvv7k9M4lAbFhPS9vlmDwf25t2Nm9Um8
+ 2tbINg+K23jp
+ =syE6
-----END PGP MESSAGE-----
fp: 878FEA3CB6A6F6E7CD80ECBE28506E3585F9F533
- - created_at: "2026-05-20T02:08:49Z"
+ - created_at: "2026-05-25T17:17:13Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hF4DKKbvh61jX5USAQdA8qtjYHoUe+GUdy3obbF+pNmvfuKQUqkMHa6V5ZXOpXAw
- M/kx52Vu5xOdynB3NMBXsfTVH7KXh0f06HcehTREOkhlwVMYPcvDQQdzgJ3Xodpc
- 0l4BdYtmbmk9ETTqr+wXvf+6BMYIuvyhsLLSqyWyCxJv7blQYsxsc3EAHZ4LB0ZS
- /lw6gQ5lmQyvVt9PQZayt6Iku0+WMJcgrf9xykOAm3N2QrtUnr4jHV3FydvTiUwR
- =snV0
+ hF4DKKbvh61jX5USAQdAHw+hxKofus/fR32ThZOHfkL+8TIPvWeYnTYe5UUCC1ww
+ AtCE+MfZvMgRx7gUpVPcdWtch6nlFzun+r84QfPopFk4S824JFEkK8jG0scYCpy3
+ 1GgBCQIQm+g/LWX0T3Do0NXrRGIuw0fiKrQiOpEhbO6a6ez/pES0zKKBdlH+scQl
+ +nLZoz6Mw5mkwhY6zIKsrikuQ/+sciO2fIq9tI4MR6cvD5gmVrGEjIyOZ4xgl3X9
+ nX6OVR9w8cR7rA==
+ =voeW
-----END PGP MESSAGE-----
fp: 41FFAF3D519CF5C039FBD8414BCC213729AF0E49
unencrypted_suffix: _unencrypted
diff --git a/inventories/z9/host_vars/z9-router.sops.yaml b/inventories/z9/host_vars/z9-router.sops.yaml
index 89f18e1..33bd3c8 100644
--- a/inventories/z9/host_vars/z9-router.sops.yaml
+++ b/inventories/z9/host_vars/z9-router.sops.yaml
@@ -1,3 +1,4 @@
+ansible_pull__age_private_key: ENC[AES256_GCM,data:TlMDo9sUTYznxKOGityGLexk54mM7LU9+U4ln0YYhO5fhXXmwvySxyMLHlaKzSlpU2/mRRy/0v7AIOuRVZx5XqV8X2JJsv3/NeY=,iv:r66g2UQ663KvWyAISitbHBRaLBlJ0gB2g/TW9JiL0Ls=,tag:VEq3Fqj+t40uBo9g4Icfew==,type:str]
secrets__secrets:
- name: ENC[AES256_GCM,data:gt9BarzsfE/GJ5gQeelgePquW6KAgE3Exv4=,iv:IPpUQI+zkf8O+ej+ZxLFyWUOrxGGlZvmDRG0ut2cNsA=,tag:GP66MvcKyCqyKV814+uMYg==,type:str]
content: ENC[AES256_GCM,data:2ljp324rAsF2zk2631TI7bV1xKxdFr4u4NxrsPYnjWsL0PX0n0KhJ1qvJCs=,iv:0+DxsTTiNLOg5iH83bFT/d+0uW2rn6bATSm3xc5PEdE=,tag:XbBDrrjriXPedyT4+sBBwA==,type:str]
@@ -18,180 +19,190 @@ secrets__secrets:
- name: ENC[AES256_GCM,data:ERsggezMBbs1YwbIgwzKSAEHWWOWYxap8IDdn2YtEKvZexqu,iv:XbObLp2QERgt57tc/Cpha1CWXi+GttcIU8hJFGSp8e8=,tag:FqCuSbvLRERpVnQTzQsfpQ==,type:str]
content: ENC[AES256_GCM,data:QPoZA71CwE8EFE0I+6z0z0O1bUCMQDDDG7wGNoxXKt3ovLkFt21r8WG7VhA=,iv:InX6A71f3DGTg1wO4G0ECf488+FnKgTHffVwvJ9hHQ0=,tag:EVxwJlneN1CbMLXto7uLFw==,type:str]
sops:
- lastmodified: "2026-05-25T16:29:22Z"
- mac: ENC[AES256_GCM,data:zxtV1xgjQuKNMvh6S8oAOxX5J6+iBRO6k3vGw3vWNlhah4Gu3S/lt+5v8lQHogz1Vyc+Zff0yMj1cn6RstDDj5AuOCljRQN0FYs0fjCo4Yrxx5sMMwcwBYquC77skEiZhRnqdXKkjiOM7EGE8qj8O3DJ29borIjm5NAsflH/qkA=,iv:7EUElg+gu8mk2Gq32JQMTf+A1+ZhZufoqt5bk4+Ca1E=,tag:XG+F/zlXizsc2B8THoXj4g==,type:str]
+ age:
+ - enc: |
+ -----BEGIN AGE ENCRYPTED FILE-----
+ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxallVTFdueHBucXBVNzIx
+ cENqanlOOUticExzVnlERS90b2hWQ2VldUE4Cm9SVmhZejVzanRDTkJhQzhwM3BM
+ MGcwTEZ4YVQvdjc3clBHei93VEN5SkkKLS0tIGI3KzRPbjlNTFFBL2huYlZSVTZh
+ OVdXYVRkVVJwbVltSHBXRktIY3BYL2sKe+eqKzYeCUWx0KmT0+aM+TwWRj+P0Ecp
+ tnFHmQgnEPypIhVvZtzL7i64kL6sHizTmNhbw+hlnCztvsdEV5T0cw==
+ -----END AGE ENCRYPTED FILE-----
+ recipient: age1tx03yh67f052jzehvtvzmhe5ja6ca0rlugw8pr9v7q67z38w2ahs2a4alp
+ lastmodified: "2026-05-25T17:15:30Z"
+ mac: ENC[AES256_GCM,data:IW9eN5H2J5cnXUHlK2aD+yd2ORx+weSFKBGWd7pIolFb5txg0WlGVp8UpD4h+Tv0SJ9NkQOT6KpcXDez/L7r7xNYtmgf7AdrdGpy3IOkEYzHJ+oHUMd/aL+h5w6/RahrpxlPSrNKAC+AfpY+l0iodwQ09iuLp4YXFxRaRDGpGZw=,iv:6M7RkDN9D9Zlyq1MCRoiT4f1bd6OBZNg+C65oEuSWn4=,tag:wRsq4lt4mHVyY6ruGkYNKQ==,type:str]
pgp:
- - created_at: "2026-05-23T20:58:22Z"
+ - created_at: "2026-05-25T17:17:14Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hQIMAxK/JaB2/SdtAQ//bbr0oza/X6GG43ay9coZbb+0aptj3pGzQqT1ND6nsI34
- iY3IZaMZIti+j/BS5kEfmRn56WZSx6EcbSrlbiyL5NZw9R4/bGRd848rOLwMvuYO
- 8Usei9jHdpHiPvKBZnZXaXGU8E27L0Y/LCxSIFOXbyHzHogjz3JmtJQsYpSC+ue6
- mIRrSAJPALrqEL+DZ2bl5UYlBIRXdtIe/jL1CFCJhULt+EjJw72T62DZK/jaNZTj
- eint63+IFZSxx5e5vrAeQB+p2EDsp6c5NbDrlgQWb8/J1q/G5bG4KxBs/0hum7OW
- /sSsIDb4Qb8U/axt5LduV6AkMXXsclNLQU/LbFAbBRcV8Lvh11f0U3V/UnqUdmvp
- efesb5VQh1x0uWjzobxaioLEV/YYbWx8binvuJ3MBHKp6E2xj7IrBTVl0MWgjEou
- ZbQDF8DvxA49xEnJyOviL2/zjnV1kXy+Q+BKZga3pr8AnBHA8Ftbsvmk6CyDEM0R
- i4FAUOVa9VWiszoOaqyn1Fl02YlweFmgzuFjd3wi74Tbi6RE37rN/vBKySbnRQYl
- rFUU3SQlztxd4UBAXBo6gQKTz5B4rehvKVye2mmqEE9bas/lCWAKVJ7+3+0NQdA2
- lp/X7h7DRSD2Qkd35SzxkJz7P86rd0LM1aOu87psxYavEWw6vFs2ErDkSeqDn1DU
- aAEJAhDb1s+jpDUa3GvVZjoiiCyutI018jfJU1vi12PGktg4KJcXBx66R/nLItO2
- ba6o66scIiAJZ+jYymW6RbJTI7XRHJp4Cs8COhpMRQeOGwEHFGGL2rpGd3KrOLQe
- 0/C6EmrJvGpl
- =atNE
+ hQIMAxK/JaB2/SdtARAAlyJLMDlT4FLpMKaC3ygn1cfA2390Dz24lzKlHmwl5GgE
+ yS9bdTGMpcM8zPOQoqaoy/my3kgx2/U3q7WiCTMdUyYePAWuJFh8ZRZjw/hPpv6n
+ GwYgK3M2C1I9++zmZD5LlR4TaTTpr99+hctYrrp79QJddgozUzAQ44g7WvDm5VhI
+ bb2UVSo0MpWvLEMXHqH9YZcjkQyVg/DL+IaU1rM9pmpZxoN7+0jQY4ci1ZeHVo9e
+ DbYcjMazBLakjZxxdtHrqx3DjZgbYCancMy/dUKVuvDF/lN35WWSxslv14BNHljL
+ +/9YBDRgIr11x9j1hq241UwBW+6mSFxWF3qQ5esdR5xlLEqbm27PYGtqC4LIdzRX
+ ZUvdujuQ2PHCYJY/jKWSf0cdfXKEGorc1ZGOV9FNq9L+aKvfmRLWfzX4D0Hp47H2
+ d3itVuA9KYOdzmk6O+8FZv/VK1042L90tOPJhrtE287KhcJ2CvfT/Az4Qot8xg3c
+ tXmO3cWQpigXxJPfKRPjmmLJ9nq0BnBXj5ngkVz7d8R3FR1J/+TWG0F1VU7YeW2+
+ Z04RAbbKf36xUTqnaV34EDum4QLLdTMra6fPYPy0KiQYIKDcRSdHeM/hEs7JXP1c
+ zbUX4xuBOXl7kWYR0e3MUTzxYiQBr9BvSDY+7sGQCb+fPw+AKvFxig1grjsnZvPU
+ ZgEJAhAUE/ebqBa2nGimcAPn3PfeihehcmjLg7HmyWBPkHHMt/TIOztjkbGiQSC/
+ jBP+rhjmFxm0WKUGM4dkh14JkMgz7DZ9fozzLfo8zN8beuSDDzX1BndTIMBQJj8P
+ Q/rk1NL6pg==
+ =UXJ9
-----END PGP MESSAGE-----
fp: EF643F59E008414882232C78FFA8331EEB7D6B70
- - created_at: "2026-05-23T20:58:22Z"
+ - created_at: "2026-05-25T17:17:14Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hQEMA1QflAioE8i3AQf+NkUGCBrTCkkyl+iBb6P1IWLDGqAY8s20mBZ7G3plKE/J
- UrIe947letj/8EA+yoN0uzjwEkh3rDLtZrOLTSgflq1GMpdVhdaTbS71fD3kghJQ
- P9tz0zDQEgXHBi+2q7iRrEETx/cu7UDNkSCNvQbWvDmo8MfbSBy+VFCknfupdQxj
- 9hlq4kBA0pckPCY8V7E05nDhQntS8wpXIEO1SWiSuiGg+p4yFlvNzWNfhLyEFHxL
- BZHVVIU/mzyClMajjLJWjKI1LSgHXXIa28tgdrtiBZOsF+CWveYqJlRJh9NUepJI
- ZSeFNhyWmnS9ZkQu5BUyb7+oRxfq2NY51T76Xbo8gNJeAZWwyr1sj1wjubuVeNMF
- aU6FiynYWr3I35JRVghTMJ93CnPl+NTpWnQuHpq1bzEGe2u8BMFhgrTu2yMD23VQ
- eGien6SqfEbA/wAiz9ZaUgTQH8UyHpliteZ8/SQgkw==
- =UJvq
+ hQEMA1QflAioE8i3AQgAg+PBxAqWTfRhxP7GxDfQBPK3d52zshP9xhutqANzszhs
+ nbo3nHWj/vjvHlEuD+Rr/lr9qxsE3qS4ON7FG929RoB1YFHJnQl29Xym2Q34T0Hy
+ Ih3dibykm0t/NE+fuxsU4iU0imtjqhqA6P0+8FNF3UeCg60brcqlrBTXM9jFqlZ2
+ 9nuvk75HkM1FoHiKx837qAd+RjNNO7xKUpn+EX0l0l9tScuPqUkWNQxLrbHrcO5M
+ bcEC1syZHQKCiucsesS1pJ7TFWOJsnamZyaqhzANGwWdhYwGQv37bWKr6dYTCy3q
+ rsT2NxQK4/N9CxmP6xWeAZbX00BDhNMfEQVtTlYLgdJcAS433Hiw+DSEwGu2zvTa
+ pHtQlGlaoOZemNnthw0NO6JQWGhz6Bx5QqYmbrshtVKNPh87vNVV0HhL/fQ7qwLp
+ uCgnMi3P59r8EKDZqTSp0YGfE2bx2hpBDnyJ42A=
+ =rOz4
-----END PGP MESSAGE-----
fp: 21C9579E6503CA815A68ABD8541F9408A813C8B7
- - created_at: "2026-05-23T20:58:22Z"
+ - created_at: "2026-05-25T17:17:14Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hQIMAz5uSgHG2iMJAQ/+O5JOJfDp/BuBCuXDQVUgJagspQO6LZ/MLrl9qH282AMf
- MdgN5M/WjbOv6WZDCMg4nfXps1XgzUEiaA/1m4PxHlMmxjEoQHAE51GMcxsXg+B1
- lM+8uJ1+js1sdDX4xsZtJpbVxJKIbPuhF7oM950oDlL2+UKhUbPlCoxeOihlkVGa
- RqHJ/M74xkyKH281oRI5bllJaAroBnXVSFIvbCxA7ts/O7YJPKBowTIj62Kye9Ra
- aHC11bPy2RlJCcFZJjPSdnXvzUMpfzEd6O72VUtMBBQZn/in7efutC8FwpRYuUW7
- vSofxUN5n6Mtb8A1XSMFD/nfXVc/pM6Cu7kdtHSwSKgbKKf6mrCeVgaM9xcG0t2W
- 9yEtWvkdvOOSqz/vd1vkftbBWcCejX7bktfmD408CJAs1bjzz5CyrDoWcnYmbxFY
- 6N4rhMDRMTe19VH2UQ4EvSjQjmmYCspnUW3/78zi5kU1ijyQy13UpbgwulU7tSGc
- KKtBjPoy6mLIVl0YhnEJZWD/XPIRWyW+0s+7m70YXCWSVipvCelEE8oPWjf8PLaE
- J85crlZGkSRcRO7yOP/YtB9ZnajgaF33zJU3ZWr0C/IXj2TeepZp/JUteD2H/LRf
- 9YJzOFYDOFIWcdmaTzJLBEaefWcDjT6wkIf6TBqQRMLsu8JUwy9VwFcsi/d5aMXS
- XgEQqSxYb1B39OR0sS1Xpw0/CFe4imBPuG3w0tOAyM3DbPWYY1kZYIRZenV1ZIOS
- aRZJh086kuWgHYB76VoNzDK3QperWvHL/8CT2g3HuPiVGSrrXwxCYXk5+UXB9bQ=
- =Xx91
+ hQIMAz5uSgHG2iMJAQ/7BOewbq1xQgTOruTFebugbSrodtfUlIDpCez+FZMw3Gos
+ uwfp6jslBKXHidsA39CRktJ40EYqygmBgcxGTvHGC94VwSl7OfCjHsyfD/93L358
+ XsjpTHXBO/mOjQmJ2smhZx+q+iMLpJnq2QA8mGUI5uzPTjXD19sD9QdYdHF2p8D6
+ mdpVWED2gRf/sDoN+y3c/iZvMTN2HeDCx5d/wIgl3mmoHLvWRO8pNBV3EUg3ZBiv
+ fc0Y7m/0KOqW1itE4yg9IoPBWJg2jYSZTkRnQMPEkKEEHNtbx6dq5tLOYUIIwOwC
+ 5JlL76BRoaul6ousBSHV8OWCAvS2N8OC+l0ATzk99p/h4zY7PCG7NhkKAOgYfWFa
+ /z5u6J6TMrmeLZjknFXepuVAzNmDU0CmuhMwZankGKq6lmsQQnHvdq8+ExGGWhfK
+ m6I8nPvG654md9H7Y3HusHa6y1rkf9gZp1UFzhvXQgZdvc7K5pJrhxjGUnEg6sS0
+ m4daDRuNLW32PXiwoWTtTJfOQFv0t1f1eEKI9DO/O8/4fNtIvmI/8HDcdF1XzDnt
+ lGnyD9cZ5jKsKjGrT9DcvJhyTGWDFeBDTY+rlt52E8NbrzWUjX4J7Gyz8QRY9j7m
+ wRi4uaVt5KBmB8Ibo2bMTUXU3Db/0p8nCAg/89D1fP6FF4izg3GU4oD3vJyl81XS
+ XAH8tGT9wbjXuhomyhqemDYb0QdTRfpAznm4AS36qbeU/Tvj4M+Nm64qLpj7FFtK
+ aeDas4lzgeQf6/cdd5ItLlRHhlBOJEmjHVzRR4npabCWZojP8PTac1IlBgvS
+ =OH/y
-----END PGP MESSAGE-----
fp: 18DFCE01456DAB52EA38A6584EDC64F35FA1D6A5
- - created_at: "2026-05-23T20:58:22Z"
+ - created_at: "2026-05-25T17:17:14Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hF4DsZXvxFXTXoQSAQdA0rZTVdySF9nUiz7ZyFJgq1tojyLojGTgE4UIEJzFSTUw
- 9y4kbGn1cWMpAqr+sE3WHV9p7v6kgm/XdUjXGN4DadpUbiYx6sQW2Jov6Km2EYhq
- 0l4BawupjX25wi7c2yR5iGdxYS8oCYVmGgcAB3T96v8VsXpkAOYQAOOh7B9GQIxm
- hB3cFQLCy2un3VvBsiKGFMA2FhZYBOuaEwP/KmWnPv0IPIRH4by6LDB0xgq8MUNz
- =xoVE
+ hF4DsZXvxFXTXoQSAQdAIjnFVslIKlmP0X12z6AdWNqxkpVBDFvf03ToWQEQv3Uw
+ 8ka0OYl32rH6UiiSE1Vve1wZ/iVvK9/il6UhTpeAt8bIiCq6gEGR9Ba5NJnm6rSG
+ 0lwBwzEtaARPJbbcWu7Jl+dAQ0quP6uVS55OYBuSannlaPrQ5qBuS14AtuQ3UEVz
+ EbcLJ0b4lGL7hgyAf2E6nuDTkPGPChAJ5H5DfrB74ZB30GcYBTzwj13+jWx/VQ==
+ =Hxuh
-----END PGP MESSAGE-----
fp: 9633412309CCB83BFA39BA5F2FEF746201D7FCFE
- - created_at: "2026-05-23T20:58:22Z"
+ - created_at: "2026-05-25T17:17:14Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hF4DerEtaFuTeewSAQdAgcGcZ3BT6lsJ8FxkMghxg5/PZLtIzNeJaEUbxN0EFhsw
- uM+Lec3k9BJSUJK8GeVmesYxQh8vP6Yi/+m2LnGjHXzkQg8Bx1HJzuC/Ap36rC6N
- 0l4Bxj1URTsRD4yILEA3TY4Dn9St9uOtodJcf5YdAKvmeb3Uwy//huNnA1eK7b+v
- WRHcU2K+GgkSzLiRLZTc/nMrrCQ/P5HzwYHmP2rypFX7kxXlPd3K6yMZWTiSgYZd
- =gZLQ
+ hF4DerEtaFuTeewSAQdANsYlCeGhhqmBgnqcSuNdQBUwYKpucDrb6aR9Siyukjww
+ 72Gin/635k9bYXwknA1rPyTMvG00giQgjUr/QK6PSD/eGi0QOtMZLj1JRi8f5EU+
+ 0lwB+MIM9+EEzHJ96ouzL3bu0e++NvRY1Qjyx1Xi43bM96eBeLZ5DAc1eTSdWizQ
+ EWTorcmXffkdfOQx1zrlGZo/qvfj5F706VcwX4aZwok/ASRmSeCfEXLgGLCwqQ==
+ =ccBm
-----END PGP MESSAGE-----
fp: 057870A2C72CD82566A3EC983695F4FCBCAE4912
- - created_at: "2026-05-23T20:58:22Z"
+ - created_at: "2026-05-25T17:17:14Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hQIMAxjNhCKPP69fAQ//YGOLOFtORNbOu+KFCtGcJBXQMy6Ej3/tePVuDi2vmqLD
- 3Dz6stB9D+BmBbcgbFlDA+g7Vi6DD+zcze9wM10iuc9t9ucAuQ7B/ymSvJc4MrYn
- MJFvQv5IYgWJmzXLYEFYYpmZPGG3hSHSgWIPs+574wEA/L867ktguW6ZD3ZuMn3E
- yjCTeT/ZkGjuIpGqMu2/o9Wvc+RYgWlCB69D8kTHtnbFzbqEzvKU5/zte5ThchA+
- QZwFd/gk3o1G/7WOYJJ6CbBSOQaSrfm0mnb6sppNPdOAQtqHVSFVX5vX96gXsht/
- AkrvD6/2R5eNzbqRaU83cg7c5far49xoBbL6czreWY3D56yK4BJbrrg9mK7oCEfO
- GaRDFFD7R4LJPfVx2xDoIQ3Hyp4E3dz4nyJx0Kg7NSEt7soOb5MnZ+04LLAiHbaT
- qZr618V530uw3qaCsYcgHy+WsZXXlqXQey3A7jphi3u9Kvn9UjeegjNvpOrMk6g1
- RhGzv72G0wjZnzjTjPlzeROHaQ6RPgfpkZjEcVZNZkfAgAbB3XPgCFGKz4qvx9MP
- 4eHIlBSJizLzSi519o+0i5PwrZdEf9L4RUVxgQgdJXMh1JaydVh5DOU+xomdStD5
- Maymkt8fSgYgDaS953YA2e04PrkXCH0EHZ62T9EMxreEoU3nYTmw/TGx7RfU+wzS
- XgEuQkLWSToJ40/Ir3obDA246yv7J2FpmPwG4oFypkM5xe1WjlMlk90b9RBhUgXk
- ylRXXLBzau6mtbPOa7LGdVyVs2DClWQo9BoK+dxEsnW+TR144O4UmZEfifJXvgQ=
- =ympd
+ hQIMAxjNhCKPP69fAQ/+IRYUQhf7zzIZy3AKAtQgyMKRINOUUqOEv6IKmNQaaQP7
+ K5JXnVi2gjgBuG+2gH9iCEimIggnWxFhHerfOps+NkAI6y7kFz5hnMtOY2Qf3vxT
+ Hoyq4l6Yn+gG1HSLozVr9dTQPjyGOKJkm36ZKpM7gqSuLNP2ijKARzay4Chg3i+p
+ E1TVTVoEczrPdLg3O2fd5mi2UT1k3E4QREti0k6K4juMWqMz+5iJ5X98qCdmE1eX
+ L5dmW0QSUChzBVw+7NEcxeNx5WsbhWgPA5m2+bng3V8tHqAwrRUCoxn2+yabnsZB
+ Z0Z7TgcLk0Xnezw+BkT3bOsKgv+atE5lm2rBiRUHRDR3S04j0Ju6fJHf24CNy5ES
+ xMF7BE23SgmqUq0BrvdJB0ToNKYGMM0C5Xg4vGRiE61+18TiFIeC3mF9suvFFKc+
+ houq6Cy7q3O5PEqEbu6t5vXAZHwL9Th+ZatIIe9jSToiZiLEOIEmiYptR009/OWq
+ v6ADzaAE6+i6HZ62xBYQuZFkiUrRKxYzTHFn0A10QUJrJgbWr8QjS76oKi8feEDC
+ BJAOwE/0aK+l46hI6mlh6rgeSy8XdOPLEnL4+1HjlshhTTiW1rE2cr0ZiTTA6UFX
+ UhABIUi6jiLnM13L+auulU1UZQ8wxp73okrcuu6g2bPT/l7zO9YNOCocWVPQa5vS
+ XAH7qrW533ttg2XAczCdALMulV2N5GHl7TbgRQBkdoBAKL+6oKfxbOZeQM2nrfZT
+ arytZbnjgCcy5ygnjeziRvWwLk7sysEpAQqQNRm50m2Cq+2ccedRP6zFzUhc
+ =4hCA
-----END PGP MESSAGE-----
fp: F38C9D4228FC6F674E322D9C3326D914EB9B8F55
- - created_at: "2026-05-23T20:58:22Z"
+ - created_at: "2026-05-25T17:17:14Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hQIMA46L6MuPqfJqARAAshm2x7wX/9g3XJtSN0AnSeCwSHO1I4+ebLKOsB7zcXh8
- hrVO3694jQcU9L01H7jGYw4lNNzBd61/uVE5AvMq4Sqn9iH3MFNESbAEOWVV+TRf
- 53JMg9C/aZfde8gHgHPaiVXlCBVEVY9CqHpUXUKDmEE7iRb5P4DuMxOmybDYZGzY
- 4c5Ke1MFMkGRmAtsT1qLrT2vh+F0CX4JwpMkxCmOzSWAXbwrVOigJ35l5zM6vme4
- 5EQu9jI8FApTxVchZbr0v3UOKxp5OebqC0jGeznZNf4qb0qnsvuowY6IIw5Tl3/q
- H4TLq5EUOVqTC1voIWY/gMjieiW1gtr6vASy4MvbswsZLc26YVE9IbHzAOUWDN2o
- f2iQ3aZYuINvniD23XtM0TKepDXWq5eF+AJpmyP/LL8sYvSnWFD+muK3O657djEu
- yGZs2EFTrkiUvhBq3apOOYiU0eOi4Aq6UeEbOsLENnQrBRXuHEm4KUSwzOitVwJ1
- ByxQTu7wzY727SOR2hzjMC0LI602WGpEQU7ech5L4uWqtMFwaBP9HnUamcofKqqt
- 1vI2BevsJfQ0rtTE6GWseHt702lllTGe3RnHWc6YsMWLwUfRdBPggMW37hAPPcfO
- ytbU3RJIxx4vImRtXhkI5yvbpFQrooz1zSeXWaitPE5jmmiKe9IRStLnfiq9E2TS
- XgFVuQM8K0LgUYEoAipvafhnC3ohfGsM2AYd36EoaMNLeQ2ZZEiV06/Y3EWoI0iM
- aqRLwyBvTuDOc5BK32nCbAgUbbPJjPhqWaoNp5ymCBV76oW613gApkzoUF+OIUU=
- =KKaI
+ hQIMA46L6MuPqfJqAQ/9G5pRNmw775xCYA+foCx9rM7eLXJFl2DjaI3a/O0yVc6t
+ 32xtPuaHwTnP00Pbbo5Vc9QG7k0Fr3Rgy+ep1lGzeCMoHwF9xk98LspDtYZoKopE
+ 6/L6KLldSauRv0rPVhCQHpZFsnx1VxaJiXn9vAW17+imC9SgqLYGWyrxAtLCOOqH
+ N68RnTsEDquXixEs82ao0EmQXPquimJgSx+xVSF4yitYYLLLHyUL+drMNuVb9q9Y
+ oAIdEL1svDIieTbTKGQUqZ8Alf8f/0cqPWpEkDwYIyB/i9KDkH5Oj7uBBRtVLGxQ
+ VxE32wO1xpXvKgUY2PhWD2rOBVDG8dW/hyqvc1WgIeo1A6FTq34b5dGC2lmTRngB
+ 9mBjUd59zeOvdXLmoGwXgbjVhpgnm/5wlUeiIC3xR9MjW3znRBT6ujCaglpAdXBC
+ 0AIugssGcuXbP9Tj5zMVlbdi2dj6Ylc8S1Tj/OjwxHCCj6AWRqpxN5vY28RiLFGy
+ +eAsryzPk6UTCPIydiWwsrP+w8EhbllFxzZM+Sn+fshAHdRug+EeyT3h5V5JF+Ko
+ BZCrZkwYqAcVkJjEYlukjvxVFvo+T6tRMz4F4yNgjqFjneUaeLCc6RllaT696H0Y
+ 8+lw5rK+XpcXBZqso6vsLChRdZQJjoj9lkjRDbmhOkaRglikC6Cx+mpY1/XnGvDS
+ XAFWOuNKjN/xIRtaDc6tmeWsKkuqghjHiMeRqw10/kTBjniMLLJIN9ssj4HjYqC3
+ CsqyHqZmrbITUMr718gX1kkAvzF/fVAXT8YshOcK7rQbiMQJCZqeBp3fY7FC
+ =5yPR
-----END PGP MESSAGE-----
fp: 8996B62CBD159DCADD3B6DC08BB33A8ABCF7BC4A
- - created_at: "2026-05-23T20:58:22Z"
+ - created_at: "2026-05-25T17:17:14Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hF4DQrf1tCqiJxoSAQdA8YKD21h5POTLPf04KvGN93omFgkYO+Y8Kc0jM0vdqm8w
- 3zYRaLsDjdh8Zd89/HhHJUfLrTp/IJ0n81sK0ZjznbXKxgkseGthMzof+L7BnPAp
- 0l4BnAs9iZS4q2LZVS7ySBP89xLmF97qhK2jagMNSAwq8Afxbcw8oQAVQmeyYfxx
- X59irIHjI1ugO4o1WnTN67nTQjU5msbVBs0eALrw3jobzFHRL67fS0a4Soa59LTY
- =ZHIU
+ hF4DQrf1tCqiJxoSAQdAfLqKILCrCv2s2V7bLntk5lHI6Dc1FQlCg3LAefc8oTIw
+ a3UZU3OajQ1CCIhhu02JSlTKZm2z+pZKVHy+s5EgCqwAWTfPNAnyPT0ZGrhIdcah
+ 0lwBdg2Tq3+Nhix1ZuA/mUgcrbRBcFKlHY+IGEgOHKLJld9UPF2xEjTX6nmLyuTR
+ 6x+HW/7vVuc/jcFeQEmokhQw/SICVdyD7NQua4k1agLkty3hGcm1XCsfyKfj+w==
+ =Bxf9
-----END PGP MESSAGE-----
fp: B71138A6A8964A3C3B8899857B4F70C356765BAB
- - created_at: "2026-05-23T20:58:22Z"
+ - created_at: "2026-05-25T17:17:14Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hF4DzAGzViGx4qcSAQdAN7rRlv3dMoFOfj9eHgf+0H8521b32nWqySUdriEy6Tcw
- gjuReMBpKQOgUfuhIiWkHIKNtNgMrYWiC20ESOXX5b9uYZNpqHCgHQPlX0lEeGim
- 0lgBOieL7mSEq4wkWLCSv4sBAmkQA+dnugBeF+TrlqKQTZsbe/Z+jNG4ZrHRvdqi
- 4I5It+uaRV9Vrul1c6H7fNreRPUd4hNyJwU7gZQ+vU2WyAmgqerxE1Wb
- =gplT
+ hF4DzAGzViGx4qcSAQdAr2tfPiCpUkxFj4rgSiLf7y4iyKbsgEY87iYH3GAZTVcw
+ vK2YpjSVgFRoJNx9s3bFr+9UG0LFmKvDZEP83ThQizYs2I/N7MSU8ERRImshaQMH
+ 0lYB4At0RHC1mp8eKqhRgXenOtpfCiBACtlIdS9m1aqcU6i9Drgt86Bk/LC/HSvJ
+ MUOit2PP7QZVRWV6F8wAHlUFd6bdTKv9eOCZLSB6mY6DQmkp93FIMg==
+ =lQcB
-----END PGP MESSAGE-----
fp: D2E9C0807BF681F5E164DAFC5EE1B61CD90954CD
- - created_at: "2026-05-23T20:58:22Z"
+ - created_at: "2026-05-25T17:17:14Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hQIMA2pVdGTIrZI+ARAAjWK8mU99VcnM/Ckzm+YsZFTwnz4PDAenDDdZ1OOz5IXe
- tS4SQPcQlSSOuXEkFLJMmm8QVxtUC3Gh4nF7o+7OygT+0ZXOrB7jFgg10+v/KVA9
- hSlqBdsMxcC0OzBtkGyAOXOxqnTVubuHEGyGpIryHt1/lthUUZHBbjgw7P0Tw2/U
- sYK5j5YbqhyBl20gyZorkTTq7pHfVXDVtpe75+ZkqbOg4S6HgW3/dl+v6N0TLfRs
- GVl0fUlWIK/akGCB71zdwJs2I1qTeMTlL6v+XSUdXj0YV+5fjh3wf8qzN9geIjQK
- ybxGFWDKCAgTMnqoFF5BCL23hFtnCbTtLN1wQT7/m7zpjaBKHOBXZOGXYZCMGZui
- sBsUvPANgNdfOse9H2aABQvUQh8WqFw8S73GasvrZHAwEmvnXzocMJd+kUovzmQu
- 9FBk5UkcgXfmxeamoP8C700vh4zI+sKz6uEW0+AuVtLlLVqlb2w21kTc+ArZW52n
- HLolH5q3Wj6pKuuFCWKr6UgLFcq2w4QngB2p+UABHU3RbwXIra7prDXCUcNC5iCn
- ElRFY7OZ3nbHOf9oaW/MitcfszVLyl0ueoay6qxdlIGdXKRGpqxHqqr+92INV/iz
- 6CRoAsTqVq1a7ZuAaUdJPvfKVAHHEHjPwlrOc9cXvykG0iQKsRzgqiOtPiGQShnU
- aAEJAhDSqCwywHDnQ7X9ZWIzPjwvqyHpEVez8zYh3vpgKpsLb9uL+JizZjV02HMe
- nhiL+4o/aNjJgGJWph1uPFhU4wO4AavnNBsHbJSiL/1yTS96hdf8d+gB41yVLU3e
- kBkDFLKkIBkU
- =aRLd
+ hQIMA2pVdGTIrZI+ARAAjNHCArTtU9D8zw5yJzvf0KSwQoOaQWHui7AqQkvQ8mJv
+ 8+Vo9sb+JoSuFHQqqDbOU+VFpmc9CZ6HCJaWqO2gZVgjxrsrPgyfq795LBd6GhX5
+ 6zwUH2huxv+n7XkfjN4HHJAlSj0pRyL3fyojdOdtXCTuBGbofLIBJUbuD1wro1K+
+ nSHLvdBEitn8afKt5/SaatB8Prwyet6E6J4HluXFQjl+KdrRHHvXImmhNSR4yfIr
+ yQt2s8qapSvLhrUw9/GFXqM/jg4ZlDhPUhCAKI2Pr5PbsRMBqwdkSrDeB7MHdsU6
+ tI4uyb7j8m3VMbFKNVpuluwgk47V+W/h+jtZetSR6ewYsXJjgHNmX6JX73XzR7R+
+ q4EBfSAxR7ByZ/HHuumUH6BKBj8IcNJQwtEkLIZmLZ3OdFtJP3YY0esV+gEhG6K7
+ m2Zl9C7axuYmvoLrqygaChmxMhMiebTPNkD/dH5Ircwl2cXfHC+bvF2WO73DTk9G
+ emHzrkniEtuUs+svMhT3NKM3/mpOJTiNezdH39HZADzkBwZ5Mmkfe4mbXByfRN7F
+ AEJWmnOcpXwXE9//sRbkRr+CGmB86raZE22wHPuk6U9IyVFJm8hJbOzFc7rwu1Eo
+ 0YWBCsc9dA+jH8hIKrIfXwqnfhYjTrX+oZJeK/8McOwfF7I2G9YrPAgwbokQmtLU
+ ZgEJAhC8ryOvXwp2kP9sv6nbXIEcwrX8lRjkEWduf6ZAWAfQ5FGBSPzR8WnZWGzN
+ PCxjg7utA9AHBChF1duwOV2Qr5XW8HTUGAx4fc0T0rjC862vSwf8yAY89WWJyUfk
+ n8qhhdw1uw==
+ =KgOe
-----END PGP MESSAGE-----
fp: 878FEA3CB6A6F6E7CD80ECBE28506E3585F9F533
- - created_at: "2026-05-23T20:58:22Z"
+ - created_at: "2026-05-25T17:17:14Z"
enc: |-
-----BEGIN PGP MESSAGE-----
- hF4DKKbvh61jX5USAQdABId/P8ozRgJ4ItF1zvxp98aH+g3LZ6UGnxjYjtDxjEIw
- VmyerznjOLnpz0EobXRRoot1Lo82Va64HQmXt26LG3gFY1HVp0WOnIZXa/CUoUb8
- 1GgBCQIQloFxKcgFTiRidaJfN7hSeQLleiEe3aifZUyJj8niTmBaY29t+CSoA46N
- xZzX1AlxVjfmputhYdTyOYSJtGrj7otmnUN2P+55pjz4L2qCYAEKi1+ibqgpmJh/
- bETQsT6WKJ8FXA==
- =Ci7L
+ hF4DKKbvh61jX5USAQdAYrtySnoCK7k4ZZIyllSAr23fozsiZb9Nf6Q+r56i3lAw
+ 7IxBdJc2ipMxafy1Ntq0wfAYYk7nY6Vz1XtB+ekVeYLOjDmHRnJWq/Jw0K8wLvWT
+ 1GYBCQIQ/0zDLdFOrMNjVPMutGVJOkpm7mbD30GpgRugzEf2NZePGtptqnP6i1t1
+ izBqFRByftV1MUw1uWgTFgB8zEVDh6gG0QAYeRuu3NS9QhwR71Wlu2J4eu+VhZi7
+ AKabk3T3Z00=
+ =A2ad
-----END PGP MESSAGE-----
fp: 41FFAF3D519CF5C039FBD8414BCC213729AF0E49
unencrypted_suffix: _unencrypted
diff --git a/inventories/z9/hosts.yaml b/inventories/z9/hosts.yaml
index 90f2efd..740c7ba 100644
--- a/inventories/z9/hosts.yaml
+++ b/inventories/z9/hosts.yaml
@@ -74,6 +74,7 @@ ansible_pull_hosts:
light:
waybackproxy:
yate:
+ z9-router:
secrets_hosts:
hosts:
z9-router:
From 0fef65b2c291d52bd124a8a73c125d9438a707fd Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Mon, 25 May 2026 19:50:01 +0200
Subject: [PATCH 06/14] z9-router(host): fix some spelling and a wireguard peer
address
---
resources/z9/z9-router/nftables/nftables.conf | 4 ++--
resources/z9/z9-router/systemd_networkd/10-wg55.netdev | 4 ++--
2 files changed, 4 insertions(+), 4 deletions(-)
diff --git a/resources/z9/z9-router/nftables/nftables.conf b/resources/z9/z9-router/nftables/nftables.conf
index 842ca04..f639689 100644
--- a/resources/z9/z9-router/nftables/nftables.conf
+++ b/resources/z9/z9-router/nftables/nftables.conf
@@ -108,7 +108,7 @@ table inet forward {
meta nfproto ipv4 oifname $v4_exposed_ifs accept comment "allow v4 exposed network access"
meta nfproto ipv6 oifname $v6_exposed_ifs accept comment "allow v6 exposed network access"
- # Allow clients and managment to most
- iifname { $if_netlan_51_clients, $if_netlan_54_management, $if_wg55_management } oifname $lan_ifs accept comment "allow clients and managment to lan_ifs"
+ # Allow clients and management to most
+ iifname { $if_netlan_51_clients, $if_netlan_54_management, $if_wg55_management } oifname $lan_ifs accept comment "Allow clients and management to lan interfaces"
}
}
diff --git a/resources/z9/z9-router/systemd_networkd/10-wg55.netdev b/resources/z9/z9-router/systemd_networkd/10-wg55.netdev
index b3e41a6..f2de509 100644
--- a/resources/z9/z9-router/systemd_networkd/10-wg55.netdev
+++ b/resources/z9/z9-router/systemd_networkd/10-wg55.netdev
@@ -5,7 +5,7 @@ Name=wg55
[WireGuard]
ListenPort=51820
-PrivateKeyFile=/etc/ansible_secrets/wireguard_wg55_privat_key
+PrivateKeyFile=/etc/ansible_secrets/wireguard_wg55_private_key
# WireGuard Peers
@@ -75,7 +75,7 @@ PresharedKeyFile = /etc/ansible_secrets/wireguard_wg55_peer_langoor_home_psk
[WireGuardPeer]
# friendly_name = lilly-lillysLaptop
-AllowedIPs = 10.89.214.16/32 #,2a07:c481:1:37::/128
+AllowedIPs = 10.89.214.16/32,2a07:c481:1:37::16/128
PublicKey = IBsI+N8qUNpQnDc5HnqQ2Zo/1graFM0RMIecHmAF+Vk=
[WireGuardPeer]
From 9bff86df7fbe4ae1d2c1ade9f07a78a0bf0fc132 Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Mon, 25 May 2026 20:13:29 +0200
Subject: [PATCH 07/14] kea_dhcp(role): some fixes and removing arch part
- remove tags from tasks
- remove archlinux part
- use debian default package for kea
---
roles/kea_dhcp/defaults/main.yaml | 1 -
roles/kea_dhcp/handlers/main.yml | 6 +--
roles/kea_dhcp/meta/argument_specs.yaml | 4 +-
roles/kea_dhcp/tasks/install_archlinux.yml | 8 ----
roles/kea_dhcp/tasks/install_debian.yml | 39 +++++++++---------
roles/kea_dhcp/tasks/kea.yaml | 10 ++---
roles/kea_dhcp/tasks/main.yml | 6 ---
roles/kea_dhcp/tasks/stork-agent.yaml | 47 +++-------------------
8 files changed, 34 insertions(+), 87 deletions(-)
delete mode 100644 roles/kea_dhcp/tasks/install_archlinux.yml
diff --git a/roles/kea_dhcp/defaults/main.yaml b/roles/kea_dhcp/defaults/main.yaml
index 409f0a1..dc6453a 100644
--- a/roles/kea_dhcp/defaults/main.yaml
+++ b/roles/kea_dhcp/defaults/main.yaml
@@ -1,7 +1,6 @@
kea_dhcp__stork_agent:
enable: false
prometheus_only: true
-kea_dhcp__version_repo: "kea-3-0"
kea_dhcp__dns_servers:
v6:
- "2a07:c481:0:4::2"
diff --git a/roles/kea_dhcp/handlers/main.yml b/roles/kea_dhcp/handlers/main.yml
index 5b44d6e..d06aa1c 100644
--- a/roles/kea_dhcp/handlers/main.yml
+++ b/roles/kea_dhcp/handlers/main.yml
@@ -4,19 +4,19 @@
ansible.builtin.systemd_service:
daemon_reload: true
-- name: Kea_dhcp4.reloaded
+- name: Kea_dhcp4.restarted
ansible.builtin.service:
name: kea-dhcp4
state: restarted
enabled: true
-- name: Kea_dhcp6.reloaded
+- name: Kea_dhcp6.restarted
ansible.builtin.service:
name: kea-dhcp6
state: restarted
enabled: true
-- name: Kea_ctrl.reloaded
+- name: Kea_ctrl.restarted
ansible.builtin.systemd:
name: kea-ctrl-agent
state: restarted
diff --git a/roles/kea_dhcp/meta/argument_specs.yaml b/roles/kea_dhcp/meta/argument_specs.yaml
index 995b838..4d0d594 100644
--- a/roles/kea_dhcp/meta/argument_specs.yaml
+++ b/roles/kea_dhcp/meta/argument_specs.yaml
@@ -37,7 +37,7 @@ argument_specs:
interfaces:
type: "list"
elements: "str"
- default: []
+ default: [ ]
control-sockets:
type: "list"
elements: "dict"
@@ -85,7 +85,7 @@ argument_specs:
interfaces:
type: "list"
elements: "str"
- default: []
+ default: [ ]
control-sockets:
type: "list"
elements: "dict"
diff --git a/roles/kea_dhcp/tasks/install_archlinux.yml b/roles/kea_dhcp/tasks/install_archlinux.yml
deleted file mode 100644
index 7bdb140..0000000
--- a/roles/kea_dhcp/tasks/install_archlinux.yml
+++ /dev/null
@@ -1,8 +0,0 @@
----
-- name: Install Kea on Archlinux
- when: ansible_facts['distribution'] == "Archlinux"
- become: true
- community.general.pacman:
- name: kea
- state: present
- update_cache: false
diff --git a/roles/kea_dhcp/tasks/install_debian.yml b/roles/kea_dhcp/tasks/install_debian.yml
index 2ac2346..f897ddb 100644
--- a/roles/kea_dhcp/tasks/install_debian.yml
+++ b/roles/kea_dhcp/tasks/install_debian.yml
@@ -1,22 +1,25 @@
---
-- name: Register isc-kea apt repository
- become: true
- register: kea_dhcp_repo
- when: ansible_facts['distribution'] == "Debian"
- ansible.builtin.deb822_repository:
- name: "isc-{{ kea_dhcp__version_repo }}"
- uris: "https://dl.cloudsmith.io/public/isc/{{ kea_dhcp__version_repo }}/deb/debian"
- suites: any-version
- components: main
- signed_by: "https://dl.cloudsmith.io/public/isc/{{ kea_dhcp__version_repo }}/gpg.key"
-
- name: Install Kea packages
become: true
when: ansible_facts['distribution'] == "Debian"
- ansible.builtin.apt:
- name:
- - isc-kea-dhcp4
- - isc-kea-dhcp6
- - isc-kea-ctrl-agent
- - isc-kea-admin
- update_cache: "{{ kea_dhcp_install_repo.changed }}"
+ block:
+ - name: Install Kea dhcp4
+ when: kea_dhcp__dhcp4.enable
+ ansible.builtin.apt:
+ name:
+ - isc-kea-dhcp4
+ - name: Install Kea dhcp6
+ when: kea_dhcp__dhcp6.enable
+ ansible.builtin.apt:
+ name:
+ - isc-kea-dhcp6
+ - name: Install Kea ctrl agent
+ when: kea_dhcp__stork_agent.enable
+ ansible.builtin.apt:
+ name:
+ - isc-kea-ctrl-agent
+ - name: Install Kea admin
+ when: kea_dhcp__stork_agent.enable
+ ansible.builtin.apt:
+ name:
+ - isc-kea-admin
diff --git a/roles/kea_dhcp/tasks/kea.yaml b/roles/kea_dhcp/tasks/kea.yaml
index a4fd3b5..116c7dd 100644
--- a/roles/kea_dhcp/tasks/kea.yaml
+++ b/roles/kea_dhcp/tasks/kea.yaml
@@ -1,12 +1,10 @@
---
- name: Include config vars
- tags: [ kea, include_vars ]
when: kea_dhcp__include_vars is not None
ansible.builtin.include_vars:
file: "{{ kea_dhcp__include_vars }}"
- name: Deploy kea-dhcp4 configuration file
- tags: [ kea, dhcp4 ]
become: true
when: kea_dhcp__dhcp4.enable
ansible.builtin.template:
@@ -18,10 +16,9 @@
mode: "u=rw,g=r,o="
validate: kea-dhcp4 -T %s
notify:
- - Kea_dhcp4.reloaded
+ - Kea_dhcp4.restarted
- name: Deploy kea-dhcp6 configuration file
- tags: [ kea, dhcp6 ]
become: true
when: kea_dhcp__dhcp6.enable
ansible.builtin.template:
@@ -33,10 +30,9 @@
mode: "u=rw,g=r,o="
validate: kea-dhcp6 -T %s
notify:
- - Kea_dhcp6.reloaded
+ - Kea_dhcp6.restarted
- name: Copy kea-ctrl-agent configuration file
- tags: [ kea, ctrl-agent ]
become: true
when: kea_dhcp__stork_agent.enable
ansible.builtin.template:
@@ -47,5 +43,5 @@
mode: "u=rw,g=r,o="
validate: kea-ctrl-agent -t %s
notify:
- - Kea_ctrl.reloaded
+ - Kea_ctrl.restarted
- Stork_agent.restarted
diff --git a/roles/kea_dhcp/tasks/main.yml b/roles/kea_dhcp/tasks/main.yml
index a3478fa..6fced08 100644
--- a/roles/kea_dhcp/tasks/main.yml
+++ b/roles/kea_dhcp/tasks/main.yml
@@ -1,11 +1,6 @@
---
- name: Setup Kea DHCP
- tags: [kea, dhcp]
block:
- - name: Install Kea on Archlinux
- when: ansible_facts['distribution'] == "Archlinux"
- ansible.builtin.import_tasks: install_archlinux.yml
-
- name: Install Kea on Debian
when: ansible_facts['distribution'] == "Debian"
ansible.builtin.import_tasks: install_debian.yml
@@ -14,6 +9,5 @@
ansible.builtin.include_tasks: kea.yaml
- name: Run stork-agent tasks
- tags: [stork-agent, monitoring]
when: kea_dhcp__stork_agent.enable
ansible.builtin.include_tasks: stork-agent.yaml
diff --git a/roles/kea_dhcp/tasks/stork-agent.yaml b/roles/kea_dhcp/tasks/stork-agent.yaml
index 916760c..0e777d4 100644
--- a/roles/kea_dhcp/tasks/stork-agent.yaml
+++ b/roles/kea_dhcp/tasks/stork-agent.yaml
@@ -1,55 +1,18 @@
---
- name: Install stork-agent
- tags: [stork-agent]
block:
- - name: Install stork-agent on Archlinux
- when: ansible_facts['distribution'] == "Archlinux"
- tags: [stork-agent, archlinux]
- block:
- - name: Create stork-agent user
- ansible.builtin.user:
- name: stork-agent
- create_home: false
- home: "/var/lib/stork-agent"
- shell: "/usr/bin/nologin"
- system: true
- groups: ["kea"]
- append: true
-
- - name: Install stork-agent with aur_pkg_install
- ansible.builtin.include_role:
- name: aur_pkg_install
- vars:
- aur_pkg_install__pkg_name: "stork-agent"
- aur_pkg_install__git_clone_url: "https://ansible:{{ secret__ansible_git_token }}@git.fux-eg.net/aur-mirror/stork-agent.git"
- aur_pkg_install__git_ref: "bf96e34"
-
- - name: Install stork-agent on Debian
+ - name: Install isc-stork-agent
when: ansible_facts['distribution'] == "Debian"
- tags: [stork-agent, debian]
- block:
- - name: Register isc-stork apt repository
- become: true
- register: "kea_dhcp_install_repo"
- ansible.builtin.deb822_repository:
- name: isc-stork
- uris: https://dl.cloudsmith.io/public/isc/stork/deb/debian
- suites: any-version
- components: main
- signed_by: https://dl.cloudsmith.io/public/isc/stork/gpg.key
-
- - name: Install isc-stork-agent
- become: true
- ansible.builtin.apt:
- name: isc-stork-agent
- update_cache: "{{ kea_dhcp_install_repo.changed }}"
+ become: true
+ ansible.builtin.apt:
+ name: isc-stork-agent
- name: Add stork-agent user to _kea group on Debian
when: ansible_facts['distribution'] == "Debian"
become: true
ansible.builtin.user:
name: stork-agent
- groups: ["_kea"]
+ groups: [ "_kea" ]
append: true
- name: Config for stork-agent
From 2798e9e01c7ae58938ae9601ffeadddd60a0b4d2 Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Mon, 25 May 2026 21:18:56 +0200
Subject: [PATCH 08/14] kea_dhcp(role): add README.md
---
roles/kea_dhcp/README.md | 102 +++++++++++++++++++++++++++++++++++++++
1 file changed, 102 insertions(+)
create mode 100644 roles/kea_dhcp/README.md
diff --git a/roles/kea_dhcp/README.md b/roles/kea_dhcp/README.md
new file mode 100644
index 0000000..4071943
--- /dev/null
+++ b/roles/kea_dhcp/README.md
@@ -0,0 +1,102 @@
+# Role `kea_dhcp`
+
+Install and manage kea dhcp.
+
+## Supported Distributions
+
+Should work on Debian-based distributions.
+
+## Required Arguments
+
+None.
+
+## Optional Arguments
+
+- `kea_dhcp__stork_agent.enable`: Enable Kea DHCP stork agent.
+ Defaults to `false`.
+- `kea_dhcp__stork_agent.prometheus_only`: Only enable the prometheus endpoint in stork agent.
+ Defaults to `true`.
+- `kea_dhcp__dns_servers.v4`: List of IPv4 DNS Servers in DHCP response.
+ Defaults to FUX DNS Servers.
+- `kea_dhcp__dns_servers.v6`: List of IPv6 DNS Servers in DHCP response.
+ Defaults to FUX DNS Servers.
+- `kea_dhcp__include_vars`: Path to YAML File to separately load VARs for Kea config templating.
+- `kea_dhcp__dhcp4.enable`: Enable Kea DHCP4 Service.
+ Defaults to `false`.
+- `kea_dhcp__dhcp4.interfaces`: List of interfaces the DHCP4 Server should listen to and serve.
+ Defaults to the empty list (`[ ]`).
+- `kea_dhcp__dhcp4.control-sockets`: List of Kea DHCP4 control sockets.
+ Defaults to the list with one entry (see below).
+- `kea_dhcp__dhcp4.control-sockets.*.socket-name`: Control socket name.
+ Defaults to `kea_dhcp__dhcp4.control-sockets.0.socket-name: /var/run/kea-dhcp4-ctrl-agent.sock`.
+- `kea_dhcp__dhcp4.control-sockets.*.socket-type`: Control socket type.
+ Defaults to `kea_dhcp__dhcp4.control-sockets.0.socket-type: unix`.
+- `kea_dhcp__dhcp4.lease-database.type`: Type of lease database.
+ Defaults to `memfile`.
+- `kea_dhcp__dhcp4.lease-database.persist`: Persist the lease database.
+ Defaults to `true`.
+- `kea_dhcp__dhcp4.option-data`: List of DHCP4 Options.
+ Defaults to a list with one entry (see below).
+- `kea_dhcp__dhcp4.option-data.*.name`: Name of DHCP4 Option.
+ Defaults to `kea_dhcp__dhcp4.option-data.0.name: "domain-name-servers"`.
+- `kea_dhcp__dhcp4.option-data.*.code`: DHCP4 Option code.
+ Defaults to `kea_dhcp__dhcp4.option-data.0.code: 6`.
+- `kea_dhcp__dhcp4.option-data.*.csv-format`: DHCP4 Option as csv format.
+ Defaults to `kea_dhcp__dhcp4.option-data.0.csv-format: true`.
+- `kea_dhcp__dhcp4.option-data.*.data`: DHCP4 Option data.
+ Defaults to `kea_dhcp__dhcp4.option-data.0.data: "{{ kea_dhcp__dns_servers.v4 | join(',') }}"`.
+- `kea_dhcp__dhcp4.subnets`: List of subnets the DHCP4 server should manage.
+ Defaults to the empty list (`[ ]`).
+- `kea_dhcp__dhcp4.subnets.*.id`: ID of interface (starts with 1).
+- `kea_dhcp__dhcp4.subnets.*.subnet`: Subnet on interface.
+- `kea_dhcp__dhcp4.subnets.*.pools`: List of DHCP pools in subnet.
+- `kea_dhcp__dhcp4.subnets.*.pools.*.pool`: DHCP pool in range format.
+- `kea_dhcp__dhcp4.subnets.*.reservations`: List of DHCP lease reservations.
+- `kea_dhcp__dhcp4.subnets.*.reservations.*.ip-address`: IP address of reservation.
+- `kea_dhcp__dhcp4.subnets.*.reservations.*.hostname`: Hostname of reservation.
+- `kea_dhcp__dhcp4.subnets.*.reservations.*.hw-address`: Hardware address of reservation.
+- `kea_dhcp__dhcp4.subnets.*.option-data`: List of DHCP lease reservations.
+- `kea_dhcp__dhcp4.subnets.*.option-data.*.name`: Name of DHCP4 Option.
+- `kea_dhcp__dhcp4.subnets.*.option-data.*.code`: DHCP4 Option code.
+- `kea_dhcp__dhcp4.subnets.*.option-data.*.csv-format`: DHCP4 Option as csv format.
+- `kea_dhcp__dhcp4.subnets.*.option-data.*.data`: DHCP4 Option data.
+- `kea_dhcp__dhcp6.enable`: Enable Kea DHCP6 Service.
+ Defaults to `false`.
+- `kea_dhcp__dhcp6.interfaces`: List of interfaces the DHCP6 Server should listen to and serve.
+ Defaults to the empty list (`[ ]`).
+- `kea_dhcp__dhcp6.control-sockets`: List of Kea DHCP6 control sockets.
+ Defaults to the list with one entry (see below).
+- `kea_dhcp__dhcp6.control-sockets.*.socket-name`: Control socket name.
+ Defaults to `kea_dhcp__dhcp6.control-sockets.0.socket-name: /var/run/kea-dhcp6-ctrl-agent.sock`.
+- `kea_dhcp__dhcp6.control-sockets.*.socket-type`: Control socket type.
+ Defaults to `kea_dhcp__dhcp6.control-sockets.0.socket-type: unix`.
+- `kea_dhcp__dhcp6.lease-database.type`: Type of lease database.
+ Defaults to `memfile`.
+- `kea_dhcp__dhcp6.lease-database.persist`: Persist the lease database.
+ Defaults to `true`.
+- `kea_dhcp__dhcp6.option-data`: List of DHCP6 Options.
+ Defaults to a list with one entry (see below).
+- `kea_dhcp__dhcp6.option-data.*.name`: Name of DHCP6 Option.
+ Defaults to `kea_dhcp__dhcp6.option-data.0.name: "domain-name-servers"`.
+- `kea_dhcp__dhcp6.option-data.*.code`: DHCP6 Option code.
+ Defaults to `kea_dhcp__dhcp6.option-data.0.code: 6`.
+- `kea_dhcp__dhcp6.option-data.*.csv-format`: DHCP6 Option as csv format.
+ Defaults to `kea_dhcp__dhcp6.option-data.0.csv-format: true`.
+- `kea_dhcp__dhcp6.option-data.*.data`: DHCP6 Option data.
+ Defaults to `kea_dhcp__dhcp6.option-data.0.data: "{{ kea_dhcp__dns_servers.v6 | join(',') }}"`.
+- `kea_dhcp__dhcp6.subnets`: List of subnets the DHCP6 server should manage.
+ Defaults to the empty list (`[ ]`).
+- `kea_dhcp__dhcp6.subnets.*.id`: ID of interface (starts with 1).
+- `kea_dhcp__dhcp6.subnets.*.subnet`: Subnet on interface.
+- `kea_dhcp__dhcp6.subnets.*.pools`: List of DHCP pools in subnet.
+- `kea_dhcp__dhcp6.subnets.*.pools.*.pool`: DHCP pool in range format.
+- `kea_dhcp__dhcp6.subnets.*.reservations`: List of DHCP lease reservations.
+- `kea_dhcp__dhcp6.subnets.*.reservations.*.ip-address`: IP address of reservation.
+- `kea_dhcp__dhcp6.subnets.*.reservations.*.hostname`: Hostname of reservation.
+- `kea_dhcp__dhcp6.subnets.*.reservations.*.hw-address`: Hardware address of reservation.
+- `kea_dhcp__dhcp6.subnets.*.option-data`: List of DHCP lease reservations.
+- `kea_dhcp__dhcp6.subnets.*.option-data.*.name`: Name of DHCP6 Option.
+- `kea_dhcp__dhcp6.subnets.*.option-data.*.code`: DHCP6 Option code.
+- `kea_dhcp__dhcp6.subnets.*.option-data.*.csv-format`: DHCP6 Option as csv format.
+- `kea_dhcp__dhcp6.subnets.*.option-data.*.data`: DHCP6 Option data.
+
From 09a4869ac11feeb31a97aae61e13f83479757849 Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Mon, 25 May 2026 21:27:25 +0200
Subject: [PATCH 09/14] kea_dhcp(role): fix indentation in template
---
roles/kea_dhcp/templates/kea-dhcp4.conf.jinja | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/roles/kea_dhcp/templates/kea-dhcp4.conf.jinja b/roles/kea_dhcp/templates/kea-dhcp4.conf.jinja
index 78f06ae..fa7cfd5 100644
--- a/roles/kea_dhcp/templates/kea-dhcp4.conf.jinja
+++ b/roles/kea_dhcp/templates/kea-dhcp4.conf.jinja
@@ -3,12 +3,12 @@
"interfaces-config": {
"interfaces": {{ kea_dhcp__dhcp4.interfaces | to_nice_json }}
},
- "control-sockets": {{ kea_dhcp__dhcp4['control-sockets'] | to_nice_json }},
- "lease-database": {{ kea_dhcp__dhcp4['lease-database'] | to_nice_json }},
- {% if kea_dhcp__dhcp4['option-data'] is defined and kea_dhcp__dhcp4['option-data'] %}
- "option-data": {{ kea_dhcp__dhcp4['option-data'] | to_nice_json }},
- {% endif %}
- "subnet4": [
+ "control-sockets": {{ kea_dhcp__dhcp4['control-sockets'] | to_nice_json }},
+ "lease-database": {{ kea_dhcp__dhcp4['lease-database'] | to_nice_json }},
+ {% if kea_dhcp__dhcp4['option-data'] is defined and kea_dhcp__dhcp4['option-data'] %}
+ "option-data": {{ kea_dhcp__dhcp4['option-data'] | to_nice_json }},
+ {% endif %}
+ "subnet4": [
{% for subnet in kea_dhcp__dhcp4.subnets %}
{
"id": {{ subnet.id }},
From a19262eae0476a3c7bca25a644f25dc597d7bacb Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Tue, 26 May 2026 08:37:40 +0200
Subject: [PATCH 10/14] kea_dhcp(role): make stork-agent.env smaller and add
link to documentation
---
roles/kea_dhcp/README.md | 2 +-
.../kea_dhcp/templates/stork-agent.env.jinja | 30 ++-----------------
2 files changed, 4 insertions(+), 28 deletions(-)
diff --git a/roles/kea_dhcp/README.md b/roles/kea_dhcp/README.md
index 4071943..9938cf9 100644
--- a/roles/kea_dhcp/README.md
+++ b/roles/kea_dhcp/README.md
@@ -1,6 +1,6 @@
# Role `kea_dhcp`
-Install and manage kea dhcp.
+Install and manage Kea DHCP and [Stork Agent](https://stork.readthedocs.io/en/latest/man/stork-agent.8.html).
## Supported Distributions
diff --git a/roles/kea_dhcp/templates/stork-agent.env.jinja b/roles/kea_dhcp/templates/stork-agent.env.jinja
index bdfa4d2..75250b0 100644
--- a/roles/kea_dhcp/templates/stork-agent.env.jinja
+++ b/roles/kea_dhcp/templates/stork-agent.env.jinja
@@ -1,11 +1,6 @@
-### the IP or hostname to listen on for incoming Stork server connections
-# STORK_AGENT_HOST=
+### Stork Agent env file
+### (created and managed by ansible kea_dhcp role)
-### the TCP port to listen on for incoming Stork server connections
-# STORK_AGENT_PORT=8081
-
-### listen for commands from the Stork server only, but not for Prometheus requests
-# STORK_AGENT_LISTEN_STORK_ONLY=true
{% if kea_dhcp__stork_agent.prometheus_only %}
### listen for Prometheus requests only, but not for commands from the Stork server
@@ -14,31 +9,12 @@ STORK_AGENT_LISTEN_PROMETHEUS_ONLY=true
### settings for exporting stats to Prometheus
### the IP or hostname on which the agent exports Kea statistics to Prometheus
-# STORK_AGENT_PROMETHEUS_KEA_EXPORTER_ADDRESS=
+STORK_AGENT_PROMETHEUS_KEA_EXPORTER_ADDRESS=localhost
### the port on which the agent exports Kea statistics to Prometheus
# STORK_AGENT_PROMETHEUS_KEA_EXPORTER_PORT=
-## enable or disable collecting per-subnet stats from Kea
-# STORK_AGENT_PROMETHEUS_KEA_EXPORTER_PER_SUBNET_STATS=true
-### the IP or hostname on which the agent exports BIND 9 statistics to Prometheus
-# STORK_AGENT_PROMETHEUS_BIND9_EXPORTER_ADDRESS=
-### the port on which the agent exports BIND 9 statistics to Prometheus
-# STORK_AGENT_PROMETHEUS_BIND9_EXPORTER_PORT=
-
-### Stork Server URL used by the agent to send REST commands to the server during agent registration
-# STORK_AGENT_SERVER_URL=
-
-### skip TLS certificate verification when the Stork Agent connects
-### to Kea over TLS and Kea uses self-signed certificates
-# STORK_AGENT_SKIP_TLS_CERT_VERIFICATION=true
-
### Logging parameters
### Set logging level. Supported values are: DEBUG, INFO, WARN, ERROR
STORK_LOG_LEVEL=DEBUG
-### disable output colorization
-# CLICOLOR=false
-
-### path to the hook directory
-# STORK_AGENT_HOOK_DIRECTORY=
From 0a74ac02c21d35bc58a0d9bc48c54efcc08133fe Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Tue, 26 May 2026 10:06:52 +0200
Subject: [PATCH 11/14] unbound(role): use existing
deploy_systemd_resolved_config role and some reordering
---
inventories/z9/hosts.yaml | 3 +++
roles/unbound/handlers/main.yml | 7 ------
roles/unbound/tasks/main.yml | 24 +++----------------
roles/unbound/tasks/prometheus-exporter.yml | 8 ++++++-
.../vars/deploy_systemd_resolved_config.yaml | 9 +++++++
5 files changed, 22 insertions(+), 29 deletions(-)
create mode 100644 roles/unbound/vars/deploy_systemd_resolved_config.yaml
diff --git a/inventories/z9/hosts.yaml b/inventories/z9/hosts.yaml
index 740c7ba..39fa97b 100644
--- a/inventories/z9/hosts.yaml
+++ b/inventories/z9/hosts.yaml
@@ -17,6 +17,9 @@ all:
z9-router:
ansible_host: z9-router.ccchh.net
ansible_user: chaos
+base_config_hosts:
+ hosts:
+ z9-router:
certbot_hosts:
hosts:
dooris:
diff --git a/roles/unbound/handlers/main.yml b/roles/unbound/handlers/main.yml
index e1345bf..222e8c5 100644
--- a/roles/unbound/handlers/main.yml
+++ b/roles/unbound/handlers/main.yml
@@ -18,10 +18,3 @@
name: prometheus-unbound-exporter.service
state: restarted
enabled: true
-
-- name: prometheus-unbound-exporter.enabled
- become: true
- ansible.builtin.systemd:
- name: prometheus-unbound-exporter.service
- enabled: true
- daemon_reload: true
diff --git a/roles/unbound/tasks/main.yml b/roles/unbound/tasks/main.yml
index 7ed42cb..eb88f93 100644
--- a/roles/unbound/tasks/main.yml
+++ b/roles/unbound/tasks/main.yml
@@ -7,11 +7,6 @@
ansible.builtin.package:
name: unbound
- - name: install extra dns tooling
- become: true
- ansible.builtin.package:
- name: [ bind ] # the bind package includes tools like dig in archlinux
-
- name: ensure correct directory permissions
become: true
ansible.builtin.file:
@@ -40,23 +35,10 @@
enabled: true
- name: disable systemd-resolved
- become: true
when: unbound_disable_systemd_networkd
- ansible.builtin.systemd:
- name: systemd-resolved.service
- state: stopped
- enabled: false
-
- - name: configure system resolver to point to local unbound
- become: true
- when: unbound_disable_systemd_networkd
- ansible.builtin.copy:
- src: no-resolved.resolv.conf
- dest: /etc/resolv.conf
- owner: unbound
- group: unbound
- mode: u=rw,g=r,o=r
-
+ ansible.builtin.include_role:
+ name: deploy_systemd_resolved_config
+ vars_from: deploy_systemd_resolved_config
- name: install and configure prometheus-exporter for unbound
ansible.builtin.import_tasks: prometheus-exporter.yml
diff --git a/roles/unbound/tasks/prometheus-exporter.yml b/roles/unbound/tasks/prometheus-exporter.yml
index d05b838..b794e07 100644
--- a/roles/unbound/tasks/prometheus-exporter.yml
+++ b/roles/unbound/tasks/prometheus-exporter.yml
@@ -3,7 +3,13 @@
become: true
ansible.builtin.package:
name: prometheus-unbound-exporter
- notify: prometheus-unbound-exporter.enabled
+
+- name: enable unbound prometheus exporter
+ become: true
+ ansible.builtin.systemd:
+ name: prometheus-unbound-exporter.service
+ enabled: true
+ daemon_reload: true
- name: configure unbound exporter
become: true
diff --git a/roles/unbound/vars/deploy_systemd_resolved_config.yaml b/roles/unbound/vars/deploy_systemd_resolved_config.yaml
new file mode 100644
index 0000000..0da57c1
--- /dev/null
+++ b/roles/unbound/vars/deploy_systemd_resolved_config.yaml
@@ -0,0 +1,9 @@
+---
+deploy_systemd_resolved_config__enable: false
+deploy_systemd_resolved_config__dns:
+ - 127.0.0.1
+deploy_systemd_resolved_config__fallback_dns: # Fux DNS Server
+ - 185.161.128.66
+ - 2a07:c481:0:4::2
+ - 185.161.128.67
+ - 2a07:c481:0:4::3
From 84b1fa70cec9e7bea03e8b916707062431acd411 Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Tue, 26 May 2026 10:08:11 +0200
Subject: [PATCH 12/14] unbound(role): add FIXME note to unbound prometheus
exporter install
---
roles/unbound/tasks/prometheus-exporter.yml | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/roles/unbound/tasks/prometheus-exporter.yml b/roles/unbound/tasks/prometheus-exporter.yml
index b794e07..fba5090 100644
--- a/roles/unbound/tasks/prometheus-exporter.yml
+++ b/roles/unbound/tasks/prometheus-exporter.yml
@@ -1,5 +1,5 @@
---
-- name: install unbound prometheus exporter
+- name: install unbound prometheus exporter # FIXME: there is no prometheus-unbound-exporter in debian .deb exists in https://github.com/letsencrypt/unbound_exporter/releases/tag/v0.6.0
become: true
ansible.builtin.package:
name: prometheus-unbound-exporter
From bb127d13754e6f1f9438b174f4ccee71c0eb08f9 Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Tue, 26 May 2026 10:09:50 +0200
Subject: [PATCH 13/14] unbound(role): remove tags inside role
---
roles/unbound/handlers/main.yml | 2 --
roles/unbound/tasks/main.yml | 1 -
2 files changed, 3 deletions(-)
diff --git a/roles/unbound/handlers/main.yml b/roles/unbound/handlers/main.yml
index 222e8c5..09af699 100644
--- a/roles/unbound/handlers/main.yml
+++ b/roles/unbound/handlers/main.yml
@@ -1,12 +1,10 @@
- name: unbound.restarted
- tags: [ unbound, dns, dns_resolver ]
become: true
ansible.builtin.systemd:
name: unbound.service
state: restarted
- name: unbound.reloaded
- tags: [ unbound, dns, dns_resolver ]
become: true
ansible.builtin.systemd:
name: unbound.service
diff --git a/roles/unbound/tasks/main.yml b/roles/unbound/tasks/main.yml
index eb88f93..a4a6896 100644
--- a/roles/unbound/tasks/main.yml
+++ b/roles/unbound/tasks/main.yml
@@ -1,5 +1,4 @@
- name: unbound role main
- tags: [ unbound, dns, dns_resolver ]
block:
- name: install unbound dns resolver
From 960315d1826fabcc8441ce14f648fc268ac0db22 Mon Sep 17 00:00:00 2001
From: bitwhisker
Date: Tue, 26 May 2026 10:19:42 +0200
Subject: [PATCH 14/14] unbound(role): reformat config template and use all
vcpus
---
roles/unbound/templates/unbound.conf.j2 | 75 ++++++++++++-------------
1 file changed, 35 insertions(+), 40 deletions(-)
diff --git a/roles/unbound/templates/unbound.conf.j2 b/roles/unbound/templates/unbound.conf.j2
index a1e310e..96aa9cd 100644
--- a/roles/unbound/templates/unbound.conf.j2
+++ b/roles/unbound/templates/unbound.conf.j2
@@ -1,22 +1,18 @@
# ref: https://unbound.docs.nlnetlabs.nl/en/latest/manpages/unbound.conf.html
# unbound.conf(5) man page
server:
- {% if unbound_enable_dnssec -%}
- # disable chroot because unbound is the only thing running on the VM
- # and because it has issues with how archlinux configures the systemd units write protection regarding the anchor file
- chroot: ""
-
- # location of the trust anchor file that enables DNSSEC
- # this file is generated by the `unbound-anchor` command
- auto-trust-anchor-file: "/etc/unbound/trusted-key.key"
- {% endif -%}
+ {% if unbound_enable_dnssec -%}
+ # location of the trust anchor file that enables DNSSEC
+ # this file is generated by the `unbound-anchor` command
+ auto-trust-anchor-file: "/etc/unbound/trusted-key.key"
+ {% endif -%}
# use all CPUs
- num-threads: 2
+ num-threads: {{ ansible_facts['processor_vcpus'] }}
# more cache memory
- rrset-cache-size: 60m
- msg-cache-size: 30m
+ rrset-cache-size: 60m
+ msg-cache-size: 30m
# prefetch to keep the cache up to date
prefetch: yes
@@ -25,49 +21,48 @@ server:
prefetch-key: yes
# Faster UDP with multithreading (only on Linux).
- so-reuseport: yes
+ so-reuseport: yes
# disable special large send buffer handling and just use kernel defaults
- so-sndbuf: 0
+ so-sndbuf: 0
- # send minimal amount of information to upstream servers to enhance privacy
- qname-minimisation: yes
+ # send minimal amount of information to upstream servers to enhance privacy
+ qname-minimisation: yes
- # specify the interface to answer queries from by ip-address.
- {% for i in unbound_bind_interfaces -%}
- interface: "{{ i }}"
- {% endfor %}
+ # specify the interface to answer queries from by ip-address.
+ {% for i in unbound_bind_interfaces -%}
+ interface: "{{ i }}"
+ {% endfor %}
- # addresses from the IP range that are allowed to connect to the resolver
- {% for i in unbound_access_control -%}
- access-control: {{ i }}
- {% endfor -%}
+ # addresses from the IP range that are allowed to connect to the resolver
+ {% for i in unbound_access_control -%}
+ access-control: {{ i }}
+ {% endfor -%}
- {% for i in unbound_private_domain -%}
- private-domain: {{ i }}
- {% endfor -%}
+ {% for i in unbound_private_domain -%}
+ private-domain: {{ i }}
+ {% endfor -%}
- # The number of seconds between printing statistics to the log for every thread.
- statistics-interval: 0
+ # The number of seconds between printing statistics to the log for every thread.
+ statistics-interval: 0
- # Extended statistics are printed, Keeping track of more statistics takes time.
- extended-statistics: yes
+ # Extended statistics are printed, Keeping track of more statistics takes time.
+ extended-statistics: yes
remote-control:
- control-enable: {{ "yes" if unbound_enable_unbound_control else "no" }}
- control-interface: /run/unbound-control.sock
+ control-enable: {{ "yes" if unbound_enable_unbound_control else "no" }}
+ control-interface: /run/unbound-control.sock
# configure some zones for which this resolver will act authoritatively
# https://www.dns.icann.org/services/axfr/
{% for i in [ ".", "in-addr.arpa.", "arpa.", "root-servers.net.", "ip6.arpa.", "ip6-servers.arpa.", "mcast.net." ] %}
auth-zone:
- name: "{{ i }}"
- primary: "lax.xfr.dns.icann.org"
- primary: "iad.xfr.dns.icann.org"
- fallback-enabled: yes
- for-downstream: no
- for-upstream: yes
-
+ name: "{{ i }}"
+ primary: "lax.xfr.dns.icann.org"
+ primary: "iad.xfr.dns.icann.org"
+ fallback-enabled: yes
+ for-downstream: no
+ for-upstream: yes
{% endfor %}