Compare commits

..

2 commits

Author SHA1 Message Date
Leon Schwarzäugl
db273edc48
feat[server]: add home proxy
Some checks failed
Build and Deploy / build (push) Has been cancelled
Build and Deploy / deploy (push) Has been cancelled
2026-01-04 17:45:53 +01:00
Leon Schwarzäugl
ca9f5830bf
feat[server]: finalize router config 2026-01-02 05:03:32 +01:00
91 changed files with 3698 additions and 1991 deletions

5
.github/README.md vendored
View file

@ -171,13 +171,14 @@
|🏠 **treehouse** | NVIDIA DGX Spark | AI Workstation, remote builder, hm-only-reference | |🏠 **treehouse** | NVIDIA DGX Spark | AI Workstation, remote builder, hm-only-reference |
|🖥️ **summers** | ASUS Z10PA-D8, 2* Intel Xeon E5-2650 v4, 128GB RAM | Homeserver (microvms), remote builder, data storage | |🖥️ **summers** | ASUS Z10PA-D8, 2* Intel Xeon E5-2650 v4, 128GB RAM | Homeserver (microvms), remote builder, data storage |
|🖥️ **winters** | ASRock J4105-ITX, 32GB RAM | Homeserver (IoT server in spe) | |🖥️ **winters** | ASRock J4105-ITX, 32GB RAM | Homeserver (IoT server in spe) |
|🖥️ **hintbooth** | HUNSN RM02, 8GB RAM | Router | |🖥️ **hintbooth** | HUNSN RM02, 8GB RAM | Router, DNS Resolver, home NGINX endpoint |
|☁️ **stoicclub** | Cloud Server: 1 vCPUs, 8GB RAM | Authoritative DNS server | |☁️ **stoicclub** | Cloud Server: 1 vCPUs, 8GB RAM | Authoritative DNS server |
|☁️ **liliputsteps** | Cloud Server: 1 vCPUs, 8GB RAM | SSH bastion | |☁️ **liliputsteps** | Cloud Server: 1 vCPUs, 8GB RAM | SSH bastion |
|☁️ **twothreetunnel**| Cloud Server: 2 vCPUs, 8GB RAM | Service proxy | |☁️ **twothreetunnel**| Cloud Server: 2 vCPUs, 8GB RAM | Service proxy |
|☁️ **eagleland** | Cloud Server: 2 vCPUs, 8GB RAM | Mailserver | |☁️ **eagleland** | Cloud Server: 2 vCPUs, 8GB RAM | Mailserver |
|☁️ **moonside** | Cloud Server: 4 vCPUs, 24GB RAM | Gaming server, syncthing + lightweight services | |☁️ **moonside** | Cloud Server: 4 vCPUs, 24GB RAM | Game servers, syncthing + other lightweight services |
|☁️ **belchsfactory** | Cloud Server: 4 vCPUs, 24GB RAM | Hydra builder and nix binary cache | |☁️ **belchsfactory** | Cloud Server: 4 vCPUs, 24GB RAM | Hydra builder and nix binary cache |
|🪟 **chaostheater** | Asus Z97-A, i7-4790k, GTX970, 32GB RAM | Home Game Streaming Server (Windows/AtlasOS, not nix-managed) |
|📱 **magicant** | Samsung Galaxy Z Flip 6 | Phone | |📱 **magicant** | Samsung Galaxy Z Flip 6 | Phone |
|💿 **drugstore** | - | NixOS-installer ISO for bootstrapping new hosts | |💿 **drugstore** | - | NixOS-installer ISO for bootstrapping new hosts |
|💿 **brickroad** | - | Kexec tarball for bootstrapping low-memory machines | |💿 **brickroad** | - | Kexec tarball for bootstrapping low-memory machines |

View file

@ -19,6 +19,8 @@ keys:
- &twothreetunnel age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d - &twothreetunnel age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d
- &winters age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza - &winters age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza
- &dgx age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns - &dgx age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns
- &hintbooth-adguardhome age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
- &hintbooth-nginx age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
creation_rules: creation_rules:
- path_regex: secrets/repo/[^/]+\.(yaml|json|env|ini|enc)$ - path_regex: secrets/repo/[^/]+\.(yaml|json|env|ini|enc)$
key_groups: key_groups:
@ -38,6 +40,8 @@ creation_rules:
- *pyramid - *pyramid
- *moonside - *moonside
- *dgx - *dgx
- *hintbooth-adguardhome
- *hintbooth-nginx
- path_regex: secrets/work/[^/]+\.(yaml|json|env|ini)$ - path_regex: secrets/work/[^/]+\.(yaml|json|env|ini)$
key_groups: key_groups:
@ -53,6 +57,7 @@ creation_rules:
age: age:
- *twothreetunnel - *twothreetunnel
- *eagleland - *eagleland
- *hintbooth-nginx
- path_regex: hosts/nixos/x86_64-linux/pyramid/secrets/[^/]+\.(yaml|json|env|ini|enc)$ - path_regex: hosts/nixos/x86_64-linux/pyramid/secrets/[^/]+\.(yaml|json|env|ini|enc)$
key_groups: key_groups:
@ -131,6 +136,22 @@ creation_rules:
age: age:
- *hintbooth - *hintbooth
- path_regex: hosts/nixos/x86_64-linux/hintbooth/secrets/adguardhome/[^/]+\.(yaml|json|env|ini|enc)$
key_groups:
- pgp:
- *swarsel
age:
- *hintbooth
- *hintbooth-adguardhome
- path_regex: hosts/nixos/x86_64-linux/hintbooth/secrets/nginx/[^/]+\.(yaml|json|env|ini|enc)$
key_groups:
- pgp:
- *swarsel
age:
- *hintbooth
- *hintbooth-nginx
- path_regex: hosts/darwin/x86_64-darwin/nbm-imba-166/secrets/[^/]+\.(yaml|json|env|ini|enc)$ - path_regex: hosts/darwin/x86_64-darwin/nbm-imba-166/secrets/[^/]+\.(yaml|json|env|ini|enc)$
key_groups: key_groups:
- pgp: - pgp:

File diff suppressed because it is too large Load diff

View file

@ -1117,7 +1117,7 @@ create a new one."
(use-package nix-ts-mode (use-package nix-ts-mode
:after lsp-mode :after lsp-mode
:mode "\\.nix\\'" :mode ("\\.nix\\'" . "\\.nix\\.enc\\'")
:ensure t :ensure t
:hook :hook
(nix-ts-mode . lsp-deferred) ;; So that envrc mode will work (nix-ts-mode . lsp-deferred) ;; So that envrc mode will work

Binary file not shown.

After

Width:  |  Height:  |  Size: 120 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 50 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 84 KiB

After

Width:  |  Height:  |  Size: 83 KiB

Before After
Before After

Binary file not shown.

After

Width:  |  Height:  |  Size: 8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 293 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

40
flake.lock generated
View file

@ -203,11 +203,11 @@
] ]
}, },
"locked": { "locked": {
"lastModified": 1728330715, "lastModified": 1764011051,
"narHash": "sha256-xRJ2nPOXb//u1jaBnDP56M7v5ldavjbtR6lfGqSvcKg=", "narHash": "sha256-M7SZyPZiqZUR/EiiBJnmyUbOi5oE/03tCeFrTiUZchI=",
"owner": "numtide", "owner": "numtide",
"repo": "devshell", "repo": "devshell",
"rev": "dd6b80932022cea34a019e2bb32f6fa9e494dfef", "rev": "17ed8d9744ebe70424659b0ef74ad6d41fc87071",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -426,11 +426,11 @@
"flake-compat_3": { "flake-compat_3": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1696426674, "lastModified": 1761588595,
"narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", "narHash": "sha256-XKUZz9zewJNUj46b4AJdiRZJAvSZ0Dqj2BNfXvFlJC4=",
"owner": "edolstra", "owner": "edolstra",
"repo": "flake-compat", "repo": "flake-compat",
"rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", "rev": "f387cd2afec9419c8ee37694406ca490c3f34ee5",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -688,11 +688,11 @@
"systems": "systems_3" "systems": "systems_3"
}, },
"locked": { "locked": {
"lastModified": 1726560853, "lastModified": 1731533236,
"narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", "narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
"owner": "numtide", "owner": "numtide",
"repo": "flake-utils", "repo": "flake-utils",
"rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", "rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -1369,11 +1369,11 @@
"pre-commit-hooks": "pre-commit-hooks" "pre-commit-hooks": "pre-commit-hooks"
}, },
"locked": { "locked": {
"lastModified": 1762088663, "lastModified": 1767198021,
"narHash": "sha256-rpCvFan9Dji1Vw4HfVqYdfWesz5sKZE3uSgYR9gRreA=", "narHash": "sha256-O/7ZAy0OczYEy7zl+EegeekvRqb3JPh0btyBKtRvbVw=",
"owner": "oddlama", "owner": "oddlama",
"repo": "nix-topology", "repo": "nix-topology",
"rev": "c15f569794a0f1a437850d0ac81675bcf23ca6cb", "rev": "0c052d902678b592b957eac2c250e4030fe70ebc",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -1862,11 +1862,11 @@
}, },
"nixpkgs_12": { "nixpkgs_12": {
"locked": { "locked": {
"lastModified": 1730531603, "lastModified": 1766651565,
"narHash": "sha256-Dqg6si5CqIzm87sp57j5nTaeBbWhHFaVyG7V6L8k3lY=", "narHash": "sha256-QEhk0eXgyIqTpJ/ehZKg9IKS7EtlWxF3N7DXy42zPfU=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "7ffd9ae656aec493492b44d0ddfb28e79a1ea25d", "rev": "3e2499d5539c16d0d173ba53552a4ff8547f4539",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -2574,18 +2574,14 @@
"nixpkgs": [ "nixpkgs": [
"nix-topology", "nix-topology",
"nixpkgs" "nixpkgs"
],
"nixpkgs-stable": [
"nix-topology",
"nixpkgs"
] ]
}, },
"locked": { "locked": {
"lastModified": 1730797577, "lastModified": 1765911976,
"narHash": "sha256-SrID5yVpyUfknUTGWgYkTyvdr9J1LxUym4om3SVGPkg=", "narHash": "sha256-t3T/xm8zstHRLx+pIHxVpQTiySbKqcQbK+r+01XVKc0=",
"owner": "cachix", "owner": "cachix",
"repo": "pre-commit-hooks.nix", "repo": "pre-commit-hooks.nix",
"rev": "1864030ed24a2b8b4e4d386a5eeaf0c5369e50a9", "rev": "b68b780b69702a090c8bb1b973bab13756cc7a27",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -61,7 +61,7 @@
postgresql = true; postgresql = true;
attic = true; attic = true;
garage = true; garage = true;
hydra = false; hydra = true;
}; };
} }

View file

@ -1,4 +1,4 @@
{ self, lib, minimal, ... }: { self, config, lib, minimal, ... }:
{ {
imports = [ imports = [
./hardware-configuration.nix ./hardware-configuration.nix
@ -10,6 +10,16 @@
topology.self = { topology.self = {
icon = "devices.cloud-server"; icon = "devices.cloud-server";
interfaces.ProxyJump = {
virtual = true;
physicalConnections = [
(config.lib.topology.mkConnection "moonside" "lan")
(config.lib.topology.mkConnection "twothreetunnel" "lan")
(config.lib.topology.mkConnection "belchsfactory" "lan")
(config.lib.topology.mkConnection "stoicclub" "lan")
(config.lib.topology.mkConnection "eagleland" "wan")
];
};
}; };
swarselsystems = { swarselsystems = {

View file

@ -5,6 +5,7 @@
./disk-config.nix ./disk-config.nix
"${self}/modules/nixos/optional/systemd-networkd-server.nix" "${self}/modules/nixos/optional/systemd-networkd-server.nix"
"${self}/modules/nixos/optional/nix-topology-self.nix"
]; ];
topology.self = { topology.self = {

View file

@ -12,7 +12,10 @@
icon = "devices.cloud-server"; icon = "devices.cloud-server";
}; };
globals.general.webProxy = config.node.name; globals.general = {
webProxy = config.node.name;
oauthServer = config.node.name;
};
swarselsystems = { swarselsystems = {
flakePath = "/root/.dotfiles"; flakePath = "/root/.dotfiles";
@ -35,6 +38,7 @@
"winters" "winters"
"belchsfactory" "belchsfactory"
"eagleland" "eagleland"
"hintbooth-adguardhome"
]; ];
}; };
}; };

View file

@ -17,8 +17,8 @@ in
]; ];
topology.self.interfaces = { topology.self.interfaces = {
"eth1" = { }; eth1.network = lib.mkForce "home";
"wifi" = { }; wifi = { };
}; };
swarselsystems = { swarselsystems = {

View file

@ -1,26 +1,27 @@
{ self, config, lib, minimal, confLib, ... }: { self, config, lib, minimal, confLib, globals, ... }:
{ {
imports = [ imports = [
./hardware-configuration.nix ./hardware-configuration.nix
./disk-config.nix ./disk-config.nix
"${self}/modules/nixos/optional/systemd-networkd-server.nix" "${self}/modules/nixos/optional/systemd-networkd-server-home.nix"
"${self}/modules/nixos/optional/systemd-networkd-vlan.nix" "${self}/modules/nixos/optional/microvm-host.nix"
]; ];
topology.self = { topology.self = {
interfaces = { interfaces = {
"eth1" = { }; lan2.physicalConnections = [{ node = "summers"; interface = "eth1"; }];
"eth2" = { }; lan3.physicalConnections = [{ node = "summers"; interface = "eth2"; }];
"eth3" = { }; lan4.physicalConnections = [{ node = "switch-bedroom"; interface = "eth1"; }];
"eth4" = { }; lan5.physicalConnections = [{ node = "switch-livingroom"; interface = "eth1"; }];
"eth5" = { };
"eth6" = { };
}; };
}; };
globals.general.homeProxy = config.node.name; globals.general = {
homeProxy = config.node.name;
routerServer = config.node.name;
};
swarselsystems = { swarselsystems = {
info = "HUNSN RM02, 8GB RAM"; info = "HUNSN RM02, 8GB RAM";
@ -35,12 +36,16 @@
swapSize = "8G"; swapSize = "8G";
networkKernelModules = [ "igb" ]; networkKernelModules = [ "igb" ];
withMicroVMs = true; withMicroVMs = true;
localVLANs = map (name: "${name}") (builtins.attrNames globals.networks.home-lan.vlans);
initrdVLAN = "home";
server = { server = {
wireguard.interfaces = { wireguard.interfaces = {
wgHome = { wgHome = {
isServer = true; isServer = true;
peers = [ peers = [
"winters" "winters"
"hintbooth-adguardhome"
"hintbooth-nginx"
]; ];
}; };
}; };
@ -63,6 +68,7 @@
guests = lib.mkIf (!minimal && config.swarselsystems.withMicroVMs) ( guests = lib.mkIf (!minimal && config.swarselsystems.withMicroVMs) (
{ } { }
// confLib.mkMicrovm "adguardhome" // confLib.mkMicrovm "adguardhome"
// confLib.mkMicrovm "nginx"
); );
} }

View file

@ -1,23 +0,0 @@
{ self, lib, minimal, ... }:
{
imports = [
"${self}/profiles/nixos/microvm"
"${self}/modules/nixos"
];
swarselsystems = {
isMicroVM = true;
};
} // lib.optionalAttrs (!minimal) {
microvm = {
mem = 1024 * 1;
vcpu = 1;
};
swarselprofiles = {
microvm = true;
};
}

View file

@ -0,0 +1,43 @@
{ self, config, lib, minimal, ... }:
{
imports = [
"${self}/profiles/nixos/microvm"
"${self}/modules/nixos"
];
swarselsystems = {
isMicroVM = true;
isImpermanence = true;
proxyHost = "twothreetunnel";
server = {
wireguard.interfaces = {
wgHome = {
isClient = true;
serverName = "hintbooth";
};
wgProxy = {
isClient = true;
serverName = "twothreetunnel";
};
};
};
};
globals.general.homeDnsServer = config.node.name;
} // lib.optionalAttrs (!minimal) {
microvm = {
mem = 1024 * 1;
vcpu = 1;
};
swarselprofiles = {
microvm = true;
};
swarselmodules.server = {
adguardhome = true;
};
}

View file

@ -0,0 +1,60 @@
{ self, config, lib, minimal, globals, confLib, ... }:
let
inherit (confLib.static) nginxAccessRules;
in
{
imports = [
"${self}/profiles/nixos/microvm"
"${self}/modules/nixos"
];
swarselsystems = {
isMicroVM = true;
isImpermanence = true;
proxyHost = config.node.name;
server = {
wireguard.interfaces = {
wgHome = {
isClient = true;
serverName = "hintbooth";
};
};
};
};
globals.general.homeWebProxy = config.node.name;
} // lib.optionalAttrs (!minimal) {
microvm = {
mem = 3072 * 1;
vcpu = 1;
};
swarselprofiles = {
microvm = true;
};
swarselmodules.server = {
nginx = true;
};
services.nginx = {
upstreams.fritzbox = {
servers.${globals.networks.home-lan.hosts.fritzbox.ipv4} = { };
};
virtualHosts.${globals.services.fritzbox.domain} = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
locations."/" = {
proxyPass = "http://fritzbox";
proxyWebsockets = true;
};
extraConfig = ''
proxy_ssl_verify off;
'' + nginxAccessRules;
};
};
}

View file

@ -0,0 +1,57 @@
wireguard-private-key: ENC[AES256_GCM,data:5RdR6CvGBwaklSgiP0kmz/ShroIa1By7ZqgxKrnSGjHRyrzaeWGTuJmqKJM=,iv:D5UmcQkbRs8WVQUA8XpFCwLy8+O4+RoJLWOkHj0H7ss=,tag:feSuK9jW+wLeygqhKHycDw==,type:str]
sops:
age:
- recipient: age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBMEM4alliWlBCT3VsbVA5
OGt5bmQvZW1TaUNkbWtFdzVGNDNpY0hBOVhzCm84TldYNHBrU01HMlBkbGNwZFAw
WVk0T3FycVRHUUNtM1pTYkQ4Qmw3RTgKLS0tIE9LUlNEVjJHOGVIK1RSMmRXUDF6
QlRKY1hRVzNTVXhESUd3OElXL2pBZXcKDWYoOzi2b4qeIbCVCfTj0lTW+OfbnsXB
8MugCHu7+b+ju0v/lUP66jDW9/2AH4PzHtCNHjsafyzr2qnW8HlOzA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJRWJXR2tYdEd4cTZsSi9l
Tm1pSC9pek5BakpEMlkwVTcrMlBuVzlXWUVrCmlnV0xJc25nL0twK3VCZ3FRK2x2
RW52Q1NxWUhTUGY0NnQ0WEhLMWxIcFUKLS0tIG83eVM0KzdLQ004aDRKNTYvdmVZ
d3ZOSStBMFpSU2ZjNWhFRkREQWlUdmcKggVvLy1mLYGf8084RQtlipS4+z4dfPsN
HZfid0srwYnezlQ5qOY8/HrDLWHEyuZ4xFZVi4n0k49qBpNwJdmvyQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-01-02T04:14:03Z"
mac: ENC[AES256_GCM,data:aA+oIq31QBla9hOpApaMeP7MFl/hI0kDjC1QyPkmexXuMB2pQJ6bBEmazreX2m2TPtHv1rtVUak7F6TbA+97IFb9EQFuAREi1Ca0xjz2eGVFQKu94qkS/FNemXTAkEZxC9LQ1TRqNXXNITehKUeIN65epuNbWqo+iOW0OHEXm/w=,iv:1NKL2PZBUDyHEIiB2ZpvTdCh9ZO+r8bPyJo+EO1PBmQ=,tag:5W9owm1Z+7O1CGVmH1afUw==,type:str]
pgp:
- created_at: "2026-01-02T21:12:51Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMAwDh3VI7VctTARAAmvkQ9V14f0BT/bNdFVZtTlY4yVon37CX32SZPUcHV7o8
Dya0sZd9tuVATSv79TnybscuNx95fkoZJwujBfAadexn2zY8zl1oEWEHx7p+8/mE
W8JbQAjbcbX9sNQYXc8kYJylBThmgNN/HXK7CGtgDFr9xnGzDBnDm/M31P1HwYBm
IdIQgFGErEt1K3xvw28Lk3tPuZLK3Y+H2Yna7RRF6K1blGJUvEnL6yFdA10/eFW7
8066mO26F2l5xFuktK0nNeniLHKa5VVYp8iM+JMhX38l0wiIi8pGyxo3uAjNpa0w
IfpCneEBe/yyaUPcWMjXmUG5LJe3kWUup8cSzvu01Z3W159/QsflxIMkIsklqhim
B2zuPdAlYsjjS/05DIHInN2IIB/rjADkQvXji1XYLhWJj4jxDeck/UIc6Q22TED+
autlbl8d/5sqyO5ghPpShF/s0vMTqUfpXZrDrbuyDFqCfwi0ahP03bUsv20ZEz6u
zG3K5HuXHh7ATSppwuMbcv7vcjF1tkbo6XhWZDv0rY0DFWqiYhnxWwlFlGLxf4zX
g6r7Ca/E/YXG/eOET6M9DxwHjj0D7u/ryAkCktqPL9w8oNGarZQ/xMx0+ocI3byc
Zvzlmd63BtgaGNSxH3stK29KN3ED8cDkG/JzAxCATWiUBBkqW/ga4sGZqtLlSO+F
AgwDC9FRLmchgYQBD/9JbFZie25PO2CyELlUWm5SmJcugT9SK/mIA2fe1PlA+Gnf
5z9iXraMSQchz4R1IoiixDhubwKeKp/auqhlOPvo58Lsi6iDR/WaLWabD+hcyAb1
ck/f/PUzTLhlLcfu18VPfXVzfnky3dX8P5aS0WMLAQblj2RaaiHxnPqf49kXSn3q
VSJ0pr0nEsPuWtoCkHUAwAJ8X5GPXN2OD4YbHsNaA9h2vrJAxNd5+HNsvg8JtI88
X/uMM7cWcaXcmNZOz166HUIPcJ5cabJ48Sv8sDfMPOcTiJkMiESBnRYTwdUcp08m
nGipSrUeW3pVOC1bGyukZb6sF84pTtCpqS+kOSfKFlxFFdAEcpzFIPuOMeo2dbKj
GSGPDemZFC2yFq883yk9/mZbgjOUsqrj0ZP3rCD5ZHpfUM5IxGQ+mKaOucTXYmif
lrTPMYnAc7pHxKZ87BgiKBYrfRAZvorLYKv8zG8YagAUw8iCtc68YUUdvLW9haQf
rwWCU1z+sszYSac7I57gfqICQhMUbs1n9S2Cn0C0xo4q2Lu36ysip4rEVGg6TmUu
znXYu+3orodw2TwC0tGxXHYKwmlr7EGnBCbdVKpDoCbV6cYkDYoPUFg0alqIPd5r
KCkee9MaCLLX7IdBrbLf1lkHGwSAs81GfZRMLBauM7/hn+hMUeIJnMbtJnVIB9Je
AdT2nSH06+POnjvxa2t0dUasnG/6ISBRSk6FgBBZ+pdVlrvaB4javgWGpiAWCUu6
b2CMZF3HullmLj+wwAKlsZsIOXGICN5GeQxLHYF8Kx7Doj68Owu/zGM5MS+7XQ==
=wYdb
-----END PGP MESSAGE-----
fp: 4BE7925262289B476DBBC17B76FD3810215AE097
unencrypted_suffix: _unencrypted
version: 3.11.0

View file

@ -0,0 +1,57 @@
wireguard-private-key: ENC[AES256_GCM,data:3T0ZoPAs/OIkhdZlH171d9d2Ycxtp4WfI92pTBI3vRw7BVvEgQZKu5DCvbA=,iv:gsczaGwcI3JocOazMIEsgHFruEKDPxOTUQzx+rdCaio=,tag:/Sw7QsZ4fV+BMWdfcUevBA==,type:str]
sops:
age:
- recipient: age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBBMEM4alliWlBCT3VsbVA5
OGt5bmQvZW1TaUNkbWtFdzVGNDNpY0hBOVhzCm84TldYNHBrU01HMlBkbGNwZFAw
WVk0T3FycVRHUUNtM1pTYkQ4Qmw3RTgKLS0tIE9LUlNEVjJHOGVIK1RSMmRXUDF6
QlRKY1hRVzNTVXhESUd3OElXL2pBZXcKDWYoOzi2b4qeIbCVCfTj0lTW+OfbnsXB
8MugCHu7+b+ju0v/lUP66jDW9/2AH4PzHtCNHjsafyzr2qnW8HlOzA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJRWJXR2tYdEd4cTZsSi9l
Tm1pSC9pek5BakpEMlkwVTcrMlBuVzlXWUVrCmlnV0xJc25nL0twK3VCZ3FRK2x2
RW52Q1NxWUhTUGY0NnQ0WEhLMWxIcFUKLS0tIG83eVM0KzdLQ004aDRKNTYvdmVZ
d3ZOSStBMFpSU2ZjNWhFRkREQWlUdmcKggVvLy1mLYGf8084RQtlipS4+z4dfPsN
HZfid0srwYnezlQ5qOY8/HrDLWHEyuZ4xFZVi4n0k49qBpNwJdmvyQ==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-01-03T05:23:18Z"
mac: ENC[AES256_GCM,data:u9N7GzLPDW7cHT4mkUAC9Diq1RdV5iSwcz/fqzXQKRmic09eVydAgyk2g6NbJ+4tBbAjIfeUch8Bhf5eG0sGzeDkb1qWAMEnP8EPmQ64OdRyN2SxJgxkc8KFGxkrGz9slS2ozWth6q/tKBSsOYbo8WDlCqXhmYp+zBxvYFR30Mg=,iv:HC1e2i0E7dV9/au+A0kHd+UXDhw3xf7RbTpwJI+hjpY=,tag:dPCDh9qalNtbHIhs//cBpg==,type:str]
pgp:
- created_at: "2026-01-02T21:12:51Z"
enc: |-
-----BEGIN PGP MESSAGE-----
hQIMAwDh3VI7VctTARAAmvkQ9V14f0BT/bNdFVZtTlY4yVon37CX32SZPUcHV7o8
Dya0sZd9tuVATSv79TnybscuNx95fkoZJwujBfAadexn2zY8zl1oEWEHx7p+8/mE
W8JbQAjbcbX9sNQYXc8kYJylBThmgNN/HXK7CGtgDFr9xnGzDBnDm/M31P1HwYBm
IdIQgFGErEt1K3xvw28Lk3tPuZLK3Y+H2Yna7RRF6K1blGJUvEnL6yFdA10/eFW7
8066mO26F2l5xFuktK0nNeniLHKa5VVYp8iM+JMhX38l0wiIi8pGyxo3uAjNpa0w
IfpCneEBe/yyaUPcWMjXmUG5LJe3kWUup8cSzvu01Z3W159/QsflxIMkIsklqhim
B2zuPdAlYsjjS/05DIHInN2IIB/rjADkQvXji1XYLhWJj4jxDeck/UIc6Q22TED+
autlbl8d/5sqyO5ghPpShF/s0vMTqUfpXZrDrbuyDFqCfwi0ahP03bUsv20ZEz6u
zG3K5HuXHh7ATSppwuMbcv7vcjF1tkbo6XhWZDv0rY0DFWqiYhnxWwlFlGLxf4zX
g6r7Ca/E/YXG/eOET6M9DxwHjj0D7u/ryAkCktqPL9w8oNGarZQ/xMx0+ocI3byc
Zvzlmd63BtgaGNSxH3stK29KN3ED8cDkG/JzAxCATWiUBBkqW/ga4sGZqtLlSO+F
AgwDC9FRLmchgYQBD/9JbFZie25PO2CyELlUWm5SmJcugT9SK/mIA2fe1PlA+Gnf
5z9iXraMSQchz4R1IoiixDhubwKeKp/auqhlOPvo58Lsi6iDR/WaLWabD+hcyAb1
ck/f/PUzTLhlLcfu18VPfXVzfnky3dX8P5aS0WMLAQblj2RaaiHxnPqf49kXSn3q
VSJ0pr0nEsPuWtoCkHUAwAJ8X5GPXN2OD4YbHsNaA9h2vrJAxNd5+HNsvg8JtI88
X/uMM7cWcaXcmNZOz166HUIPcJ5cabJ48Sv8sDfMPOcTiJkMiESBnRYTwdUcp08m
nGipSrUeW3pVOC1bGyukZb6sF84pTtCpqS+kOSfKFlxFFdAEcpzFIPuOMeo2dbKj
GSGPDemZFC2yFq883yk9/mZbgjOUsqrj0ZP3rCD5ZHpfUM5IxGQ+mKaOucTXYmif
lrTPMYnAc7pHxKZ87BgiKBYrfRAZvorLYKv8zG8YagAUw8iCtc68YUUdvLW9haQf
rwWCU1z+sszYSac7I57gfqICQhMUbs1n9S2Cn0C0xo4q2Lu36ysip4rEVGg6TmUu
znXYu+3orodw2TwC0tGxXHYKwmlr7EGnBCbdVKpDoCbV6cYkDYoPUFg0alqIPd5r
KCkee9MaCLLX7IdBrbLf1lkHGwSAs81GfZRMLBauM7/hn+hMUeIJnMbtJnVIB9Je
AdT2nSH06+POnjvxa2t0dUasnG/6ISBRSk6FgBBZ+pdVlrvaB4javgWGpiAWCUu6
b2CMZF3HullmLj+wwAKlsZsIOXGICN5GeQxLHYF8Kx7Doj68Owu/zGM5MS+7XQ==
=wYdb
-----END PGP MESSAGE-----
fp: 4BE7925262289B476DBBC17B76FD3810215AE097
unencrypted_suffix: _unencrypted
version: 3.11.0

View file

@ -23,9 +23,9 @@ in
topology.self = { topology.self = {
interfaces = { interfaces = {
"eth1" = { }; eth1.network = lib.mkForce "home";
"wifi" = { }; wifi = { };
"fritz-wg" = { }; fritz-wg.network = "fritz-wg";
}; };
}; };
@ -64,7 +64,7 @@ in
main = { main = {
# name = "BOE 0x0BC9 Unknown"; # name = "BOE 0x0BC9 Unknown";
name = "BOE 0x0BC9"; name = "BOE 0x0BC9";
mode = "2560x1600"; # TEMPLATE mode = "2560x1600";
scale = "1"; scale = "1";
position = "2560,0"; position = "2560,0";
workspace = "15:L"; workspace = "15:L";
@ -78,8 +78,8 @@ in
personal = true; personal = true;
}; };
networking.nftables = { # networking.nftables = {
enable = lib.mkForce false; # enable = lib.mkForce false;
firewall.enable = lib.mkForce false; # firewall.enable = lib.mkForce false;
}; # };
} }

View file

@ -75,7 +75,7 @@
fileSystems = { fileSystems = {
"/persist".neededForBoot = true; "/persist".neededForBoot = true;
"/home".neededForBoot = true; "/home".neededForBoot = true;
"/".neededForBoot = true; "/".neededForBoot = true; # this is ok because this is not a impermanence host
"/var/log".neededForBoot = true; "/var/log".neededForBoot = true;
}; };
} }

View file

@ -1,5 +1,5 @@
{ {
"data": "ENC[AES256_GCM,data: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,iv:Wc2rOI9aWgchjFGCl5R8d6E6GmYEKCIkIAZlUIlbE/4=,tag:3p301gA9WrBjwcpXs68ayg==,type:str]", "data": "ENC[AES256_GCM,data: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,iv:kkH/Hy/0PNzkVdTfYTgKBAN6nYslP0OFIndsmORZVEg=,tag:j/fMiT9DCog0CHnM74MNMw==,type:str]",
"sops": { "sops": {
"age": [ "age": [
{ {
@ -7,8 +7,8 @@
"enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3UFZTaXFNdjF2UmRFd3VL\nY2pZZ3ZaRkhZSjdVUjIraHV5ZlNaNGtwM3k0CkZ4OVRFcmR3MFBDcmdsbWFId3Iy\nVzQyUGI1eG44d3JFL2NvZEg4NnduT2cKLS0tIEdhOEZETk9nRTlVbmJ5UW9GalVx\nS00yaUpJZVFVNThFei8yRzJYejRkYk0Kf6Z8WnG8phRtFIUWIPys3PW0OImhAcF+\nUFLuL4Qr7zWaeItCRieYCs1yBn7KbUJHZNkJcvnkYW50NYvlEa8wBw==\n-----END AGE ENCRYPTED FILE-----\n" "enc": "-----BEGIN AGE ENCRYPTED FILE-----\nYWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3UFZTaXFNdjF2UmRFd3VL\nY2pZZ3ZaRkhZSjdVUjIraHV5ZlNaNGtwM3k0CkZ4OVRFcmR3MFBDcmdsbWFId3Iy\nVzQyUGI1eG44d3JFL2NvZEg4NnduT2cKLS0tIEdhOEZETk9nRTlVbmJ5UW9GalVx\nS00yaUpJZVFVNThFei8yRzJYejRkYk0Kf6Z8WnG8phRtFIUWIPys3PW0OImhAcF+\nUFLuL4Qr7zWaeItCRieYCs1yBn7KbUJHZNkJcvnkYW50NYvlEa8wBw==\n-----END AGE ENCRYPTED FILE-----\n"
} }
], ],
"lastmodified": "2025-12-31T12:22:14Z", "lastmodified": "2026-01-02T22:52:45Z",
"mac": "ENC[AES256_GCM,data:H17OWQwkZaugzTuMM8kBPZLYZs/poaLJt8osoY/gzC2CMpWXUtWpwgJ83CO7GkiPrPN2SZtEiaADP3PvZZqVcV5rDJNhdELmdvZfB14RQDUD9rYfnIX5uuzMMII+kguTkk+Zd1IRWv+MN9y4cdhys0lYJ7Nw1RyEMP9Bxd1zvcA=,iv:01Yode7T/2pUP1dFLyIUoDIfeWRWKf1Qq7pHvUDKQJQ=,tag:Ldxq5cRB2iexLhIrBfqGVQ==,type:str]", "mac": "ENC[AES256_GCM,data:p/m76sd+5HhD+tz7oSnoSzVRCnB1czTUTF90LSyLQuL6aVyTpVZp+p6/CnYc/fG+L/8wBUsLrwwajl22S2+MZAqvQFoYQwY/AiFb10wZNK2fzPEURW3P+QYzaf62nb4G3GlckjAcGxGyeGcU4TnL1qZEDgp/KcdZpsUwvVQvV/U=,iv:k7m4dOr13gczZTGlz7uHIQB/uFPEQJX19uHuLB1fupg=,tag:mzpbLMV5aun7IOvPIJv0ng==,type:str]",
"pgp": [ "pgp": [
{ {
"created_at": "2025-12-02T14:59:33Z", "created_at": "2025-12-02T14:59:33Z",

View file

@ -1,7 +1,7 @@
{ config, lib, ... }: { config, lib, ... }:
let let
mapperTarget = lib.swarselsystems.mkIfElse config.swarselsystems.isCrypted "/dev/mapper/cryptroot" "/dev/disk/by-label/nixos"; mapperTarget = lib.swarselsystems.mkIfElse config.swarselsystems.isCrypted "/dev/mapper/cryptroot" "/dev/disk/by-label/nixos";
inherit (config.swarselsystems) isImpermanence isCrypted; inherit (config.swarselsystems) isImpermanence isCrypted isBtrfs;
in in
{ {
options.swarselmodules.impermanence = lib.mkEnableOption "impermanence config"; options.swarselmodules.impermanence = lib.mkEnableOption "impermanence config";
@ -17,7 +17,7 @@ in
# So if it doesn't run, the btrfs system effectively acts like a normal system # So if it doesn't run, the btrfs system effectively acts like a normal system
# Taken from https://github.com/NotAShelf/nyx/blob/2a8273ed3f11a4b4ca027a68405d9eb35eba567b/modules/core/common/system/impermanence/default.nix # Taken from https://github.com/NotAShelf/nyx/blob/2a8273ed3f11a4b4ca027a68405d9eb35eba567b/modules/core/common/system/impermanence/default.nix
boot.tmp.useTmpfs = lib.mkIf (!isImpermanence) true; boot.tmp.useTmpfs = lib.mkIf (!isImpermanence) true;
boot.initrd.systemd = lib.mkIf isImpermanence { boot.initrd.systemd = lib.mkIf (isImpermanence && isBtrfs) {
enable = true; enable = true;
services.rollback = { services.rollback = {
description = "Rollback BTRFS root subvolume to a pristine state"; description = "Rollback BTRFS root subvolume to a pristine state";

View file

@ -33,6 +33,7 @@ let
(splitPath "services.kanidm.provision.systems.oauth2") (splitPath "services.kanidm.provision.systems.oauth2")
(splitPath "sops.secrets") (splitPath "sops.secrets")
(splitPath "swarselsystems.server.dns") (splitPath "swarselsystems.server.dns")
(splitPath "topology.self.services")
] ]
++ expandOptions (splitPath "networking.nftables.firewall") [ "zones" "rules" ] ++ expandOptions (splitPath "networking.nftables.firewall") [ "zones" "rules" ]
++ expandOptions (splitPath "services.firezone.gateway") [ "enable" "name" "apiUrl" "tokenFile" "package" "logLevel" ] ++ expandOptions (splitPath "services.firezone.gateway") [ "enable" "name" "apiUrl" "tokenFile" "package" "logLevel" ]

View file

@ -1,11 +1,10 @@
{ self, inputs, ... }: { self, lib, config, inputs, microVMParent, nodes, ... }:
{ {
imports = [ imports = [
inputs.disko.nixosModules.disko inputs.disko.nixosModules.disko
inputs.home-manager.nixosModules.home-manager inputs.home-manager.nixosModules.home-manager
inputs.impermanence.nixosModules.impermanence inputs.impermanence.nixosModules.impermanence
inputs.lanzaboote.nixosModules.lanzaboote inputs.lanzaboote.nixosModules.lanzaboote
inputs.microvm.nixosModules.host
inputs.microvm.nixosModules.microvm inputs.microvm.nixosModules.microvm
inputs.nix-index-database.nixosModules.nix-index inputs.nix-index-database.nixosModules.nix-index
inputs.nix-minecraft.nixosModules.minecraft-servers inputs.nix-minecraft.nixosModules.minecraft-servers
@ -23,6 +22,51 @@
]; ];
config = { config = {
system.stateVersion = "23.05"; _module.args.dns = inputs.dns;
nix.settings.experimental-features = [
"nix-command"
"flakes"
];
systemd.services."systemd-networkd".environment.SYSTEMD_LOG_LEVEL = "debug";
# NOTE: this is needed, we dont import sevrer network module for microvms
globals.hosts.${config.node.name}.isHome = true;
fileSystems."/persist".neededForBoot = lib.mkForce true;
systemd.network.networks."10-vlan-services" = {
dhcpV6Config = {
WithoutRA = "solicit";
# duid-en is nice in principle, but I already have MAC info anyways for reservations
DUIDType = "link-layer";
};
# networkConfig = {
# IPv6PrivacyExtensions = "no";
# IPv6AcceptRA = false;
# };
ipv6AcceptRAConfig = {
DHCPv6Client = "always";
};
};
microvm = {
shares = [
{
tag = "persist";
source = "${lib.optionalString nodes.${microVMParent}.config.swarselsystems.isImpermanence "/persist"}/microvms/${config.networking.hostName}";
mountPoint = "/persist";
proto = "virtiofs";
}
];
# mount the writeable overlay so that we can use nix shells inside the microvm
volumes = [
{
image = "/tmp/nix-store-overlay-${config.networking.hostName}.img";
autoCreate = true;
mountPoint = config.microvm.writableStoreOverlay;
size = 1024;
}
];
};
}; };
} }

View file

@ -1,13 +1,21 @@
{ config, lib, ... }: { config, lib, ... }:
{ {
# imports = [
# inputs.microvm.nixosModules.host
# ];
config = lib.mkIf (config.guests != { }) { config = lib.mkIf (config.guests != { }) {
microvm = { systemd.tmpfiles.settings."15-microvms" = builtins.listToAttrs (
hypervisor = lib.mkDefault "qemu"; map
}; (path: {
name = "${lib.optionalString config.swarselsystems.isImpermanence "/persist"}/microvms/${path}";
value = {
d = {
group = "kvm";
user = "microvm";
mode = "0750";
};
};
})
(builtins.attrNames config.guests)
);
}; };
} }

View file

@ -1,13 +1,25 @@
{ lib, config, globals, ... }: { lib, config, globals, confLib, ... }:
let
inherit (confLib.static) webProxy;
in
{ {
topology.self = { topology.self = {
icon = lib.mkIf config.swarselsystems.isCloud "devices.cloud-server"; icon = lib.mkIf config.swarselsystems.isCloud "devices.cloud-server";
interfaces.wan = lib.mkIf config.swarselsystems.isCloud { }; interfaces = {
interfaces.wg = lib.mkIf (config.swarselsystems.server.wireguard.isClient || config.swarselsystems.server.wireguard.isServer) { wan = lib.mkIf (config.swarselsystems.isCloud && config.swarselsystems.server.localNetwork == "wan") { };
addresses = [ globals.networks.twothreetunnel-wg.hosts.${config.node.name}.ipv4 ]; lan = lib.mkIf (config.swarselsystems.isCloud && config.swarselsystems.server.localNetwork == "lan") { };
renderer.hidePhysicalConnections = true; wgProxy = lib.mkIf (config.swarselsystems.server.wireguard ? wgHome) {
virtual = true; addresses = [ globals.networks."${webProxy}-wg.hosts".${config.node.name}.ipv4 ];
type = "wireguard"; renderer.hidePhysicalConnections = true;
virtual = true;
type = "wireguard";
};
wgHome = lib.mkIf (config.swarselsystems.server.wireguard ? wgHome) {
addresses = [ globals.networks.home-wgHome.hosts.${config.node.name}.ipv4 ];
renderer.hidePhysicalConnections = true;
virtual = true;
type = "wireguard";
};
}; };
}; };
} }

View file

@ -0,0 +1,13 @@
{ lib, config, ... }:
{
networking = {
useDHCP = lib.mkForce false;
useNetworkd = true;
dhcpcd.enable = lib.mkIf (!config.swarselsystems.isMicroVM) false;
renameInterfacesByMac = lib.mkIf (!config.swarselsystems.isMicroVM) (lib.mapAttrs (_: v: if (v ? mac) then v.mac else "") (
config.repo.secrets.local.networking.networks or { }
));
};
systemd.network.enable = true;
}

View file

@ -0,0 +1,131 @@
{ self, lib, config, globals, ... }:
let
inherit (globals.general) routerServer;
inherit (config.swarselsystems) withMicroVMs isCrypted initrdVLAN;
isRouter = config.node.name == routerServer;
localVLANsList = config.swarselsystems.localVLANs;
localVLANs = lib.genAttrs localVLANsList (x: globals.networks.home-lan.vlans.${x});
in
{
imports = [
"${self}/modules/nixos/optional/systemd-networkd-server.nix"
];
config = {
assertions = [
{
assertion = ((localVLANsList != [ ]) && (initrdVLAN != null)) || (localVLANsList == [ ]) || (!isCrypted);
message = "This host uses VLANs and disk encryption, thus a VLAN must be specified for initrd or disk encryption must be removed.";
}
];
boot.initrd = lib.mkIf (isCrypted && (localVLANsList != [ ]) && (!isRouter)) {
availableKernelModules = [ "8021q" ];
systemd.network = {
enable = true;
netdevs."30-vlan-${initrdVLAN}" = {
netdevConfig = {
Kind = "vlan";
Name = "vlan-${initrdVLAN}";
};
vlanConfig.Id = globals.networks.home-lan.vlans.${initrdVLAN}.id;
};
networks = {
"10-lan" = {
matchConfig.Name = "lan";
# This interface should only be used from attached vlans.
# So don't acquire a link local address and only wait for
# this interface to gain a carrier.
networkConfig.LinkLocalAddressing = "no";
linkConfig.RequiredForOnline = "carrier";
vlan = [ "vlan-${initrdVLAN}" ];
};
"30-vlan-${initrdVLAN}" = {
address = [
globals.networks.home-lan.vlans.${initrdVLAN}.hosts.${config.node.name}.cidrv4
globals.networks.home-lan.vlans.${initrdVLAN}.hosts.${config.node.name}.cidrv6
];
matchConfig.Name = "vlan-${initrdVLAN}";
networkConfig = {
IPv6PrivacyExtensions = "yes";
};
linkConfig.RequiredForOnline = "routable";
};
};
};
};
systemd.network = {
netdevs = lib.flip lib.concatMapAttrs localVLANs (
vlanName: vlanCfg: {
"30-vlan-${vlanName}" = {
netdevConfig = {
Kind = "vlan";
Name = "vlan-${vlanName}";
};
vlanConfig.Id = vlanCfg.id;
};
# Create a MACVTAP for ourselves too, so that we can communicate with
# our guests on the same interface.
"40-me-${vlanName}" = lib.mkIf withMicroVMs {
netdevConfig = {
Name = "me-${vlanName}";
Kind = "macvlan";
};
extraConfig = ''
[MACVLAN]
Mode=bridge
'';
};
}
);
networks = {
"10-lan" = lib.mkIf (!isRouter) {
matchConfig.Name = "lan";
# This interface should only be used from attached vlans.
# So don't acquire a link local address and only wait for
# this interface to gain a carrier.
networkConfig.LinkLocalAddressing = "no";
linkConfig.RequiredForOnline = "carrier";
vlan = (map (name: "vlan-${name}") (builtins.attrNames localVLANs));
};
# Remaining macvtap interfaces should not be touched.
"90-macvtap-ignore" = lib.mkIf withMicroVMs {
matchConfig.Kind = "macvtap";
linkConfig.ActivationPolicy = "manual";
linkConfig.Unmanaged = "yes";
};
}
// lib.flip lib.concatMapAttrs localVLANs (
vlanName: vlanCfg:
let
me = {
address = [
vlanCfg.hosts.${config.node.name}.cidrv4
vlanCfg.hosts.${config.node.name}.cidrv6
];
gateway = lib.optionals (vlanName == "services") [ vlanCfg.hosts.${routerServer}.ipv4 vlanCfg.hosts.${routerServer}.ipv6 ];
matchConfig.Name = "${if withMicroVMs then "me" else "vlan"}-${vlanName}";
networkConfig.IPv6PrivacyExtensions = "yes";
linkConfig.RequiredForOnline = "routable";
};
in
{
"30-vlan-${vlanName}" = if (!withMicroVMs) then me else {
matchConfig.Name = "vlan-${vlanName}";
# This interface should only be used from attached macvlans.
# So don't acquire a link local address and only wait for
# this interface to gain a carrier.
networkConfig.LinkLocalAddressing = "no";
networkConfig.MACVLAN = "me-${vlanName}";
linkConfig.RequiredForOnline = if isRouter then "no" else "carrier";
};
"40-me-${vlanName}" = lib.mkIf withMicroVMs (lib.mkDefault me);
}
);
};
};
}

View file

@ -1,28 +1,30 @@
{ lib, config, globals, ... }: { self, lib, config, globals, ... }:
let
inherit (config.swarselsystems) isCrypted localVLANs;
inherit (globals.general) routerServer;
isRouter = config.node.name == routerServer;
ifName = config.swarselsystems.server.localNetwork;
in
{ {
networking = { imports = [
useDHCP = lib.mkForce false; "${self}/modules/nixos/optional/systemd-networkd-base.nix"
useNetworkd = true; ];
dhcpcd.enable = false;
renameInterfacesByMac = lib.mapAttrs (_: v: if (v ? mac) then v.mac else "") ( boot.initrd.systemd.network = lib.mkIf (isCrypted && ((localVLANs == [ ]) || isRouter)) {
config.repo.secrets.local.networking.networks or { }
);
};
boot.initrd.systemd.network = {
enable = true; enable = true;
networks."10-${config.swarselsystems.server.localNetwork}" = config.systemd.network.networks."10-${config.swarselsystems.server.localNetwork}"; networks."10-${ifName}" = config.systemd.network.networks."10-${ifName}";
}; };
systemd = { systemd = {
network = { network = {
enable = true;
wait-online.enable = false; wait-online.enable = false;
networks = networks =
let let
netConfig = config.repo.secrets.local.networking; netConfig = config.repo.secrets.local.networking;
in in
{ {
"10-${config.swarselsystems.server.localNetwork}" = { "10-${ifName}" = lib.mkIf (isRouter || (localVLANs == [ ])) {
address = [ address = [
"${globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.cidrv4}" "${globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.cidrv4}"
"${globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.cidrv6}" "${globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.cidrv6}"

View file

@ -1,116 +0,0 @@
{ lib, config, globals, ... }:
{
systemd.network = {
wait-online.anyInterface = true;
netdevs = {
"10-veth" = {
netdevConfig = {
Kind = "veth";
Name = "veth-br";
};
peerConfig = {
Name = "veth-int";
};
};
"20-br" = {
netdevConfig = {
Kind = "bridge";
Name = "br";
};
};
} // lib.flip lib.concatMapAttrs globals.networks.home-lan.vlans (
vlanName: vlanCfg: {
"30-vlan-${vlanName}" = {
netdevConfig = {
Kind = "vlan";
Name = "vlan-${vlanName}";
};
vlanConfig.Id = vlanCfg.id;
};
"40-me-${vlanName}" = {
netdevConfig = {
Name = "me-${vlanName}";
Kind = "macvlan";
};
extraConfig = ''
[MACVLAN]
Mode=bridge
'';
};
}
);
networks = {
"40-br" = {
matchConfig.Name = "br";
bridgeConfig = { };
linkConfig = {
ActivationPolicy = "always-up";
RequiredForOnline = "no";
};
networkConfig = {
ConfigureWithoutCarrier = true;
LinkLocalAddressing = "no";
};
};
"15-veth-br" = {
matchConfig.Name = "veth-br";
linkConfig = {
RequiredForOnline = "no";
};
networkConfig = {
Bridge = "br";
};
};
"15-veth-int" = {
matchConfig.Name = "veth-int";
linkConfig = {
ActivationPolicy = "always-up";
RequiredForOnline = "no";
};
networkConfig = {
ConfigureWithoutCarrier = true;
LinkLocalAddressing = "no";
};
vlan = map (name: "vlan-${name}") (builtins.attrNames globals.networks.home-lan.vlans);
};
"90-macvtap-ignore" = {
matchConfig.Kind = "macvtap";
linkConfig.ActivationPolicy = "manual";
linkConfig.Unmanaged = "yes";
};
} // lib.flip lib.concatMapAttrs globals.networks.home-lan.vlans (
vlanName: vlanCfg: {
"30-vlan-${vlanName}" = {
matchConfig.Name = "vlan-${vlanName}";
networkConfig.LinkLocalAddressing = "no";
networkConfig.MACVLAN = "me-${vlanName}";
linkConfig.RequiredForOnline = "no";
};
"40-me-${vlanName}" = {
address = [
vlanCfg.hosts.${config.node.name}.cidrv4
vlanCfg.hosts.${config.node.name}.cidrv6
];
matchConfig.Name = "me-${vlanName}";
networkConfig = {
IPv4Forwarding = "yes";
IPv6PrivacyExtensions = "yes";
IPv6SendRA = true;
IPv6AcceptRA = false;
};
ipv6Prefixes = [
{ Prefix = vlanCfg.cidrv6; }
];
linkConfig.RequiredForOnline = "routable";
};
}
);
};
}

View file

@ -0,0 +1,138 @@
{ self, inputs, lib, config, globals, dns, confLib, ... }:
let
inherit (confLib.gen { name = "adguardhome"; port = 3000; }) serviceName servicePort serviceAddress serviceDomain proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied homeProxy homeProxyIf webProxy webProxyIf homeWebProxy dnsServer homeDnsServer homeServiceAddress nginxAccessRules;
homeServices = lib.attrNames (lib.filterAttrs (_: serviceCfg: serviceCfg.isHome) globals.services);
homeDomains = map (name: globals.services.${name}.domain) homeServices;
in
{
options = {
swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
};
config = lib.mkIf config.swarselmodules.server.${serviceName} {
globals = {
networks = {
${webProxyIf}.hosts = lib.mkIf isProxied {
${config.node.name}.firewallRuleForNode.${webProxy}.allowedTCPPorts = [ servicePort ];
};
${homeProxyIf}.hosts = lib.mkIf isHome {
${config.node.name}.firewallRuleForNode.${homeProxy}.allowedTCPPorts = [ servicePort ];
};
};
services.${serviceName} = {
domain = serviceDomain;
inherit proxyAddress4 proxyAddress6 isHome;
};
};
networking.firewall = {
allowedTCPPorts = [ 53 ];
allowedUDPPorts = [ 53 ];
};
services.adguardhome = {
enable = true;
mutableSettings = false;
host = "0.0.0.0";
port = servicePort;
settings = {
dns = {
bind_hosts = [
globals.networks.home-lan.vlans.services.hosts.${homeDnsServer}.ipv4
globals.networks.home-lan.vlans.services.hosts.${homeDnsServer}.ipv6
];
ratelimit = 300;
upstream_dns = [
"https://dns.cloudflare.com/dns-query"
"https://dns.google/dns-query"
"https://doh.mullvad.net/dns-query"
];
bootstrap_dns = [
"1.1.1.1"
"2606:4700:4700::1111"
"8.8.8.8"
"2001:4860:4860::8844"
];
dhcp.enabled = false;
};
filtering.rewrites = [
]
# Use the local mirror-proxy for some services (not necessary, just for speed)
++
map
(domain: {
inherit domain;
# FIXME: change to homeWebProxy once that is setup
answer = globals.networks.home-lan.vlans.services.hosts.${homeWebProxy}.ipv4;
# answer = globals.hosts.${webProxy}.wanAddress4;
})
homeDomains;
filters = [
{
name = "AdGuard DNS filter";
url = "https://adguardteam.github.io/AdGuardSDNSFilter/Filters/filter.txt";
enabled = true;
}
{
name = "AdAway Default Blocklist";
url = "https://adaway.org/hosts.txt";
enabled = true;
}
{
name = "OISD (Big)";
url = "https://big.oisd.nl";
enabled = true;
}
];
};
};
environment.persistence."/persist".directories = lib.mkIf config.swarselsystems.isImpermanence [
{
directory = "/var/lib/private/AdGuardHome";
mode = "0700";
}
];
nodes =
let
genNginx = toAddress: extraConfig: {
upstreams = {
${serviceName} = {
servers = {
"${toAddress}:${builtins.toString servicePort}" = { };
};
};
};
virtualHosts = {
"${serviceDomain}" = {
useACMEHost = globals.domains.main;
forceSSL = true;
acmeRoot = null;
oauth2 = {
enable = true;
allowedGroups = [ "adguardhome_access" ];
};
locations = {
"/" = {
proxyPass = "http://${serviceName}";
proxyWebsockets = true;
};
};
extraConfig = lib.mkIf (extraConfig != "") extraConfig;
};
};
};
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = genNginx serviceAddress "";
${homeWebProxy}.services.nginx = genNginx homeServiceAddress nginxAccessRules;
};
};
}

View file

@ -14,6 +14,12 @@ in
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
}; };
topology.self.services.${serviceName} = {
name = lib.swarselsystems.toCapitalized serviceName;
info = "https://${serviceDomain}";
# attic does not have a logo
};
globals = { globals = {
networks = { networks = {
${webProxyIf}.hosts = lib.mkIf isProxied { ${webProxyIf}.hosts = lib.mkIf isProxied {

View file

@ -4,6 +4,9 @@ let
subnetMask = globals.networks.${config.swarselsystems.server.netConfigName}.subnetMask4; subnetMask = globals.networks.${config.swarselsystems.server.netConfigName}.subnetMask4;
gatewayIp = globals.hosts.${config.node.name}.defaultGateway4; gatewayIp = globals.hosts.${config.node.name}.defaultGateway4;
inherit (globals.general) routerServer;
isRouter = config.node.name == routerServer;
hostKeyPathBase = "/etc/secrets/initrd/ssh_host_ed25519_key"; hostKeyPathBase = "/etc/secrets/initrd/ssh_host_ed25519_key";
hostKeyPath = hostKeyPath =
if config.swarselsystems.isImpermanence then if config.swarselsystems.isImpermanence then
@ -42,7 +45,7 @@ in
}; };
boot = lib.mkIf (!config.swarselsystems.isClient) { boot = lib.mkIf (!config.swarselsystems.isClient) {
kernelParams = lib.mkIf (!config.swarselsystems.isCloud) [ kernelParams = lib.mkIf (!config.swarselsystems.isCloud && ((config.swarselsystems.localVLANs == [ ]) || isRouter)) [
"ip=${localIp}::${gatewayIp}:${subnetMask}:${config.networking.hostName}::none" "ip=${localIp}::${gatewayIp}:${subnetMask}:${config.networking.hostName}::none"
]; ];
initrd = { initrd = {

View file

@ -0,0 +1,16 @@
{ lib, config, globals, confLib, ... }:
let
inherit (confLib.gen { name = "dns-home"; }) serviceName homeProxy;
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
config = lib.mkIf (config.swarselmodules.server.${serviceName}) {
networking.hosts = {
${globals.networks.home-lan.vlans.services.hosts.${homeProxy}.ipv4} = [ "server.${homeProxy}.${globals.domains.main}" ];
${globals.networks.home-lan.vlans.services.hosts.${homeProxy}.ipv6} = [ "server.${homeProxy}.${globals.domains.main}" ];
};
};
}

View file

@ -1,4 +1,4 @@
{ lib, pkgs, config, globals, confLib, dns, nodes, ... }: { self, lib, pkgs, config, globals, confLib, dns, nodes, ... }:
let let
inherit (confLib.gen { name = "firezone"; dir = "/var/lib/private/firezone"; }) serviceName serviceDir serviceAddress serviceDomain proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy homeProxyIf webProxyIf idmServer dnsServer; inherit (confLib.gen { name = "firezone"; dir = "/var/lib/private/firezone"; }) serviceName serviceDir serviceAddress serviceDomain proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy homeProxyIf webProxyIf idmServer dnsServer;
inherit (config.swarselsystems) sopsFile; inherit (config.swarselsystems) sopsFile;
@ -60,6 +60,12 @@ in
}; };
}; };
topology.self.services.${serviceName} = {
name = lib.swarselsystems.toCapitalized serviceName;
info = "https://${serviceDomain}";
icon = "${self}/files/topology-images/${serviceName}.png";
};
sops = { sops = {
secrets = { secrets = {
kanidm-firezone-client = { inherit sopsFile; mode = "0400"; }; kanidm-firezone-client = { inherit sopsFile; mode = "0400"; };
@ -314,12 +320,17 @@ in
}; };
services.firezone.gateway = { services.firezone.gateway = {
enable = true; enable = true;
logLevel = "trace"; # logLevel = "trace";
inherit (nodeCfg.node) name; inherit (nodeCfg.node) name;
apiUrl = "wss://${globals.services.firezone.domain}/api/"; apiUrl = "wss://${globals.services.firezone.domain}/api/";
tokenFile = nodeCfg.sops.secrets.firezone-gateway-token.path; tokenFile = nodeCfg.sops.secrets.firezone-gateway-token.path;
package = nodePkgs.stable25_05.firezone-gateway; # newer versions of firezone-gateway are not compatible with server package package = nodePkgs.stable25_05.firezone-gateway; # newer versions of firezone-gateway are not compatible with server package
}; };
topology.self.services."${serviceName}-gateway" = {
name = lib.swarselsystems.toCapitalized "${serviceName} Gateway";
icon = "${self}/files/topology-images/${serviceName}.png";
};
}; };
${idmServer} = ${idmServer} =
let let

View file

@ -1,5 +1,5 @@
# inspired by https://github.com/atropos112/nixos/blob/7fef652006a1c939f4caf9c8a0cb0892d9cdfe21/modules/garage.nix # inspired by https://github.com/atropos112/nixos/blob/7fef652006a1c939f4caf9c8a0cb0892d9cdfe21/modules/garage.nix
{ lib, pkgs, config, globals, dns, confLib, ... }: { self, lib, pkgs, config, globals, dns, confLib, ... }:
let let
inherit (confLib.gen { inherit (confLib.gen {
name = "garage"; name = "garage";
@ -81,6 +81,12 @@ in
"*.${subDomain}-web" = dns.lib.combinators.host proxyAddress4 proxyAddress6; "*.${subDomain}-web" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
}; };
topology.self.services.${serviceName} = {
name = lib.swarselsystems.toCapitalized serviceName;
info = "https://${serviceDomain}";
icon = "${self}/files/topology-images/${serviceName}.png";
};
sops = { sops = {
secrets.garage-admin-token = { inherit sopsFile; }; secrets.garage-admin-token = { inherit sopsFile; };
secrets.garage-rpc-secret = { inherit sopsFile; }; secrets.garage-rpc-secret = { inherit sopsFile; };

View file

@ -1,4 +1,4 @@
{ lib, pkgs, config, globals, dns, confLib, ... }: { self, lib, pkgs, config, globals, dns, confLib, ... }:
let let
inherit (confLib.gen { name = "homebox"; port = 7745; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf; inherit (confLib.gen { name = "homebox"; port = 7745; }) servicePort serviceName serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf;
in in
@ -10,7 +10,11 @@ in
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
}; };
topology.self.services.${serviceName}.info = "https://${serviceDomain}"; topology.self.services.${serviceName} = {
name = "Homebox";
info = "https://${serviceDomain}";
icon = "${self}/files/topology-images/${serviceName}.png";
};
globals = { globals = {
networks = { networks = {

View file

@ -13,6 +13,8 @@ in
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
}; };
topology.self.services.${serviceName}.info = "https://${serviceDomain}";
globals = { globals = {
networks = { networks = {
${webProxyIf}.hosts = lib.mkIf isProxied { ${webProxyIf}.hosts = lib.mkIf isProxied {

View file

@ -228,6 +228,7 @@ in
"radicale.access" = { }; "radicale.access" = { };
"slink.access" = { }; "slink.access" = { };
"opkssh.access" = { }; "opkssh.access" = { };
"adguardhome.access" = { };
}; };
inherit (config.repo.secrets.local) persons; inherit (config.repo.secrets.local) persons;
@ -370,6 +371,11 @@ in
"email" "email"
"profile" "profile"
]; ];
"adguardhome.access" = [
"openid"
"email"
"profile"
];
}; };
preferShortUsername = true; preferShortUsername = true;
claimMaps.groups = { claimMaps.groups = {
@ -380,6 +386,7 @@ in
"firefly.access" = [ "firefly_access" ]; "firefly.access" = [ "firefly_access" ];
"radicale.access" = [ "radicale_access" ]; "radicale.access" = [ "radicale_access" ];
"slink.access" = [ "slink_access" ]; "slink.access" = [ "slink_access" ];
"adguardhome.access" = [ "adguardhome_access" ];
}; };
}; };
}; };

View file

@ -62,7 +62,6 @@ in
virtualHosts = { virtualHosts = {
"${serviceDomain}" = { "${serviceDomain}" = {
useACMEHost = globals.domains.main; useACMEHost = globals.domains.main;
forceSSL = true; forceSSL = true;
acmeRoot = null; acmeRoot = null;
locations = { locations = {

View file

@ -1,6 +1,75 @@
{ lib, config, globals, confLib, ... }: { self, lib, config, globals, confLib, ... }:
let let
inherit (confLib.gen { name = "kea"; dir = "/var/lib/private/kea"; }) serviceName serviceDir; inherit (confLib.gen { name = "kea"; dir = "/var/lib/private/kea"; }) serviceName serviceDir homeDnsServer;
dhcpX = intX:
let
x = builtins.toString intX;
in
{
enable = true;
settings = {
reservations-out-of-pool = true;
lease-database = {
name = "/var/lib/kea/dhcp${x}.leases";
persist = true;
type = "memfile";
};
valid-lifetime = 86400;
renew-timer = 3600;
interfaces-config = {
interfaces = map (name: "me-${name}") (builtins.attrNames globals.networks.home-lan.vlans);
service-sockets-max-retries = -1;
};
"subnet${x}" = lib.flip lib.mapAttrsToList globals.networks.home-lan.vlans (
vlanName: vlanCfg: {
inherit (vlanCfg) id;
interface = "me-${vlanName}";
subnet = vlanCfg."cidrv${x}";
rapid-commit = lib.mkIf (intX == 6) true;
pools = [
{
pool = "${lib.net.cidr.host 20 vlanCfg."cidrv${x}"} - ${lib.net.cidr.host (-6) vlanCfg."cidrv${x}"}";
}
];
pd-pools = lib.mkIf (intX == 6) [
{
prefix = builtins.replaceStrings [ "::" ] [ ":0:0:100::" ] (lib.head (lib.splitString "/" vlanCfg.cidrv6));
prefix-len = 56;
delegated-len = 64;
}
];
option-data =
lib.optional (intX == 4)
{
name = "routers";
data = vlanCfg.hosts.hintbooth."ipv${x}";
}
# Advertise DNS server for VLANS that have internet access
++
lib.optional
(lib.elem vlanName globals.general.internetVLANs)
{
name = if (intX == 4) then "domain-name-servers" else "dns-servers";
data = globals.networks.home-lan.vlans.services.hosts.${homeDnsServer}."ipv${x}";
};
reservations = lib.concatLists (
lib.forEach (builtins.attrValues vlanCfg.hosts) (
hostCfg:
lib.optional (hostCfg.mac != null) {
hw-address = lib.mkIf (intX == 4) hostCfg.mac;
duid = lib.mkIf (intX == 6) "00:03:00:01:${hostCfg.mac}"; # 00:03 = duid type 3; 00:01 = ethernet
ip-address = lib.mkIf (intX == 4) hostCfg."ipv${x}";
ip-addresses = lib.mkIf (intX == 6) [ hostCfg."ipv${x}" ];
prefixes = lib.mkIf (intX == 6) [
"${builtins.replaceStrings ["::"] [":0:0:${builtins.toString (256 + hostCfg.id)}::"] (lib.head (lib.splitString "/" vlanCfg.cidrv6))}/64"
];
}
)
);
}
);
};
};
in in
{ {
options = { options = {
@ -12,65 +81,18 @@ in
{ directory = serviceDir; mode = "0700"; } { directory = serviceDir; mode = "0700"; }
]; ];
services.kea.dhcp4 = { topology = {
enable = true; extractors.kea.enable = false;
settings = { self.services.${serviceName} = {
lease-database = { name = lib.swarselsystems.toCapitalized serviceName;
name = "/var/lib/kea/dhcp4.leases"; icon = "${self}/files/topology-images/${serviceName}.png";
persist = true;
type = "memfile";
};
valid-lifetime = 86400;
renew-timer = 3600;
interfaces-config = {
# XXX: BUG: why does this bind other macvtaps?
interfaces = map (name: "me-${name}") (builtins.attrNames globals.networks.home-lan.vlans);
service-sockets-max-retries = -1;
};
subnet4 = lib.flip lib.mapAttrsToList globals.networks.home-lan.vlans (
vlanName: vlanCfg: {
inherit (vlanCfg) id;
interface = "me-${vlanName}";
subnet = vlanCfg.cidrv4;
pools = [
{
pool = "${lib.net.cidr.host 20 vlanCfg.cidrv4} - ${lib.net.cidr.host (-6) vlanCfg.cidrv4}";
}
];
option-data =
[
{
name = "routers";
data = vlanCfg.hosts.hintbooth.ipv4; # FIXME: how to advertise v6 address also?
}
];
# Advertise DNS server for VLANS that have internet access
# ++
# lib.optional
# (lib.elem vlanName [
# "services"
# "home"
# "devices"
# "guests"
# ])
# {
# name = "domain-name-servers";
# data = globals.networks.home-lan.vlans.services.hosts.hintbooth-adguardhome.ipv4;
# };
reservations = lib.concatLists (
lib.forEach (builtins.attrValues vlanCfg.hosts) (
hostCfg:
lib.optional (hostCfg.mac != null) {
hw-address = hostCfg.mac;
ip-address = hostCfg.ipv4;
}
)
);
}
);
}; };
}; };
services.kea = {
dhcp4 = dhcpX 4;
dhcp6 = dhcpX 6;
};
}; };
} }

View file

@ -13,6 +13,10 @@ in
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
config = lib.mkIf config.swarselmodules.server.${serviceName} { config = lib.mkIf config.swarselmodules.server.${serviceName} {
swarselmodules.server = {
podman = true;
postgresql = true;
};
nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;

View file

@ -1,4 +1,4 @@
{ lib, config, globals, dns, confLib, ... }: { self, lib, config, globals, dns, confLib, ... }:
let let
inherit (config.swarselsystems) sopsFile; inherit (config.swarselsystems) sopsFile;
inherit (confLib.gen { name = "mailserver"; dir = "/var/lib/dovecot"; user = "virtualMail"; group = "virtualMail"; port = 443; }) serviceName serviceDir servicePort serviceUser serviceGroup serviceAddress serviceDomain proxyAddress4 proxyAddress6 isHome webProxy dnsServer; inherit (confLib.gen { name = "mailserver"; dir = "/var/lib/dovecot"; user = "virtualMail"; group = "virtualMail"; port = 443; }) serviceName serviceDir servicePort serviceUser serviceGroup serviceAddress serviceDomain proxyAddress4 proxyAddress6 isHome webProxy dnsServer;
@ -32,6 +32,16 @@ in
}; };
}; };
topology.self.services = lib.listToAttrs (map
(service:
lib.nameValuePair "${service}" {
name = lib.swarselsystems.toCapitalized service;
info = lib.mkIf (service == "postfix" || service == "roundcube") (if service == "postfix" then "https://${serviceDomain}" else "https://${roundcubeDomain}");
icon = "${self}/files/topology-images/${service}.png";
}
)
[ "postfix" "dovecot" "rspamd" "clamav" "roundcube" ]);
sops.secrets = { sops.secrets = {
user1-hashed-pw = { inherit sopsFile; owner = serviceUser; }; user1-hashed-pw = { inherit sopsFile; owner = serviceUser; };
user2-hashed-pw = { inherit sopsFile; owner = serviceUser; }; user2-hashed-pw = { inherit sopsFile; owner = serviceUser; };

View file

@ -1,4 +1,4 @@
{ lib, config, pkgs, globals, dns, confLib, ... }: { self, lib, config, pkgs, globals, dns, confLib, ... }:
let let
inherit (confLib.gen { name = "minecraft"; port = 25565; dir = "/opt/minecraft"; proxy = config.node.name; }) serviceName servicePort serviceDir serviceDomain proxyAddress4 proxyAddress6 isHome dnsServer; inherit (confLib.gen { name = "minecraft"; port = 25565; dir = "/opt/minecraft"; proxy = config.node.name; }) serviceName servicePort serviceDir serviceDomain proxyAddress4 proxyAddress6 isHome dnsServer;
inherit (config.swarselsystems) mainUser; inherit (config.swarselsystems) mainUser;
@ -12,7 +12,11 @@ in
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
}; };
topology.self.services.${serviceName}.info = "https://${serviceDomain}"; topology.self.services.${serviceName} = {
name = "Minecraft";
info = "https://${serviceDomain}";
icon = "${self}/files/topology-images/${serviceName}.png";
};
globals.services.${serviceName} = { globals.services.${serviceName} = {
domain = serviceDomain; domain = serviceDomain;

View file

@ -16,6 +16,8 @@ in
mpv mpv
]; ];
topology.self.services.${serviceName}.info = "https://${serviceDomain}";
users = { users = {
groups = { groups = {
${serviceGroup} = { ${serviceGroup} = {

View file

@ -2,7 +2,6 @@
let let
netConfig = config.repo.secrets.local.networking; netConfig = config.repo.secrets.local.networking;
netPrefix = "${if config.swarselsystems.isCloud then config.node.name else "home"}"; netPrefix = "${if config.swarselsystems.isCloud then config.node.name else "home"}";
# netName = "${netPrefix}-${config.swarselsystems.server.localNetwork}";
in in
{ {
options = { options = {
@ -28,11 +27,6 @@ in
swarselsystems.server.localNetwork = netConfig.localNetwork or ""; swarselsystems.server.localNetwork = netConfig.localNetwork or "";
# globals.networks.${netName}.hosts.${config.node.name} = {
# inherit (netConfig.networks.${netConfig.localNetwork}) id;
# mac = netConfig.networks.${netConfig.localNetwork}.mac or null;
# };
globals.networks = lib.mapAttrs' globals.networks = lib.mapAttrs'
(netName: _: (netName: _:
lib.nameValuePair "${netPrefix}-${netName}" { lib.nameValuePair "${netPrefix}-${netName}" {
@ -45,7 +39,8 @@ in
netConfig.networks; netConfig.networks;
globals.hosts.${config.node.name} = { globals.hosts.${config.node.name} = {
inherit (config.repo.secrets.local.networking) defaultGateway4; defaultGateway4 = netConfig.defaultGateway4 or null;
defaultGateway6 = netConfig.defaultGateway6 or null;
wanAddress4 = netConfig.wanAddress4 or null; wanAddress4 = netConfig.wanAddress4 or null;
wanAddress6 = netConfig.wanAddress6 or null; wanAddress6 = netConfig.wanAddress6 or null;
isHome = if (netPrefix == "home") then true else false; isHome = if (netPrefix == "home") then true else false;

View file

@ -40,6 +40,7 @@ in
nnf-drop.enable = true; nnf-drop.enable = true;
nnf-loopback.enable = true; nnf-loopback.enable = true;
nnf-ssh.enable = true; nnf-ssh.enable = true;
nnf-dhcpv6.enable = true;
}; };
rules.untrusted-to-local = { rules.untrusted-to-local = {

View file

@ -67,7 +67,7 @@ in
}; };
}; };
config = { config = {
extraConfig = lib.mkIf topmod.config.defaultStapling (lib.mkAfter '' extraConfig = lib.mkIf topmod.config.defaultStapling (lib.mkBefore ''
ssl_stapling on; ssl_stapling on;
ssl_stapling_verify on; ssl_stapling_verify on;
resolver 1.1.1.1 8.8.8.8 valid=300s; resolver 1.1.1.1 8.8.8.8 valid=300s;

View file

@ -1,4 +1,4 @@
{ lib, config, globals, dns, confLib, ... }: { self, lib, config, globals, dns, confLib, ... }:
let let
inherit (confLib.gen { name = "nsd"; port = 53; }) serviceName servicePort proxyAddress4 proxyAddress6; inherit (confLib.gen { name = "nsd"; port = 53; }) serviceName servicePort proxyAddress4 proxyAddress6;
inherit (config.swarselsystems) sopsFile; inherit (config.swarselsystems) sopsFile;
@ -34,6 +34,11 @@ in
}; };
}; };
topology.self.services.${serviceName} = {
name = lib.toUpper serviceName;
icon = "${self}/files/topology-images/${serviceName}.png";
};
services.nsd = { services.nsd = {
enable = true; enable = true;
keys = { keys = {

View file

@ -3,7 +3,7 @@ with dns.lib.combinators; {
SOA = { SOA = {
nameServer = "soa"; nameServer = "soa";
adminEmail = "admin@${globals.domains.main}"; # this option is not parsed as domain (we cannot just write "admin") adminEmail = "admin@${globals.domains.main}"; # this option is not parsed as domain (we cannot just write "admin")
serial = 2025122401; # update this on changes for secondary dns serial = 2026010201; # update this on changes for secondary dns
}; };
useOrigin = false; useOrigin = false;

View file

@ -1,6 +1,7 @@
{ lib, config, globals, dns, confLib, ... }: { lib, config, globals, dns, confLib, ... }:
let let
inherit (confLib.gen { name = "oauth2-proxy"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6 isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf; inherit (confLib.gen { name = "oauth2-proxy"; port = 3004; }) servicePort serviceName serviceUser serviceGroup serviceDomain serviceAddress proxyAddress4 proxyAddress6;
inherit (confLib.static) isHome isProxied homeProxy webProxy dnsServer homeProxyIf webProxyIf homeWebProxy oauthServer nginxAccessRules;
kanidmDomain = globals.services.kanidm.domain; kanidmDomain = globals.services.kanidm.domain;
mainDomain = globals.domains.main; mainDomain = globals.domains.main;
@ -119,10 +120,6 @@ in
}; };
config = lib.mkIf config.swarselmodules.server.${serviceName} { config = lib.mkIf config.swarselmodules.server.${serviceName} {
nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
sops = { sops = {
secrets = { secrets = {
"oauth2-cookie-secret" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; }; "oauth2-cookie-secret" = { inherit sopsFile; owner = serviceUser; group = serviceGroup; mode = "0440"; };
@ -208,31 +205,41 @@ in
}; };
}; };
nodes.${webProxy}.services.nginx = { nodes =
upstreams = { let
${serviceName} = { genNginx = toAddress: extraConfig: {
servers = { upstreams = {
"${serviceAddress}:${builtins.toString servicePort}" = { }; ${serviceName} = {
}; servers = {
}; "${toAddress}:${builtins.toString servicePort}" = { };
}; };
virtualHosts = { };
"${serviceDomain}" = { };
useACMEHost = globals.domains.main; virtualHosts = {
"${serviceDomain}" = {
forceSSL = true; useACMEHost = globals.domains.main;
acmeRoot = null;
locations = { forceSSL = true;
"/" = { acmeRoot = null;
proxyPass = "http://${serviceName}"; locations = {
"/" = {
proxyPass = "http://${serviceName}";
};
};
extraConfig = ''
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
'' + lib.optionalString (extraConfig != "") extraConfig;
}; };
}; };
extraConfig = ''
proxy_set_header X-Scheme $scheme;
proxy_set_header X-Auth-Request-Redirect $scheme://$host$request_uri;
'';
}; };
in
{
${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
};
${webProxy}.services.nginx = genNginx serviceAddress "";
${homeWebProxy}.services.nginx = genNginx globals.hosts.${oauthServer}.wanAddress4 nginxAccessRules;
}; };
};
}; };
} }

View file

@ -11,6 +11,7 @@ in
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
config = lib.mkIf config.swarselmodules.server.${serviceName} { config = lib.mkIf config.swarselmodules.server.${serviceName} {
services.${serviceName} = { services.${serviceName} = {
enable = true; enable = true;
user = serviceUser; user = serviceUser;

View file

@ -13,6 +13,8 @@
sops sops
tmux tmux
busybox busybox
ndisc6
tcpdump
swarsel-deploy swarsel-deploy
] ++ lib.optionals withHomeManager [ ] ++ lib.optionals withHomeManager [
swarsel-gens swarsel-gens

View file

@ -0,0 +1,38 @@
{ config, lib, ... }:
let
serviceName = "podman";
in
{
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
config = lib.mkIf config.swarselmodules.server.${serviceName} {
virtualisation = {
podman.enable = true;
oci-containers.backend = "podman";
};
networking.nftables.firewall = lib.mkIf config.networking.nftables.enable {
zones.podman = {
interfaces = [ "podman0" ];
};
rules = {
podman-to-postgres = lib.mkIf config.services.postgresql.enable {
from = [ "podman" ];
to = [ "local" ];
before = [ "drop" ];
allowedTCPPorts = [ config.services.postgresql.settings.port ];
};
local-to-podman = {
from = [ "local" "wgProxy" "wgHme" ];
to = [ "podman" ];
before = [ "drop" ];
verdict = "accept";
};
};
};
};
}

View file

@ -1,6 +1,15 @@
{ lib, config, globals, ... }: { lib, config, globals, confLib, ... }:
let let
serviceName = "router"; serviceName = "router";
bridgeVLANs = lib.mapAttrsToList
(_: vlan: {
VLAN = vlan.id;
})
globals.networks.home-lan.vlans;
selectVLANs = vlans: map (vlan: { VLAN = globals.networks.home-lan.vlans.${vlan}.id; }) vlans;
lan5VLANs = selectVLANs [ "home" "devices" "guests" ];
lan4VLANs = selectVLANs [ "home" "services" ];
inherit (confLib.gen { }) homeDnsServer;
in in
{ {
options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server"; options.swarselmodules.server.${serviceName} = lib.mkEnableOption "enable ${serviceName} on server";
@ -8,13 +17,27 @@ in
{ {
services.avahi.reflector = true; services.avahi.reflector = true;
topology.self.interfaces = (lib.mapAttrs'
(vlanName: _:
lib.nameValuePair "vlan-${vlanName}" {
network = lib.mkForce vlanName;
}
)
globals.networks.home-lan.vlans) // (lib.mapAttrs'
(vlanName: _:
lib.nameValuePair "me-${vlanName}" {
network = lib.mkForce vlanName;
}
)
globals.networks.home-lan.vlans);
networking.nftables = { networking.nftables = {
firewall = { firewall = {
zones = { zones = {
untrusted.interfaces = [ "lan" ]; untrusted.interfaces = [ "lan" ];
wgHome.interfaces = [ "wgHome" ]; wgHome.interfaces = [ "wgHome" ];
adguardhome.ipv4Addresses = [ globals.networks.home-lan.vlans.services.hosts.hintbooth-adguardhome.ipv4 ]; adguardhome.ipv4Addresses = [ globals.networks.home-lan.vlans.services.hosts.${homeDnsServer}.ipv4 ];
adguardhome.ipv6Addresses = [ globals.networks.home-lan.vlans.services.hosts.hintbooth-adguardhome.ipv6 ]; adguardhome.ipv6Addresses = [ globals.networks.home-lan.vlans.services.hosts.${homeDnsServer}.ipv6 ];
} }
// lib.flip lib.concatMapAttrs globals.networks.home-lan.vlans ( // lib.flip lib.concatMapAttrs globals.networks.home-lan.vlans (
vlanName: _: { vlanName: _: {
@ -24,7 +47,7 @@ in
rules = { rules = {
masquerade-internet = { masquerade-internet = {
from = map (name: "vlan-${name}") (builtins.attrNames globals.networks.home-lan.vlans); from = map (name: "vlan-${name}") (globals.general.internetVLANs);
to = [ "untrusted" ]; to = [ "untrusted" ];
# masquerade = true; NOTE: custom rule below for ip4 + ip6 # masquerade = true; NOTE: custom rule below for ip4 + ip6
late = true; # Only accept after any rejects have been processed late = true; # Only accept after any rejects have been processed
@ -33,7 +56,7 @@ in
# Allow access to the AdGuardHome DNS server from any VLAN that has internet access # Allow access to the AdGuardHome DNS server from any VLAN that has internet access
access-adguardhome-dns = { access-adguardhome-dns = {
from = map (name: "vlan-${name}") (builtins.attrNames globals.networks.home-lan.vlans); from = map (name: "vlan-${name}") (globals.general.internetVLANs);
to = [ "adguardhome" ]; to = [ "adguardhome" ];
verdict = "accept"; verdict = "accept";
}; };
@ -53,7 +76,7 @@ in
services-to-local = { services-to-local = {
from = [ "vlan-services" ]; from = [ "vlan-services" ];
to = [ "local" ]; to = [ "local" ];
allowedUDPPorts = [ 52829 ]; allowedUDPPorts = [ 52829 547 ];
}; };
# Forward traffic between wireguard participants # Forward traffic between wireguard participants
@ -71,7 +94,7 @@ in
late = true; late = true;
rules = rules =
lib.forEach lib.forEach
(map (name: "vlan-${name}") (builtins.attrNames globals.networks.home-lan.vlans)) (map (name: "vlan-${name}") (globals.general.internetVLANs))
( (
zone: zone:
lib.concatStringsSep " " [ lib.concatStringsSep " " [
@ -93,7 +116,68 @@ in
systemd.network = { systemd.network = {
wait-online.anyInterface = true; wait-online.anyInterface = true;
netdevs = {
"10-veth" = {
netdevConfig = {
Kind = "veth";
Name = "veth-br";
};
peerConfig = {
Name = "veth-int";
};
};
"20-br" = {
netdevConfig = {
Kind = "bridge";
Name = "br";
};
bridgeConfig = {
VLANFiltering = true;
};
};
};
networks = { networks = {
"40-br" = {
matchConfig.Name = "br";
bridgeConfig = { };
linkConfig = {
ActivationPolicy = "always-up";
RequiredForOnline = "no";
};
networkConfig = {
ConfigureWithoutCarrier = true;
LinkLocalAddressing = "no";
};
};
"15-veth-br" = {
matchConfig.Name = "veth-br";
linkConfig = {
RequiredForOnline = "no";
};
networkConfig = {
Bridge = "br";
};
inherit bridgeVLANs;
};
"15-veth-int" = {
matchConfig.Name = "veth-int";
linkConfig = {
ActivationPolicy = "always-up";
RequiredForOnline = "no";
};
networkConfig = {
ConfigureWithoutCarrier = true;
LinkLocalAddressing = "no";
};
vlan = map (name: "vlan-${name}") (builtins.attrNames globals.networks.home-lan.vlans);
};
# br
"30-lan1" = { "30-lan1" = {
matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan1.mac; matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan1.mac;
linkConfig.RequiredForOnline = "enslaved"; linkConfig.RequiredForOnline = "enslaved";
@ -101,7 +185,9 @@ in
Bridge = "br"; Bridge = "br";
ConfigureWithoutCarrier = true; ConfigureWithoutCarrier = true;
}; };
inherit bridgeVLANs;
}; };
# wifi
"30-lan2" = { "30-lan2" = {
matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan2.mac; matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan2.mac;
linkConfig.RequiredForOnline = "enslaved"; linkConfig.RequiredForOnline = "enslaved";
@ -109,7 +195,9 @@ in
Bridge = "br"; Bridge = "br";
ConfigureWithoutCarrier = true; ConfigureWithoutCarrier = true;
}; };
inherit bridgeVLANs;
}; };
# summers
"30-lan3" = { "30-lan3" = {
matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan3.mac; matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan3.mac;
linkConfig.RequiredForOnline = "enslaved"; linkConfig.RequiredForOnline = "enslaved";
@ -117,7 +205,9 @@ in
Bridge = "br"; Bridge = "br";
ConfigureWithoutCarrier = true; ConfigureWithoutCarrier = true;
}; };
inherit bridgeVLANs;
}; };
# winters
"30-lan4" = { "30-lan4" = {
matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan4.mac; matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan4.mac;
linkConfig.RequiredForOnline = "enslaved"; linkConfig.RequiredForOnline = "enslaved";
@ -125,7 +215,9 @@ in
Bridge = "br"; Bridge = "br";
ConfigureWithoutCarrier = true; ConfigureWithoutCarrier = true;
}; };
bridgeVLANs = lan4VLANs;
}; };
# lr
"30-lan5" = { "30-lan5" = {
matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan5.mac; matchConfig.MACAddress = config.repo.secrets.local.networking.networks.lan5.mac;
linkConfig.RequiredForOnline = "enslaved"; linkConfig.RequiredForOnline = "enslaved";
@ -133,10 +225,37 @@ in
Bridge = "br"; Bridge = "br";
ConfigureWithoutCarrier = true; ConfigureWithoutCarrier = true;
}; };
bridgeVLANs = lan5VLANs;
}; };
}; } // lib.flip lib.concatMapAttrs globals.networks.home-lan.vlans (
}; vlanName: vlanCfg: {
"40-me-${vlanName}" = lib.mkForce {
address = [
vlanCfg.hosts.${config.node.name}.cidrv4
vlanCfg.hosts.${config.node.name}.cidrv6
];
matchConfig.Name = "me-${vlanName}";
networkConfig = {
IPv4Forwarding = "yes";
IPv6PrivacyExtensions = "yes";
IPv6SendRA = true;
IPv6AcceptRA = false;
};
ipv6Prefixes = [
{
Prefix = vlanCfg.cidrv6;
}
];
ipv6SendRAConfig = {
Managed = true; # set RA M flag -> DHCPv6 for addresses
OtherInformation = true; # optional, for “other info” via DHCPv6
};
linkConfig.RequiredForOnline = "routable";
};
}
);
};
}; };
} }

View file

@ -12,6 +12,10 @@ in
}; };
config = lib.mkIf config.swarselmodules.server.${serviceName} { config = lib.mkIf config.swarselmodules.server.${serviceName} {
swarselmodules.server = {
podman = true;
};
nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
}; };

View file

@ -10,6 +10,10 @@ in
}; };
config = lib.mkIf config.swarselmodules.server.${serviceName} { config = lib.mkIf config.swarselmodules.server.${serviceName} {
swarselmodules.server = {
podman = true;
};
nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = { nodes.${dnsServer}.swarselsystems.server.dns.${globals.services.${serviceName}.baseDomain}.subdomainRecords = {
"${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6; "${globals.services.${serviceName}.subDomain}" = dns.lib.combinators.host proxyAddress4 proxyAddress6;
}; };

View file

@ -95,6 +95,14 @@ in
) )
); );
topology.self.interfaces = lib.mapAttrs'
(wgName: _:
lib.nameValuePair "${wgName}" {
network = wgName;
}
)
config.swarselsystems.server.wireguard.interfaces;
environment.systemPackages = with pkgs; [ environment.systemPackages = with pkgs; [
wireguard-tools wireguard-tools
]; ];

View file

@ -1,27 +1,27 @@
{ self, config, lib, globals, inputs, outputs, minimal, nixosConfig ? null, ... }: { self, config, lib, globals, inputs, outputs, minimal, nixosConfig ? null, ... }:
let
domainDefault = service: config.repo.secrets.common.services.domains.${service};
proxyDefault = config.swarselsystems.proxyHost;
addressDefault =
if
config.swarselsystems.proxyHost != config.node.name
then
if
config.swarselsystems.server.wireguard.interfaces.wgProxy.isClient
then
globals.networks."${config.swarselsystems.server.wireguard.interfaces.wgProxy.serverNetConfigPrefix}-wgProxy".hosts.${config.node.name}.ipv4
else
globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.ipv4
else
"localhost";
in
{ {
_module.args = { _module.args = {
confLib = rec { confLib = rec {
addressDefault =
if
config.swarselsystems.proxyHost != config.node.name
then
if
config.swarselsystems.server.wireguard.interfaces.wgProxy.isClient
then
globals.networks."${config.swarselsystems.server.wireguard.interfaces.wgProxy.serverNetConfigPrefix}-wgProxy".hosts.${config.node.name}.ipv4
else
globals.networks.${config.swarselsystems.server.netConfigName}.hosts.${config.node.name}.ipv4
else
"localhost";
domainDefault = service: config.repo.secrets.common.services.domains.${service};
proxyDefault = config.swarselsystems.proxyHost;
getConfig = if nixosConfig == null then config else nixosConfig; getConfig = if nixosConfig == null then config else nixosConfig;
gen = { name, user ? name, group ? name, dir ? null, port ? null, domain ? (domainDefault name), address ? addressDefault, proxy ? proxyDefault }: rec { gen = { name ? "n/a", user ? name, group ? name, dir ? null, port ? null, domain ? (domainDefault name), address ? addressDefault, proxy ? proxyDefault }: rec {
servicePort = port; servicePort = port;
serviceName = name; serviceName = name;
specificServiceName = "${name}-${config.node.name}"; specificServiceName = "${name}-${config.node.name}";
@ -36,12 +36,28 @@
proxyAddress4 = globals.hosts.${proxy}.wanAddress4 or null; proxyAddress4 = globals.hosts.${proxy}.wanAddress4 or null;
proxyAddress6 = globals.hosts.${proxy}.wanAddress6 or null; proxyAddress6 = globals.hosts.${proxy}.wanAddress6 or null;
inherit (globals.hosts.${config.node.name}) isHome; inherit (globals.hosts.${config.node.name}) isHome;
inherit (globals.general) homeProxy webProxy dnsServer idmServer; inherit (globals.general) homeProxy webProxy dnsServer homeDnsServer homeWebProxy idmServer;
webProxyIf = "${webProxy}-wgProxy"; webProxyIf = "${webProxy}-wgProxy";
homeProxyIf = "home-wgHome"; homeProxyIf = "home-wgHome";
isProxied = config.node.name != webProxy; isProxied = config.node.name != webProxy;
}; };
static = rec {
inherit (globals.hosts.${config.node.name}) isHome;
inherit (globals.general) homeProxy webProxy dnsServer homeDnsServer homeWebProxy idmServer oauthServer;
webProxyIf = "${webProxy}-wgProxy";
homeProxyIf = "home-wgHome";
isProxied = config.node.name != webProxy;
nginxAccessRules = ''
allow ${globals.networks.home-lan.vlans.home.cidrv4};
allow ${globals.networks.home-lan.vlans.home.cidrv6};
allow ${globals.networks.home-lan.vlans.services.hosts.${homeProxy}.ipv4};
allow ${globals.networks.home-lan.vlans.services.hosts.${homeProxy}.ipv6};
deny all;
'';
homeServiceAddress = lib.optionalString (config.swarselsystems.server.wireguard.interfaces ? wgHome) globals.networks."${config.swarselsystems.server.wireguard.interfaces.wgHome.serverNetConfigPrefix}-wgHome".hosts.${config.node.name}.ipv4;
};
mkMicrovm = mkMicrovm =
if config.swarselsystems.withMicroVMs then if config.swarselsystems.withMicroVMs then
(guestName: { (guestName: {
@ -49,7 +65,7 @@
backend = "microvm"; backend = "microvm";
autostart = true; autostart = true;
modules = [ modules = [
(config.node.configDir + /guests/${guestName}.nix) (config.node.configDir + /guests/${guestName}/default.nix)
{ {
node.secretsDir = config.node.configDir + /secrets/${guestName}; node.secretsDir = config.node.configDir + /secrets/${guestName};
node.configDir = config.node.configDir + /guests/${guestName}; node.configDir = config.node.configDir + /guests/${guestName};
@ -62,6 +78,7 @@
}; };
} }
"${self}/modules/nixos/optional/microvm-guest.nix" "${self}/modules/nixos/optional/microvm-guest.nix"
"${self}/modules/nixos/optional/systemd-networkd-base.nix"
]; ];
microvm = { microvm = {
system = config.node.arch; system = config.node.arch;
@ -74,6 +91,7 @@
inherit inputs outputs minimal; inherit inputs outputs minimal;
inherit (inputs) self; inherit (inputs) self;
withHomeManager = false; withHomeManager = false;
microVMParent = config.node.name;
globals = outputs.globals.${config.node.arch}; globals = outputs.globals.${config.node.arch};
}; };
}; };

View file

@ -37,6 +37,18 @@
type = lib.types.str; type = lib.types.str;
default = ""; default = "";
}; };
# @ future me: dont put this under server prefix
# home-manager would then try to import all swarselsystems.server.* options
localVLANs = lib.mkOption {
type = lib.types.listOf lib.types.str;
default = [ ];
};
# @ future me: dont put this under server prefix
# home-manager would then try to import all swarselsystems.server.* options
initrdVLAN = lib.mkOption {
type = lib.types.nullOr lib.types.str;
default = null;
};
mainUser = lib.mkOption { mainUser = lib.mkOption {
type = lib.types.str; type = lib.types.str;
default = "swarsel"; default = "swarsel";

View file

@ -4,189 +4,250 @@
inputs.nix-topology.flakeModule inputs.nix-topology.flakeModule
]; ];
perSystem.topology.modules = [ perSystem = { system, ... }:
({ config, ... }: let
let inherit (self.outputs) lib;
inherit (self.outputs) globals; in
inherit (config.lib.topology) {
mkInternet topology.modules = [
mkDevice ({ config, ... }:
mkSwitch let
mkRouter globals = self.outputs.globals.${system};
mkConnection inherit (config.lib.topology)
; mkInternet
in mkDevice
{ mkSwitch
renderer = "elk"; mkRouter
mkConnection
;
in
{
renderer = "elk";
networks = { networks = {
home-lan = { fritz-lan = {
name = "Home LAN"; name = "Fritz!Box LAN";
inherit (globals.networks.home-lan) cidrv4; inherit (globals.networks.home-lan) cidrv4 cidrv6;
};
fritz-wg = {
name = "Wireguard Tunnel for Fritzbox net access";
inherit (globals.networks.twothreetunnel-wg) cidrv4;
};
wg = {
name = "Wireguard Tunnel for proxy access";
inherit (globals.networks.twothreetunnel-wg) cidrv4;
};
};
nodes = {
internet = mkInternet {
connections = [
(mkConnection "fritzbox" "dsl")
(mkConnection "moonside" "wan")
(mkConnection "belchsfactory" "wan")
(mkConnection "twothreetunnel" "wan")
(mkConnection "stoicclub" "wan")
(mkConnection "liliputsteps" "wan")
(mkConnection "eagleland" "wan")
(mkConnection "magicant" "wifi")
(mkConnection "toto" "bootstrapper")
(mkConnection "hotel" "demo host")
];
};
fritzbox = mkRouter "FRITZ!Box" {
info = "FRITZ!Box 7682";
image = "${self}/files/topology-images/hunsn.png";
interfaceGroups = [
[
"eth1"
"eth2"
"eth3"
"eth-wan"
"wifi"
]
[ "dsl" ]
];
connections = {
eth1 = mkConnection "winters" "eth1";
eth2 = mkConnection "switch-bedroom" "eth1";
eth3 = mkConnection "switch-livingroom" "eth1";
eth-wan = mkConnection "hintbooth" "eth6";
wgPyramid = mkConnection "pyramid" "fritz-wg";
wgMagicant = mkConnection "magicant" "fritz-wg";
wifiPyramid = mkConnection "pyramid" "wifi";
wifiMagicant = mkConnection "magicant" "wifi";
wifiBakery = mkConnection "bakery" "wifi";
wifiMachpizza = mkConnection "machpizza" "wifi";
};
interfaces = {
eth1 = {
addresses = [ globals.networks.home-lan.hosts.fritzbox.ipv4 ];
network = "home-lan";
}; };
eth2 = { services = {
addresses = [ globals.networks.home-lan.hosts.fritzbox.ipv4 ]; name = "VLAN: Services";
network = "home-lan"; inherit (globals.networks.home-lan.vlans.services) cidrv4 cidrv6;
}; };
eth3 = { home = {
addresses = [ globals.networks.home-lan.hosts.fritzbox.ipv4 ]; name = "VLAN: Home";
network = "home-lan"; inherit (globals.networks.home-lan.vlans.home) cidrv4 cidrv6;
}; };
eth-wan = { devices = {
addresses = [ globals.networks.home-lan.hosts.fritzbox.ipv4 ]; name = "VLAN: Devices";
network = "home-lan"; inherit (globals.networks.home-lan.vlans.devices) cidrv4 cidrv6;
}; };
wifi = { guests = {
addresses = [ globals.networks.home-lan.hosts.fritzbox.ipv4 ]; name = "VLAN: Guests";
virtual = true; inherit (globals.networks.home-lan.vlans.guests) cidrv4 cidrv6;
network = "home-lan";
}; };
fritz-wg = { fritz-wg = {
addresses = [ globals.networks.fritz-wg.hosts.fritzbox.ipv4 ]; name = "WireGuard: Fritz!Box tunnel";
network = "wg"; inherit (globals.networks.fritz-wg) cidrv4 cidrv6;
virtual = true; };
type = "wireguard"; wgProxy = {
name = "WireGuard: Web proxy tunnel";
inherit (globals.networks.twothreetunnel-wgProxy) cidrv4 cidrv6;
};
wgHome = {
name = "WireGuard: Home proxy tunnel";
inherit (globals.networks.home-wgHome) cidrv4 cidrv6;
}; };
}; };
};
switch-livingroom = mkSwitch "Switch Livingroom" { nodes = {
info = "TL-SG108"; internet = mkInternet {
image = "${self}/files/topology-images/TL-SG108.png"; connections = [
interfaceGroups = [ (mkConnection "fritzbox" "dsl")
[ (mkConnection "magicant" "wifi")
"eth1" (mkConnection "liliputsteps" "lan")
"eth2" (mkConnection "treehouse" "eth1")
"eth3" (mkConnection "toto" "bootstrapper")
"eth4" (mkConnection "hotel" "demo host")
"eth5" ];
"eth6" };
"eth7"
"eth8"
] fritzbox = mkRouter "FRITZ!Box" {
]; info = "FRITZ!Box 7682";
connections = { image = "${self}/files/topology-images/Fritz!Box_7682.png";
eth2 = mkConnection "nswitch" "eth1"; interfaceGroups = [
eth7 = mkConnection "pc" "eth1"; [
eth8 = mkConnection "pyramid" "eth1"; "eth1"
"eth2"
"eth3"
"eth-wan"
"wifi"
]
[ "dsl" ]
];
connections = {
eth1 = mkConnection "winters" "eth1";
eth-wan = mkConnection "hintbooth" "lan";
};
interfaces = {
eth1 = {
addresses = [ globals.networks.home-lan.hosts.fritzbox.ipv4 ];
network = "fritz-lan";
};
eth2 = { };
eth3 = { };
eth-wan = {
addresses = [ globals.networks.home-lan.hosts.fritzbox.ipv4 ];
network = "fritz-lan";
};
wifi = {
addresses = [ globals.networks.home-lan.hosts.fritzbox.ipv4 ];
virtual = true;
renderer.hidePhysicalConnections = true;
network = "fritz-lan";
physicalConnections = [
(mkConnection "pyramid" "wifi")
(mkConnection "bakery" "wifi")
(mkConnection "machpizza" "wifi")
];
};
fritz-wg = {
addresses = [ globals.networks.fritz-wg.hosts.fritzbox.ipv4 ];
network = "fritz-wg";
virtual = true;
renderer.hidePhysicalConnections = true;
type = "wireguard";
physicalConnections = [
(mkConnection "pyramid" "fritz-wg")
(mkConnection "magicant" "fritz-wg")
];
};
};
};
switch-livingroom = mkSwitch "Switch Livingroom" {
info = "TL-SG108E";
image = "${self}/files/topology-images/TL-SG108E.png";
interfaceGroups = [
# trunk
[ "eth1" ]
# devices
[ "eth2" ]
# home
[ "eth3" "eth8" ]
# guests
[ "eth4" "eth5" "eth6" "eth7" ]
];
interfaces = {
eth2 = { network = lib.mkForce "devices"; };
eth3 = { network = lib.mkForce "home"; };
eth7 = { network = lib.mkForce "guests"; };
eth8 = { network = lib.mkForce "home"; };
};
connections = {
eth2 = mkConnection "nswitch" "eth1";
eth3 = mkConnection "bakery" "eth1";
eth7 = mkConnection "pc" "eth1";
eth8 = mkConnection "pyramid" "eth1";
};
};
switch-bedroom = mkDevice "Switch Bedroom" {
info = "Cisco SG 200-08";
image = "${self}/files/topology-images/Cisco_SG_200-08.png";
interfaceGroups = [
# trunk
[ "eth1" ]
# devices
[ "eth2" ]
# guests
[ "eth3" "eth4" "eth5" "eth6" "eth7" "eth8" ]
];
interfaces = {
eth2 = { network = lib.mkForce "devices"; };
eth3 = { network = lib.mkForce "guests"; };
};
connections = {
eth2 = mkConnection "printer" "eth1";
eth3 = mkConnection "machpizza" "eth1";
};
};
nswitch = mkDevice "Nintendo Switch" {
info = "Nintendo Switch";
image = "${self}/files/topology-images/nintendo-switch.png";
interfaces.eth1 = { };
};
magicant = mkDevice "magicant" {
icon = "${self}/files/topology-images/phone.png";
info = "Samsung Z Flip 6";
image = "${self}/files/topology-images/zflip6.png";
interfaces = {
wifi = { };
fritz-wg.network = "fritz-wg";
};
};
machpizza = mkDevice "machpizza" {
info = "MacBook Pro 2016";
icon = "devices.laptop";
deviceIcon = "${self}/files/topology-images/mac.png";
interfaces = {
eth1.network = "guests";
wifi = { };
};
};
treehouse = mkDevice "treehouse" {
info = "NVIDIA DGX Spark";
icon = "${self}/files/topology-images/home-manager.png";
deviceIcon = "${self}/files/topology-images/dgxos.png";
interfaces = {
eth1 = { };
wifi = { };
};
services = {
ollama = {
name = "Ollama";
icon = "${self}/files/topology-images/ollama.png";
};
openwebui = {
name = "Open WebUI";
icon = "${self}/files/topology-images/openwebui.png";
};
comfyui = {
name = "Comfy UI";
icon = "${self}/files/topology-images/comfyui.png";
};
};
};
pc = mkDevice "Chaostheater" {
info = "ASUS Z97-A, i7-4790k, GTX970, 32GB RAM";
icon = "${self}/files/topology-images/windows.png";
deviceIcon = "${self}/files/topology-images/atlasos.png";
services = {
sunshine = {
name = "Sunshine";
icon = "${self}/files/topology-images/sunshine.png";
};
};
interfaces.eth1.network = "guests";
};
printer = mkDevice "Printer" {
info = "DELL C2665dnf";
image = "${self}/files/topology-images/DELL-C2665dnf.png";
interfaces.eth1 = { };
};
}; };
};
switch-bedroom = mkSwitch "Switch Bedroom" { })
info = "TL-SG1005D";
image = "${self}/files/topology-images/TL-SG1005D.png";
interfaceGroups = [
[
"eth1"
"eth2"
"eth3"
"eth4"
"eth5"
]
];
connections.eth2 = mkConnection "printer" "eth1";
connections.eth3 = mkConnection "machpizza" "eth1";
};
nswitch = mkDevice "Nintendo Switch" {
info = "Nintendo Switch";
image = "${self}/files/topology-images/nintendo-switch.png";
interfaces.eth1 = { };
};
magicant = mkDevice "magicant" {
icon = "${self}/files/topology-images/phone.png";
info = "Samsung Z Flip 6";
image = "${self}/files/topology-images/zflip6.png";
interfaces = {
wifi = { };
fritz-wg = { };
};
};
machpizza = mkDevice "machpizza" {
info = "MacBook Pro 2016";
icon = "${self}/files/topology-images/mac.png";
interfaces = {
eth1 = { };
wifi = { };
};
};
pc = mkDevice "Windows Gaming Server" {
info = "i7-4790k, GTX970, 32GB RAM";
image = "${self}/files/topology-images/pc.png";
interfaces.eth1 = { };
};
printer = mkDevice "Printer" {
info = "DELL C2665dnf";
image = "${self}/files/topology-images/DELL-C2665dnf.png";
interfaces.eth1 = { };
};
};
})
]; ];
};
} }

View file

@ -20,6 +20,8 @@
general = lib.mkDefault true; general = lib.mkDefault true;
packages = lib.mkDefault true; packages = lib.mkDefault true;
ssh = lib.mkDefault true; ssh = lib.mkDefault true;
wireguard = lib.mkDefault true;
dns-home = lib.mkDefault true;
}; };
}; };
}; };

View file

@ -0,0 +1 @@
emVomIbxGS95tDiwPpUbsRTAur/TZ+BRy7+4737Sv1Q=

View file

@ -0,0 +1 @@
G4NXSwhwU5a2K1q3oAwmnOtBlCj15J2aqh6zIJJtggE=

View file

@ -8,143 +8,161 @@ sops:
- recipient: age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza - recipient: age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpZW1LTVFtaGVraTFDRVI2 YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFdDZiY1BsaHhLYy93L2Ju
dkNRV0tpdUg1YmdiL2hMVUlodzFJM1hHUkJBClRHaGRMTDNlbVpDS1A5dzBpc2Yv TkJHRUdTU0VFKy9jd1p2ZmJrU092Z09yMTNvCnpzbXFIZ1VMVk1QVzN6YXFmckQ0
ancxU3lSRTJNMFBjeFNoSEF1Rys0YVUKLS0tIHVpb2g4bnN4NHJTdHJrSDdKVFZY U0hFam53Z3V5U2xYNjkwU1UxNmI4ZncKLS0tIGk1MC9EV2hnMFN6aFRtekt0enQy
aGNOMDgvakoxcWJ3bEVyeFZOQU94UXcK/mjqz9Ys7ZEm2+9Y+mLrQVqoC5g5ag85 RWxXVmhJU3NVbHdlS1Rsd05sSkZiY1UKaK5bSDPhQlVTryAYr/9mIgmXDzVp2KWF
Xp9Fo7gmsgc9lZwgxRPLzIBeWcaN17NIaMRDMxTz5cdDCRi5JP9FiQ== M4FQURHk6kvSIVjHNfRyMX0IVtCFZMSmVpuPUP46J/5kzdN59Jn2Bw==
-----END AGE ENCRYPTED FILE-----
- recipient: age18cgqlely56hgmhscllkmafwpjdk6dwep6ej3vkk97dzemp8jtuksqrrjjl
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBLRElrSnhrM0ZVQ043K1Nk
VTNlWDVDNW5veDNPM0RuOWZTZ3IwQ2pBdmpFCktEZFNvUTRrVVRBdFU5alhJSTE0
RVlqRkl5MUEzZjhUVWwrWTFWMk8yWG8KLS0tIHJKZXJrNXZiRjNiZEh6VEhHWnZT
dlI3RTl2MW43YVdJMVlDaUoxSDV3YTAKBCjLqctIpPeTYsRxhj0/7DzR0q1cGe2d
w0B8DmH56XP7vq+nLh6+imWFLsbEOS0lRPHRRBEiimEkYljO5ZkoZg==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d - recipient: age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXMXRHK1Nud0VEMUh5OFRZ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3TEREZ0lVR2Q5aEN1S2sv
Z1ljcmZyRG9yRFFwdWtTcEVXc3NEOVVId2xjCnVIb3cvSG9oODJvd0NGd1BIb3A4 dVhURlhhWTJBdEdhbHlXZGVQa2ZwZkhFd2lnClM1QUJrMW1GU3FuVTFwUkZxR0xD
TmJ4SGdmd1FDWCs2c0YvZXkxWWFidG8KLS0tIHIzUlloTUhxY29pQ081akFGSmRO YS9kVFVRdGZKMVVRTk5sNm9nRVV1YkkKLS0tIExyKzlJUHhUdEVhSGJEUUs1YlQz
Y25iUkw4bU1sUzZlUHEyWDB3d3hlZDAK4auJRQylMD3vf/PeMdImqRrx86sT2vdM Yk5WMERLb1MyVTRvM3hkVVFNU3ZtajAKqH9sLSNTacfRj4c/FeeOyCITdz9zwgqm
lbmSBNqry2CueSgvFp2z4q+NOE4F5z/rlc0GZnUvdzBTLZ83C1BYoQ== e52OOUzI9nmq3zbhzd7b2nWHlJ2d/vmFN0u4oEpLodQPqBy/cvuoLQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1ly2endyt0y9xyddj6yuj4nw6fa3ltvzlvew4cr4lzs6dv8dkavpqadmyxx - recipient: age1ly2endyt0y9xyddj6yuj4nw6fa3ltvzlvew4cr4lzs6dv8dkavpqadmyxx
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyZFpCaWNlSGdWTG9EanBC YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEbmRtN1FXaFYwUTBsbEhr
MlVKZ1FCMHpzMkNJUTA3QzZ3aUtCbmFIemxjCktVZ0V3L25NNGxLaWRVbTZCWjBV T0tGcVkvdmhjOWZMLzZ3UUpoQ0V6Y2luRlNrCnU0RThMcXlabWQraHB0ZjNldFRW
NXJKSzczYUd1ajJ6U0VsTmRpQW5SalEKLS0tIER1Y3VCTzJ5TjZ5dHMxSG8yaHM3 bUtRNGgwNDZhNjF6MzlQM2V5RmVRRnMKLS0tIDB0ZUpPZzJFMndSZXJNQWEzbjZQ
OGFWc240c0lSYXEzWlp6eGtIcHpnUlkK+7wia8nrB982IdbW8zXg0p4Zf/3XE+Rn YVJxb3NLNEJkNXlzR0Q2MUNhZ0NGeTQKC204L2g3b/ER0RtnTaGtuZSukTawgiC0
u0Nsa7cbeOpB+stTV/i/2ayY86+zkN8UQXJnlv+AVf3Oe/3xaKsZ1A== 94UolrcApg2tAUDJR9AqJ0iAAu8KSkcy77mQIs1t1d5lwejwsOBUMQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age15klj4t7gpfp69472mne4ue62pp6m4e04dmjyw7yf30qtqd3vl3uqjmcyxm - recipient: age15klj4t7gpfp69472mne4ue62pp6m4e04dmjyw7yf30qtqd3vl3uqjmcyxm
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzUzNPMUE0M3Uzc2JqTUhk YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjbmZRNDYwVjhacnZzTm1J
ejVmS2FpSHN2YitaRHNMNm9abHdTSUF3QVdRCnlQcW9aMFh5MHRHNjNrWXFrRTlF MG5FWVd5TytPNWhDVTR6Z2dxdEYwbEU5VVFNCkVpdmMxTmR2dHBKNnZNTmF4c3hs
TXNBN3FEY3dPMHhNbEQ0eGdacGNvbkUKLS0tIEtoWlFqblROSndGOEZwdEN2cXcr eUozU2VkKzlKMjhWaDJXQUx3ZXdHV1UKLS0tIEtNb25NU204dFovM2xvMEpDYUJX
c0IzdGY3T3E4Vmk1SzkydEVLbng3MG8K2pF8UY+89cI0dh7xgdrvl7fn8f05jSpM QWZLNDQvZjZjaDZiN3JLcWswMkhtcnMK0kkTPKMgKNiOOgen2BQANozKY0npxINI
MFcVBU9ySITPb3lcGtOKVcyyh8OaTusdZWmzbnl/dKr7kWjg/M8l/g== ZhKkf/eQsPD5kUbD1gLshfeOS+GOcDJSjrYigneJo11yEhNVF7juDQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1k73gy5em3js9zklnnkzp5hme9k04lny32fgahmzddknjw5c295asdyr4x6 - recipient: age1k73gy5em3js9zklnnkzp5hme9k04lny32fgahmzddknjw5c295asdyr4x6
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBQZmdsMEpVanFKdEhaNUlp YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0VVBQaVluOExJSnBxaWtn
Tk5KYllvRWRhQXNBN2VzMGxHSVA2aVhhclZFCkdGWWhLakN4dkVVMnhMYkk2ZmdF N2RXb0UzaFgvTmpXcENKaTkzb05Vb3hMeHpnCjRVSmhTZ01sVy9ZRnZrK1FTa0Ey
TDhtOGlpWlF3QlBKWVJkejhwUERZczQKLS0tIGMvdWpXV3pJaytsY2kvbXlsY3Rl TnJmYlVaNGFLRmZUcnFXYkswQnQ5emMKLS0tIGNuMlBmYnNzNXczYTljbUY3bUtk
Wm56NTVKcmdESG43NGhhWk0xbHZFeU0KUwZW24hBFmC3PR5iP4e5eMt94I4xHgo6 TkFMSlZzTjVjMkVUaVcyVXI3cXc0K28KUDg9+qZqrbUk+D8TEG2p5tu6v8HgGfHK
qB2ceOd4c86h16+XiJvhiYbPQdvuKcHoMSdmt2ZbHstzeuOn1ZdClA== MGkbN/+3wmitC2T1HEdA18ULGrmd1SFN6qGIfYOkR6dkhETIs+w/jQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8 - recipient: age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEZjEvNlMzQXYvZG9QaXdY YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBHSjhleGt2Y0JTU3ZRWnda
SDFqSDUzVE1xNE1sM0l5RXNJZllEL3c2Y3dzCjFMTEp0eFNRTndWWExYS1phSjlu US9ScWpPYTk2Qlhjdlh6RS9JR0lzTVc1djMwCm8zZnJ2a1prOW9Vc3h4RjJXNE5G
MGluSVZPOExnd3ErN2VZVTJIb2l4WjQKLS0tIHd2SEwwaXIvRXhEVFd5OC9vQ3ph d0IwYSttaC9iVGZaejBmK1J6SXc0aTgKLS0tIGZvbnJTZ29xcDJGbzkraytKb2tY
azdrTklmaWNYR3RuaitKbHk5WVhsb0UKgpHMKCR0/LzLWUgH3aasF9tETrapgsoB OUIxMHJmbTlhei9nSEpQeUtIWjJLSGsKwLTnTxIqkumhWoVbt7eKTU03upmZYvF1
oNXyxH7ry8jE+WYw4p+oOgSpNVuq9ae2Hot36u3hTjgXuub9kF2IhA== S3a4mS/FZAU/9PgtHeY7LF4a0wwnHBAOxTwKcj8lYPWQzfPNSBFEBQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx - recipient: age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyNFFWendCOFptUU15a1kz YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjMmF1VkdhUHIzYW5sdlo0
TTNmSTUySkFrN2ZNUmZzNDVTWG96SDdwNENNCmx0TmdnTnVRYWo5ZHJQK093bG1X UnpRUjNieVREc09ONWtqQTdWQU82R2g2S1RzClowWVpMZTEwM1czdW0zWmdiMGd3
TWk3Sm41RVFUY2FPVUN4TldjaEs1RUEKLS0tIFF3Vm9sY1BIeUxteFgwd0xaVXRt V1djaDBpRFZHU1BZbmRhUDk2RndmaGMKLS0tIG9oQmlKMW5TVE1lQ2ZEMnU1c0pI
SkJ6WmlobXF6Y01semFHUnJUK0wzZWcKMwhhIBUZxXRsaemaaJ7zFXJ8CH3Gw6N8 dlRVNFR5ZDhJcitoaXdmdFBHenM2NEkKHrWek+5xtVdwVaLF7FuhdJJCdZxvg3ib
nNZUTPb7eg7yvHIiST7EqO57qhpHuxqK/OCFBOIPYs/wjdO806ubAA== JKIN6/IKg6v8wWbts+oJZmH0+ibv3dPPCNll0U0toYGBkbJVUUiMbw==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1mjgw3nxlnqdj04mgjz3wn7fj2nl2nxla4p2r2fn4nkvayfgp09pqllxzyh - recipient: age1mjgw3nxlnqdj04mgjz3wn7fj2nl2nxla4p2r2fn4nkvayfgp09pqllxzyh
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSByUXA3T0Z6eVpGQVZheWFF YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXQ0FYTnBILzF1TENDVFcx
N2NOV2NjZFdlTUwySE16NlBuU2pPRlRFV25NCnlxOENwa3lKMlZHcXhhMkd1dHFH Wi9pZUg1eGNiTCtGdUFrRERBVGxxR05jQWkwClBLK0FBd201ZzlRVC9aQUIwUzlz
bXAyQXErVlFvSnNvekxkWFpsNW1rc3cKLS0tIDRSS0lVT3BYNXZUcWk5dTNMc2Qw Yy9Sc2dpQ2l3Ty9ST3JrdU54VFN2UlEKLS0tIG5ldXY1R1k0dGlsRXhPYlpLS2Yv
ZjBKOW5XVTJiMFhpdm5qeUY0VjBqT2MK83ZdreVtLQdV5zPPjRpcDVKPtU2heVME dFBoM0RGQXVLdnhxVnJ0V1FpWmFkTUUKCHv8KQYB2QdcTdCB3Wig7YTRKt1ZiqkA
yhXwR5VmKKpSHnu9uYSzIjyWoLQA7uLD6GcFkUEcUuRifd0tYMJTuA== MT5A0z0rizax0YZLGJ7QJlWkT/EmX0EsV62cvjzXeUkE2FKpYffiNQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl - recipient: age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBTZWl1dGFGajFZNzhJZkUr YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1VVlxd3RrRDFnN0Q5SGgx
Nm5hc0d2WG9QRDkraWYySVpiT2twakpqa2pVCjhDUk94LzFZalkyaUdIVE5YMDJL OGlDV3lyYmRQTjBsZ1kydlI4UFNVMUNZYmdRCmh0dzdEUmFDWmU0VjZHZHhhN2ZX
V3NLRHUvaWcwbEpXcFNOVTlhMkg2UVEKLS0tIGxrYk9wVWFFd2V5ZDNycVA5VXUx MW04LzB1ZHc4K1dCbGVBK1NMRDJJbDAKLS0tIDEzclhsWWhIRlUrU1ZjV2Q2dExF
Y2wzNGFGMTJXUUpPbGxuMU5nWlFvU28KTmP0byJFneTPHUJ6e+ScSiKypMrz7TNV cW42NFdBa1JKZTRpb2Z3aVpNVDJaWFkKynL65X4AjGw7PDrFZw+J34KajCl/TfZ7
FHZ78vmNIzcstLKgXwK23hyEIYTtgrLOP37B768fAM8aHiqGQORs+Q== fA1c8fyngnt42FuKVoSHiIrEUCfFEsf37NbV5WQFF61V0bO83EX5qQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age15cx90pnp54xp5gxlt02yn9j2pz968wp3l5ukdkx55xuecp34e5pszjku4m - recipient: age15cx90pnp54xp5gxlt02yn9j2pz968wp3l5ukdkx55xuecp34e5pszjku4m
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSakpNTmczZGNWUmlxODlS YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1U2d3WXpqbkNQUnhvNmxT
eURFTUcxLzZtSU5RT1J0cE56TXdPb3NsRlJnCm1pZVBGNFJrd0w4cFhFMkxzRmYw NE1hUDFSZXBTOFlQMFYxT0F2VkdzK1MvRmlnCmkvc21GMTJjNmlXNWFxS0JsQzBL
Q2thUU1DVlhBc1Z2d1EvVEJvKzVQOG8KLS0tIDk4MUJ1Q1dIM1lkdC9KbjgrNG1n MUVoWkdMR1hOd09MZUF4bUpubi9CM00KLS0tIDdCVkxXenIwN3F0YW1COEJxMTFn
YjF2TzltV2NsTVNRM3pRZVByS001R0EK6d+Hwl4dQB79n5Baq8kQKUqYaifbp7PH a3VvbEZUUHNJcEhUMllud2tYQU1RQUkKDG5dUpTAKHdGrnD1U2JWWv2Ue/LShVwt
YUZmR8xwiJP87oFmD2lETgJQyWDvGBk+nM5glAjIqO6PEhJBvviVHw== XRgdjTwmXtvf2s9sIetX2rLiJxcLkpRz8z+AjK5c3GWxF6ZVPuuGvA==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh - recipient: age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBRVVYweEtGQSt2Qk9Ic2pJ YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjQThNQVJyR1BVOElNNldl
QnJlQ21wVzJTZGNrby82dU41bDRkWTFvandnCmtYSUpFRkNSZ2FBNFhpSURQVXFt ZmphdkE4ZVpaaHE2N2tPdGpxMFFaVHUzZkg4CmlsSmtRdnVMSDhTK1p3S05Kamhi
ekhBaHRlc2tSS0lXdFdRdXR5SEd2MzQKLS0tIEZTeFhqZjgzZDVwN2NxVVluMVlE THRVMUE2d1NDc3FIdUpXQXoxa00xRk0KLS0tIEhhUnBIQnJQUnZKU21vTHk5WFVt
ZkhzSFkrS2NMK1diL2RwbnNzTzNQaWMK7/Q16epHfSDQ4q29DN0WpLKCWh2rnLJC cUhkVFRNMHFkdVFMQTdWWUwyVGZxZU0K4Dn0V7ulWdSOnsFSaFTBdfOz6RD0R3Ba
cKR+gQKXUNzt/7Osh6eWuCVWMfc9p03ruvlxrJ416Am4k66kbAmrQA== MOM2I0afFAcbQI2rzdySbGzy7yJeuA1puBbrHDMOkVCK2soYm3Gerg==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns - recipient: age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB5OXhuNk1VcFhpWWJYMHBN YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBjOVpRQVJBVWFnaFR6SnBo
U2pjWXJNbFpUZUdBbWFxOHRZY3N5bmxwdUJvClpTc3ZiTmpyZW8vS2UyNGh6N0l6 UXdrTk4yMW95QStMOGFqV0paSHp2Ly9Ga3pNCk1PSnFOWFUramM5OUxLU3BibG1C
UHBnTk9lSTEyOGFvSnRKUE5rN0lrRDgKLS0tIHRsOXJiR3RwVlRXSzlVRG1PRWxu blJtc3dNTWlBek5POXRMbUZDbG1WelkKLS0tIGZkVEErZ0twTFV6dWhVanUrdlpY
Zk5EVlJUekwxYWpuVkgxQ2oxcGI3K0UKmA+Ae0Ja6CfkGL3yhpGsmHVdZLPz2/Sc VkJDQ2Vmc3FPTEJKbWcrQkRwYnN2TG8KO245mM0A94pLL4/EHi6/eeh4rak02IuR
TYeUhIwKRJql7Rg4Yu0aG//2gK0HKLnSOq/nJtSIJ+8P87OKTYg8iQ== n8rBcJ/U4qOD+1QNW+mHbGiNNSHLtGHuVrM5uKaruRJDmxzNWQjmXA==
-----END AGE ENCRYPTED FILE-----
- recipient: age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkUXdnZ1FLenQ3SjNwN3c1
aTREVTBhNEIrN1NWWUJ3SlRrQmppSnVTc1JJCnFydzZoNEdxUVdDUEQ4UkUyUTYv
aXAvZmxXT1ZkSmpCWUpWeWJZYXFGcmMKLS0tIDdySzROS3dxSk1id2FKbHZ4UERG
ZzZzYjVjVCtMdVpoM0tzY2w4Mm9aSXcKr88HZkBxwuRzDtb/I8D7uopzjglZQsKD
oEd1uz/uYhDvy58MIKz9nnTMKyPUOE+uICZbjZ25ZsdkcDdCWNhyig==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2025-11-19T14:09:27Z" lastmodified: "2025-11-19T14:09:27Z"
mac: ENC[AES256_GCM,data:tZ6QzVPivueZiC9Qfb3KNZAv02QatgHRNnlM+Y0iV4BZkYoBjxeDojutizvAMwUarnubUdk5I6m2OZK1mvVDZKXyI6zALX4JMeT2xYQWRHYzHpOygLhhGwTFVhV+0C4jN+eJFF2cNf9lu7NuZI9ylZSOY8I3YKUl+l0l3CkXUl4=,iv:JSGOUq+j9T/NXspn70dfu0J4ISV6vVFZUe/Z1CirrJk=,tag:Hm9N55f9qMc056nSTR1piw==,type:str] mac: ENC[AES256_GCM,data:tZ6QzVPivueZiC9Qfb3KNZAv02QatgHRNnlM+Y0iV4BZkYoBjxeDojutizvAMwUarnubUdk5I6m2OZK1mvVDZKXyI6zALX4JMeT2xYQWRHYzHpOygLhhGwTFVhV+0C4jN+eJFF2cNf9lu7NuZI9ylZSOY8I3YKUl+l0l3CkXUl4=,iv:JSGOUq+j9T/NXspn70dfu0J4ISV6vVFZUe/Z1CirrJk=,tag:Hm9N55f9qMc056nSTR1piw==,type:str]
pgp: pgp:
- created_at: "2025-12-15T21:53:33Z" - created_at: "2026-01-02T21:17:29Z"
enc: |- enc: |-
-----BEGIN PGP MESSAGE----- -----BEGIN PGP MESSAGE-----
hQIMAwDh3VI7VctTAQ//T3Ld00/QPCKpVc4bonVGR1XRF8POkqr1eGc9locjDs+x hQIMAwDh3VI7VctTAQ//cFd10y5cI5pCudkNrwJjjCvaJmP33pteHYJrzH951JFt
MZFYAUApLXsM2A7W6hPa+sgffHTPmyjg85xC3XC+Z9aWCnHAh0tFjU0OdBaMOaK1 FmO5NVPxFkyZIApN2LJ+neqDhfOHWoAqb+2GWeAnKQwqWWD3mAMzTFbZ/GnfNTpJ
ha3nX3FmmC4QEuUs4elA0/CwfRG/16/bRTV+ys1jESM8AnQt9RhsBtDqJ42wNLFW tdGh/PtTawnjl5olwv/TSDj4DJSH9B/r5KJG+2oKvDNYHQ06K6qVoZTtlI9wA8nR
zlM96X+7j3DGyQAkgFV4qW4uL2tpPgnTgpvhjotW4Fl0xsBzf8E09IvmDGAV7sbt TLZlqlHlLNrYBBKNH8hUcdwCbd9wlBZGY/dhprTUlKb+W7i5LszQJuKdmxUj4njq
JQcSAUxZilKjVlwutz2AnAOl3fLaaBuNIYySr0r6pc4uv9W9g9z3NdxkKLrdAN4w QVjxMG9AHKn+SU4awAOyEI0uzTdKApem1REaJE/d+quaR7KLCjZIpQ3n4SsbBUfJ
UJglMIRai7Pv4DA9QdC6khJUswngfrk5GWuRTkqNSMkVOi5pl9y+Tdw9qKuSVFoE yAsBv57JAlxbaG5xuMZ/kjWQaGiufUK0J9IBfEKAyHZM//iFl+CAPNzPrQDPI4wy
GGmMzdmbFd7XOAYwIawAZqWAqlZ3mJaxAwSwut1Gls0u6BBQh4wjYJW6yknS8qJg 6HRL2r9EvUwZb6vJYskd8Od57nT4/0+zV8bSzh18JkEc9UKvMn7d4bx7AnKU+rsP
Gb92+Ly4r3/Kt+iOxpL9Uz6JUWtk4DFRCAdiwGdie6tnoB6VI01SVzkw2aDj7deN cDeIC5JTJjygaiodIdYAYS81FZZGj+t04hrAzkiPZcM/+3JdHNkuxV4jKbD6ljzr
kG7AFx1kofX+kUvi6gKK6kN0cZuwCOlyUE7OUSWSKWCmVzqUiDMy2WUdw+x5arqc xdCaJUXSmGrK4uznLFoIBz4A35UHSwSsa8s3RUL1Knem59cGSMVqfz6nJPQ/0sOT
zjstPzBWW/hLr5aY8vHpPONoM32KWc6ewKnxeVt8kjCh64IHOJQ4c6ilgghqECUd tI+8VI5HCdJ0vlNw669opzgGGiaIKcBKWfrXsxYkww9ekWxbjWaBcFLKm3g7p/mh
DN8AnpCXWeP09LkOu5rNX9miuLAEIGEYXZoP4bfVHKxP6jsx9jQdEBD0G21RaFOF KzFRmQwcOXG6nQ2ROUnL18Jh1u+iiXvzc17yK/6xuh3lLi+wvfRXMb3/ePG4j86F
AgwDC9FRLmchgYQBD/9lPhj+gc929oxlP7cEanqOpcb3lHpS6d6wOF1PXoFn48P/ AgwDC9FRLmchgYQBD/918RvwuPqcGLYgUJLJr/ycnAG5EzoSA7qqBvItgoJfzbah
JMchtMpNfQZ1kDW5CcdoG31zeTzhjpUlYVuZHhvhBuT+pEshjZOsw7vY0NAdScFE oCnnVRwAyvvvYYyqWrpIxc9X5w8vD5CeLDWEX4slm6AXUbBFK9i+tesmXC6D7du/
/45MrKsRKeHEkhKcke6w2BNW+o+202ZIjSZv+1QvAQYt0wGfI9EzYclE9CV9zcrm Sb/DHYH1Fa168nZ/oK2YieVQto6VS0WK37WqT6thybyEpYZu898tE9mY9riKlE+B
3M5exSXVOYgt6REwEVKb0OaoAAgNrlRpJRj8CjrJ5g1vN21wG+anqhaxYoWFdsXm JHKjGailLl4KeaWbZQgLNP9KKi1wwOC/Ae43SS3XqFWu0zx/l4RHn/KvNNVcYyc5
LMKY9eyAAiFm01RU7cSHfl1Qy1op3KzpbQyabQ6zIbq7BS/ouo4jGyMyHt3DPT1e UuuBHhFem12f14xVy2bwjELTkQfImlBFmPmbN2sqOIG8maFzdwUVfVMcAR2Ceq9Z
EY7dkNFcZh5sIIZEmKWjFbjIXT/urVWdKJPfkdC/QLsCvm37V5sDs8JB9JFivumA pTOL2q7NCZ/JlwZ25ficJ1Og4Wnk3oTQwZswoN+nApIF7Td1QxmDLnGB8xmrnLpn
LcNgFVmoCdmM8K2f98q3R6K38VsNH+AgcJA87RKGnHMw3NVnHthR6x4T6+cknK09 7A1PCo9IR3MdOatqN2xvotV1WotYTz3lcqpHfsYpscEBuyozxVw++1c2+QpZtmBQ
e0iV6wdazNN5/1Bmu1Y/JrnaGyIAuyoom0Nrv+OTVgjjenftw+J4GsWIpicSYHHc C3MQoqUDXBwvku5BfVG97XFy1QDCCTelUPdNCvIkXoJg9AUugPYRokCcI2bTybFY
mN8TcFqqrZ9QjHQS9BMXFNLC+m1HGpP4Mi8J7haEh6cIURFVkmZRDl+SUwnqX+BN unL0sirc8+/mgEQTwZgJXDhtvYTpps0pj5PFwdDHRDgrW/CzSkLz05HIKl+NKDmc
XtHs2q0Ht6jDY1K93StrXTFqNTasG31MUEcs8og/KkUhT4LGRIrAJoR70jPojV8c +aIxFLAQiFBiqgJneb5q3GK7uZq0YVIb86MD5sqSNT2Utz1KMzhL56sTjPEtn73E
TQsT/bLFgYVvKaKPRoI6SbJyhQeoJMnEoDFAZdlB78KBMcRSAHZt16j6f6bke9Jc zfwMX/EpCkpshsfbG1hLZeKPsYZBAo14Jbv/IfWHX0OXp6EVWrLM4FT8sEEwWtJc
AYQEzirwmSjViuIEnu57k96w1UHJB+rjjgP62C88A0ENr97UbCacIC8EemFN0xPP AeNU3uXSpOW5xlKv6bpNSl0A9C8XYK28FU8JaENq85Q5VZGLf4JP2auFXQ2PWbpo
UDubuNbq7O9XAfoXbKy8jqeciZVo40AF8YN3HZuRnrppgik5zzs4o3yBv5k= 9MmhPhMNk4a5aDh+AqaB7yXCFvqzsGEJu8Xqe3gAN8Jn9ThMvUW+nwm56A0=
=1hR6 =arGb
-----END PGP MESSAGE----- -----END PGP MESSAGE-----
fp: 4BE7925262289B476DBBC17B76FD3810215AE097 fp: 4BE7925262289B476DBBC17B76FD3810215AE097
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted

View file

@ -41,143 +41,161 @@ sops:
- recipient: age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza - recipient: age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1UEUyZDNVQ3U0NklpU1Bs YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAvcTNvUVVSZ2R1N1FKWWw5
VndoTnRBMW5ESUlDWi83TUdGdXpMeDdRam1rClh2SU4zRmFscWtSWFMvYnlySXAw dGJHc2swRXN6SmdvZ09zTGhYa1VqWnp3L0VzClZvYmhYTjdnVytBZFI3c2JqdlhI
S0hjcVZZN1MwTm1kZ2xUcVhxQ0wwdHMKLS0tIGE5djdQZkl6NFdJMUJPVWh2ZEJW M3NiNVFQTXkzZ09ESkUzamRleU02WFEKLS0tIElxaENIb0V6RElZeVZFZWRIRzlH
Y1BMbDgwaDliN2tLdjBYOU5TaG9uaDAK0bHyEDpXoM1hZlhw9uJVOpCG8FnfONyh UE1mM0VEOExFNm9OaUV1NFh4cEc1alUKX6niNF5QxQ9ub+grPkUqeLw+gjBcwV2A
cZKAl0ykQ5dZ6pQo8K/4jtOf08GesZIRenyCxIE/lNZBvFg6OgJBJw== Y7zeR9eYAABCkDh789luQd37LXP2QdD90hiaDGMQChVMpmcIjdP34w==
-----END AGE ENCRYPTED FILE-----
- recipient: age18cgqlely56hgmhscllkmafwpjdk6dwep6ej3vkk97dzemp8jtuksqrrjjl
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOS3g4dEhVYlBGMXNzcGN6
ZldoUVRtY3FsNVNpcXI2cTk4T3RzNUQ2cW5NCmFmUXRXb3REaXZTVk5MemhOaUNk
bjYyYThFSm1ZZ2JRcDF4WnFxSndxL0kKLS0tIGJXZEsxRS9LcVRrd01xYzM5QVQx
MW9TYkhMRUdXZVVBeVkvRUFQWElhMW8KIhz1sFGRNkhVyLRZjA3IyYInRbNhN/Qq
5OWHJj/iS05xunkPNoWfxphRtHRudljgDXpt2UwYgWoTm1cAnoIj5w==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d - recipient: age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBpcXFsVzNBRFlsQUxiREZI YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXbkc3aGtMcXRiTm82Nllp
dG1UVEE2c0NzSjk3bEM1UWlXMU5wakFZTFRJCm5VQUs4alk0TlYwNmRaOUNFOHdW aHRJdFVvcXp6ZEorNmVmUmIySzdRWW8ydWlnCm9oYWZhTStJQmNSL21hVFFyOFpL
dC9CTVRuODFnMmpxRGY4L2l5azU3MTQKLS0tIE00Rm1BSDh3NnZRZ1BJbzVLL0t3 aUFmQk0wbzVwTWRtSEtkQ3RFc3hOUFkKLS0tIHo4YzU0aHhFVmZCTGZWclNpakdn
TzM0TExsbUVXRUhKMDVMS3B1VzYwZGsKDD5JXe6ySfCrgiVXN8NjI75z2nr6HuhD eVVDYUNXUk5BM2M4MFJjVlY5NzJKd0EKt/vaHVeTowmbc8MfQwHqxnbolf0t5Th/
cTx0S3m3KD+uyw9bVVdUkRTCFaLwD05080PN46uB532HsZAMLLSFQQ== wBQHe+MUBg9lCr+TqDi7+TaRYa93V0oiBVQ1uDLweV5olpOi2ttc3g==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1ly2endyt0y9xyddj6yuj4nw6fa3ltvzlvew4cr4lzs6dv8dkavpqadmyxx - recipient: age1ly2endyt0y9xyddj6yuj4nw6fa3ltvzlvew4cr4lzs6dv8dkavpqadmyxx
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJTFYzakJ4cVJoMnhTUDFx YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBDUVQwYXNiVTE3dENRV2N1
SG82QWFMWW9La2lOcmdPNlpaWjNpNk11M0hZCmp6TXI5Q2NLa1ZieVdlbllhRUtB Z3AwcDk0YkRFZkRjZW9KZHFlYVNaWHljMUNjCnJmN2pzaXV6RFk4NmVFdSthYVcx
cU1EVkZxa053NFJkZUs0bE00MnpsZGsKLS0tIC85UzhzQnNKUlMrdDB1SDJQZDUx TVpTclp3NnlBakNaYUQwMmg3VVM1SDQKLS0tIFF2enEwWXAwYVVTeWxNY0kwRWdC
d2h1MEJHcjdxTXEySTlLNFlnSDJoSXcK2kWhF7v9mm3EIQoJ4aQIT8I/INKB3lSf bVJuaEdsOERBKyszcHRYUFpUcm5zeDgKISCkCqLSCUwSM7XqrY+JMW9OE9q5sfbB
xEscNVOqeOGnfdrOIYHBWhWIsBNRsgfJMIxFY8TVxmDNGj6r4GqvHA== EXVLqqjqBICQ50vtnGywG70qu3WXzpuVy0NK+zA/3sgVpXuU6/Cplw==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age15klj4t7gpfp69472mne4ue62pp6m4e04dmjyw7yf30qtqd3vl3uqjmcyxm - recipient: age15klj4t7gpfp69472mne4ue62pp6m4e04dmjyw7yf30qtqd3vl3uqjmcyxm
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBSVWU3YlNtby9ZVWNWZ0R1 YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSArYnQzTm5nMHUrTForWTlq
NWV1VUo2V2hJSmJYVlJmVkloMzVxbVFobVdnCmxJV3ZvUzBrYmFLYW5NNWVWdDl0 akhabVhFRlVxQmZFS3RId1RBU3FTYVl0NUJNCmRGUlp3QzR2RFVNU2Q4aGlud1BN
TDkzZmY0a0FHQTVmOUwwajhtaWRqNjQKLS0tIEJFUE9Oc0IwTXpJUFFjUWxXTFBW bWlzWnNUQnJlelVsS3dhWTdyTGgxUWsKLS0tIG9sRE00QVozUzJ5eEJtekRQWmVr
NmpVbzRDbzVGOW5iVFBQYU9FdFJtUU0K1NAuCYjrYUZVLajR3h7Le1p7ZDcfGYpr YlM2WXdQTFJRMTlZQ2xlTzMzbXFFd0UKZBiT6x4zfpKQctOCUFmBQHzWZ2rFIIKh
kctaY2S80mPxN2Dv1Y81S0G84ptmi7NXTCghDrPhkdrnzFd+egeWvA== Lx2oteWtHrGABf+wc45ypz6CBEJjw7moBf7ZCupOOL+jIJpe3UriqA==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1k73gy5em3js9zklnnkzp5hme9k04lny32fgahmzddknjw5c295asdyr4x6 - recipient: age1k73gy5em3js9zklnnkzp5hme9k04lny32fgahmzddknjw5c295asdyr4x6
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBkdHJCREhwRWdqVXVYa1o0 YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFcHZqNFJWNGFOUUNkZTlN
dEdRNjhxd1VxWWI5b3dQQUVacXdmNUxWSFZrCjFFdEJHNmFGeVhyZVdSeW5BQXNO L0IzcU9qR09BcGQ5ZGxGMmcxaWx4SHZDakdvCnZpc0N4QzNzTU1XWWhZYk10QjVN
L1I5VkdBK1FEZFQyblVtOWJOYzl5U1UKLS0tIE54NENJRUt5bzNvN0NIVVhlNEQ5 dHEwMS9xOGRBSlFKQi82eE84aGMwbTgKLS0tIHNjNUFCaFdEM3lmTlhNUDJHQXlM
YXFPeDBQZUJsL0IyNFVpVFB4NUdtZ28K4LIamLUU4zn9MY7NphIjfCMSWlwLkF1c ZVhBQUNoYlMwQ056V1ZCRUdrdG5ESWsKO8a6+mhNR2jzTHuKROp0QbFFLJD0TN/e
8zqOyNS5tpjCsdZ47IInoPSxtlKEq/97PV/nUzw1BTH10Rxx3ENCGg== 5zKySP6bHrlcK9fguXWnOqshWuxPdECNmE32L0pm9maL7G2T4FhvzA==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8 - recipient: age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1djk4SEFBUXF2U1FOQjZ2 YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBGWDdyVm51cFZ1SjNVQU5L
eTEvaWdMcTFzY0ZBTk1XUGE0UGUzNVMyYmlZClUwRU9KeGc0cVZGSTdDaERQSWhL UUFqbEhkV2puWEJxVmJkb1prOGNnZ1pRZG44CkZpOEZ5dUdjN0NYWXZSK1lLMERG
bHhwa3RtUWZXSWFxYmF5UWtLK0JabDAKLS0tIFR1eHFPVGNtRDJFMnNoaVJnUHlJ M3Rwb3FLa0crQmx1YkFZTnZlVGF6Z2MKLS0tIHpmd2RyZC9ZR2lIQUszZlNQbUJu
d2k4TjF0a0tkbFRvVGR3ZS9XcndpcXMKpqZXI/APjHSqR+j4/k4UcQfdL7toFGHJ bVNkMTI3ZXpDY01KamRFb0FmY1B2dWcK1RRtVtIwzgckwxX5YEQWdL+BHUdEAD57
9vRdsWWYGae3JABNpFGC8xCpvEtdPyMwEQw0JpjkRz3n0KKSa0XL3Q== 9Y/lLGzhGHwRA9lYaN8q+cpMDjhuIDiDqSZV7N16EZcOjZ0MIjZonw==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx - recipient: age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBvSVR1SzFxSFphazlaM3Jv YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzaXZTNU4vNTArazNxZnBz
a3V5Um5hMS9SU3FHTXJmQW1ncWh1VTdXNEhVClI5NmowcDdzSWVsTzRWSzN6L2JC ZGNrWXJ6Y0JSaGY1UzhjdzhIdVVsNjlQUERZCm5RV0Ftams3US9WVzA0eHdOTkpX
R3A1NElHdmFFU0psejNlWkNidTlWVUUKLS0tIEZWMjM0b25YSXRCS3U5aXdTN05W RVYwS3MvUXZNOFFUMG9VKzh3aWk5YjQKLS0tIHZhb2ZSYndLcGJIK0xURTRBR2NQ
eFUyYzZydWdvTjBTV2JnK3dQam5Ya1kKBhrX+2CX9ZJdymOY5yC2thfUY3/N2TB2 OVN2ZURGSWxCNkViK3NFSVRqdUo3aWMK4tjIx7paJg7bTgTwjnXjbpHE+Vvf3YbF
LqUctgXpqxk67bupTN/wkfSkYV+//FdSdVtLiopnXHC5k0QIVizCSQ== C9Ekp1Kw0k+THfTgnjwyNWuaLv+8VoLqt2k10H+oALjLHxQKpPSmCw==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1mjgw3nxlnqdj04mgjz3wn7fj2nl2nxla4p2r2fn4nkvayfgp09pqllxzyh - recipient: age1mjgw3nxlnqdj04mgjz3wn7fj2nl2nxla4p2r2fn4nkvayfgp09pqllxzyh
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2bW5hblpKNGlYRkwvVXpz YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB1ZmV3WUc3SGR3OU8wb1RX
ZDlNdkNjS1ZPSGZUbXdnZHgrTE1XaWw4Z0FnCkNEZ1JFRDA5eVJEWTVGdVdwdXNI aGVLUnJWdU5BTE1uSy9YSUhVUHIrMEhDVVVrCmhNYW9yd0I4RnBaSlJRRzR0R2NS
Z1JXUnhXOXdTV0RoZnNYNnAxREZvV1kKLS0tIDB0dlM5ZVNzRlVzRDU5QjZDcllU R2JkSENzQ2N4ZW5Xdmh2cW9iZHVvNW8KLS0tIDA4cTI2YitUMFlVL3ZlVFJlT1du
VFVjc3pZdHphT1dwYnV6NTFtTmViSTgK7a6/HWAV8Bxf3d062LFXB1QyTqvfLFPB eXh3ZkJyRk1oOUlmM1dwdGUraXZsU1EKCVvFlj0X0Q79116nQ+8Ybsjk1HBE55vh
ZrTV01HMKzleFY3Fv9HLjJNGt/l54ZVdq+Ea3sp9UUfw+BKMpoqrrA== /j5g7ggeLdCcoU7qEevHvBukbGa84xmiwJxa13mumI7Yi4383P8Twg==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl - recipient: age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA0M2dYWVBZWVFNQ3JnWXVn YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBMZkptNVRuYWZMWmZkdXMz
YVNnYWFzdGxXeVhLQ0tBdzdaYzhaN0p6cDIwClRXNUNtYTRiNXFCZnZ6WGQ5WUtJ VDR2OEpOM2E2S2tZOTNPaXQ3c0taYVBZVm5rCnNqWnNHNEt2SlphdmhZZ2hGS0JE
VzBRV211YzZ2VzNkTTJtblNFZ1hiUVUKLS0tIFVhVEpCRHZOTzVsUmlxT1VXZWZx RXlDQ281cEtjblNZeVBvWkVUaW5lc00KLS0tIGRLKytBRWNvUmlJZ2RzZHZWdFRy
bi9pWnhsY0V4TjIzN1hqeVhkb3FsNTAKcngM/MK1uLuw2i9AOxPnscD+OLopKIuv K0VWbzdiOTRvbllSb1dIemVLNnZiWjQK9StbdLSPG2h98Dao5ZG3qvhvD6iSg3XK
B9U7mSE5zRyYFgXK8Y+s8r3CBq9NUFlKFv8Rl9wmD7EMa1DfZ5GF7g== MhgksJ/YfuWo0aaLMZ++1jjGD3O5DE3QbGrBA5R2RcInvUi7jHWBtQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age15cx90pnp54xp5gxlt02yn9j2pz968wp3l5ukdkx55xuecp34e5pszjku4m - recipient: age15cx90pnp54xp5gxlt02yn9j2pz968wp3l5ukdkx55xuecp34e5pszjku4m
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1Q1lSdld6Q2kxMjJ1WTlB YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAyMjZLa3J2dUlDNnJmcUtq
M1I5MTRpMkNiRjJJOUVKRnlJcnZsd0UwbzBjCmlsMlFvMnp6UitRcjR3NCtDZ2Jz VndpSWxGREhCY21xRlpNb0F6dVhvZXV5YkNNCmJaVFFRdGY4NEdUcTZ4ckhmZldM
TjgxSmwwRHFMQjlrTUFTSVBpNU93cXcKLS0tIGxxMXU4aURVbjFpSGlLS2JYNVdF TmU5TDRwTG5QMGVHN3BwOWZuTFpQWlUKLS0tIEg5TjVjOUpaa1dabTlzM3REMmtz
MnhxTURKWWdzWCtaMS9lTjM3YUdNSDQKhNFCq2mRvWMAsCUXrpiW69ti5LfBilp+ ZUVWRGFsbDNWRTBaVUpnZlZLYW1GT2sKInrMXDj0MLNb4r2hwZEsw9HxpVE/eThv
8B+mk86cFxhpaZtQLOthSBhhzTTdScCKDTywEVV6K51x1DGHqrYfbA== TYyiPbaNkzr0EqDcOQQ/3MEw0Q2XPaMDdCG18u7kYlGGwdYNcWRgmw==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh - recipient: age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBtR2NWOW45T0VSeWdPSHBM YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB0UVBvdXMzRVRuc0N4NktF
OHJWRUUyaW5qbWx4ZytGOHJuQk5rRjlIRjBVClFJSm1kSWdGZ2xwMFE2TVRkSG9W MzdnVExNWDNGanc3cGc0NkNoajJROFR2MUM0ClIvQnk1RmJCWXJZcjk4aHRYUTkv
Z0FRS281UU5oSDkzMHkxOXhIMnpzcUkKLS0tIDNNTUhMR2Z1UVcrOFhRWWRYdUFF cUN4NHJaSWxHckw0NTV4WWxKWHZHelEKLS0tIEs1em8xamQ4YnVpTzRZMDg0UkIz
T2d4dnJxTnBueW1LWHl3VnJMTm5abEEKUpUtH/deey97QuKWMFxabVSrpzzfaoSw b2N2RDRYemVDSzZESVhUOVR6MUEydG8KVLj9kVMaZeKDIQiVQF9lu80wA0m8CuMD
pR7nianRBaD8b8HsC8V7x98CenFBK0jVQAkx9VGMgqIGDsTaHiHPhQ== IBCwg5sHoz7fAK8vHpUPKh2XooD2BL9q0pPZCc3sCUjQvLgW1ZK1YQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns - recipient: age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA2Zk9wN2hRTzJYVnZ6RUwx YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2YWtZNlJBMUVna2tmODdo
WFVtdzF2NUM1QUxFRjdYNHVOWFErK0dOM0NZClZpc0JQZzBNc0lFd2IyZDAremZQ TC82U0ZtMFV5L3Q4NktxZ1N5cklyR0ZUZ1R3ClNzSEhEVmg5WEpROTZIQzQ1dm92
aWxmK1ZtOEVZRFF5ajZ2QkFmK1J1bWcKLS0tIElpNHh4eDZZaFNWczl4MG9ZdjJ5 UGpxcHNzUytVYUM5dFJDcVVzVzNuWU0KLS0tIGtYaVNBTHNYNVZQTnZUN3BZSEh5
L0gzWDFia2Jha0lDaGZaSWEwOWFmb1EKJqqjxODIgVeiMKtV6361sjYQa559pKCG eFQvUWx2Y3JPa2VCem55TkR3M3U2M00K5TSdJyIS1yCV8GIYZgWlSC/y2r5+hquL
1pKczlzXxL1FliBQoZZGq55NR4azWYEl/yV5tee1dtUohJW0pAyScA== RLougeJFaSXiZ9AOzsnC9jGzzBVvlsf5RNH+fYsK9oHuTH3Kv/s8Jg==
-----END AGE ENCRYPTED FILE-----
- recipient: age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBwWWRpTkFsWVZGbkY4dmli
VzRQaWt0UFM0L1BkV3dTSjMxbm4xMFhCT3hVCjNXbllqNDl4cXhZaDJVd1gxQ2No
d2tLL2VSY3N1T3E2WldHdDlwNXBycE0KLS0tIGd0YzUrZzF5cjlxVDBwWCtiZHNp
RVFnZWs5T1pxN3VHRWdnbjR4UFFIcGsKUnEeBhX9K2tUNd48XOvpb0n2OoeUPyq2
N+LBxwPYoSxoiZAW0vDg4mNcJwALYDXA5ew0fSZj1nP2LvaROV84Jw==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2025-12-23T01:11:36Z" lastmodified: "2025-12-23T01:11:36Z"
mac: ENC[AES256_GCM,data:e0WoFBQSR5q3GOQ+GMJGBd4lNBAMqlnVjtUq3snxrdvcytb9YvKnoYQH+GjbdGIiqrND8pOVnZt34AjkR8YfpWe+VrkP3Vj/3l+1GjF1XIHbzBNKOQHdYPSVsH2NZwftcAdphbStf3GTlb+b+cpTn4a9Y4pTNGVoOaOA1tBr8bM=,iv:sPXktitTNMkBhHr6E/QRZCVKrgyED9/o9hiivbObACI=,tag:tTNr4UEf92UrtI0Jvi5o3g==,type:str] mac: ENC[AES256_GCM,data:e0WoFBQSR5q3GOQ+GMJGBd4lNBAMqlnVjtUq3snxrdvcytb9YvKnoYQH+GjbdGIiqrND8pOVnZt34AjkR8YfpWe+VrkP3Vj/3l+1GjF1XIHbzBNKOQHdYPSVsH2NZwftcAdphbStf3GTlb+b+cpTn4a9Y4pTNGVoOaOA1tBr8bM=,iv:sPXktitTNMkBhHr6E/QRZCVKrgyED9/o9hiivbObACI=,tag:tTNr4UEf92UrtI0Jvi5o3g==,type:str]
pgp: pgp:
- created_at: "2025-12-15T21:53:36Z" - created_at: "2026-01-02T21:17:35Z"
enc: |- enc: |-
-----BEGIN PGP MESSAGE----- -----BEGIN PGP MESSAGE-----
hQIMAwDh3VI7VctTAQ/+J73641lle7VHi7015hM2tzDaDhtLfoPl7R7jz2dOSmFx hQIMAwDh3VI7VctTARAAzjG3sJ25PaNOD6VowSNYaaK4DCY6PU2LGCCpJWzDXnwo
FXfzu0kHK6Mg44WC5pcWvIHWJA9D0bKlMO5pxPO9vrG6tNU6C24WuibaLYbYWQDV irJZUtGOiqeZeu/8BdWmQSwBiI9k/JuCt131rwXCrtj0+Yj0MRKTK/xc8NoDnW5t
7Gxbgi1SPEhLZY4BOU4nObRqR7GfDyHMVASKzzO5Rp15t4vxKko5VyPYPkX96XrG R0CpQnWJ8yc1RRAMhx9l26HXH44786rhVt5/4ZCvq2mje6Ha0yK0vmjO6P+WR8kA
OHcxeHe6BYBKCE6beee2KPtVfWtWxuKmK57inzeSnCGNVAXI/6RX7GMcCa1Y865C AUCuVUtQCtN5UP0yecdRHl6MvZe1qPd8tv3kLittJ2c48LD02CL3g0ZeATtCgiGN
QWvSmO8h6rEvCtj6heNdj39p1Iz1MckqAepsaTw6hpU9yiLkkiGzimZaeOJjU2V7 5h9cBfDQnFcBh5EuMxn3AoGQjIJollCS5fRNNi1VUTp4uyAqYnyRjnORNI6vRk2k
hOfqmawpPWwGic7pcKE1kcbv9e7ogtcIOd1up1fWNn9jZ3wErwUiFYfT2oKfqlFB hju5W5ThidbYQlJlwO6hZM7e/sW/XM8RWi6x4TO1VN8MuXavKnIbzlOKmJZlLbb/
rkO5IrDy6zvfF8diKmHM7/NiXwUa6h32uHxnLv0AcK8nOKaCW4ZcWOwmbu7gcZIb yp0ueIzKuJpEz0nQZh0DFCD/D8yoTAfgtXgzzZKuUgErhkCQEXe/xKPDFvSKkWqA
3Kl9teuaJ5FEV/7giz3lf8Fd5ljyGOUE3t1TWjJxzI0ovBjFMy8l5DEWhoNejfqI AnVl6RwyTl5110Ea3535K3vycYR0EAxapEqzEZ0Ez/o28wR/1hgMrTWE9f++6HwT
cB2AbQqXuuOvdMTC+qaftpE+XXiIHniwQ3IzkUzhUE5p//xF2pk8SZkQ2iDn7Bb0 wZ7EiPTs45yzZYJ0ONE4s9u9HNIvUY4UX3ncIhvTIWMyASfS2dbDu5fqxg5e+Szk
10p8TD8aLM7AuHd0fpkZPxpAyHCrN++i4wjsv8qdq8obmZ/BzsY4eUJnvcLlfaER 9QcDL0bzLnGCmR4w6fKUl2mkupTMsi6sfRFMzGlabK6FizUnpwNQHd2LAxL7rNF6
zMUuoT2JhbSLaFRgxgGrm/ez022X4pFmF5ONbbTrAEMxwcmvp9xGwy/krV43qX2F JiD6LxVQfY/TfKqQdKa93Ctf2k/tkdW2aw8JKZh02V9PqXUax0N4uR/TxOjKa/GF
AgwDC9FRLmchgYQBD/9PgG+2n2k5sUCLh266s4cHKbpVZdOnJ2uSiImyCtW95H2T AgwDC9FRLmchgYQBEADJTfHgtKmwdG4s+Mbml+VD3f0tDJnbOXBfISFp4+s/6Wf+
Uy0EpafcYyxEs/Hzz73UKaGDz9TwP2cAEVjQ4YumvrKq38SthyFXUAsiI8skXkic kILyeL7V4yllzJWqUZ97IH4BScUBSbvcg45IvuzgfTrBTx6ZSa3OQYo+2KS76Wsv
LSEgEWzD0hmvW167mg1PptQyiPsgfAOBw6X6QdOFWJ3nadf8+2AV55JvHuQ9SxC4 uQkItpGdsVSrLYDseH4cOWev9D5zscU+pEdT6VKXP47UHbJPdxQ2IU0oncrMatgm
ejOsrVCQL7rMhNTXP2TSfm+ZFM9U6Qbv/xSXKPRBiqEsN/DZXD8BXTUY7KBpazOI rBh+PfB+XeJRX9mKzsL9qVWuc5k9SVcsXLKSCM2IJszfRy/vsSJcAphReHxXHSuO
Ttjapr7DcI1ptMK/AIG1eJQAOpgRSsy6z+INpGsvbUIaAJDn8XFEt7kSMXGmQxDJ XYGVkSYLGgzA1by0wjZ4Gi3y8MVaUEm8rXYVnbaVRnx5bntEfj1pTjmqStH0EE07
oGtwHH1oDXK+ws/F3bn1FPZZlBVbq7fpSoEBBqnAd2jrGibEWEZ2zRBDSROalqCS vkOooLLDFaP6o4c58jvRTwXBWKlBbgWqoSBgm08OPKQpFFpM+14GrLqGv5ECti6W
fA72h/1ZRUfx8iFBRd6Mu2PJAQ/oecZV+dcIlTD7B3v30HyAZTtVC2Mtdmxqi03U 299pjfyWU99ILNG6RdQiS5MLA01z4wWYXRlxyNVXOHlspVaacX8cE3/uGOslURwH
TFTfhaeCNlficx1R1VtgAABlAMBeGerb6AuBVf9vziRkXiWcP/9RdYuTEJskHjZb ZbDgmpyAr3Ss5nj7s8plnxpYIRdXNCgPJ8qZtEVSuQkHbkHMKUJ8gycQNRcB8wZI
VXCQbEKck0YQHOds6QTu/+QlLZUoZF1LXVKF1iy+khc16oKYhRBUL58eJTOpYbtE H4EtOkeG6mLt7WJlWa4T2VF1AEfQXZoewkaWCK7JekY+DPyyK+b3JT6qArAMvGMl
PUrayC6PXE0tKg1Ghe/yVsW9rLWmu7FMdAvM44/PjyI66zAwzKEu6STVahIrpxje apVaDegSptYYUteO67yHwP83GNAGwDY+o1/ECZhG4ucGkXYpS6MCBkyCeV++gy3B
qKd1jugtsmR5kNK5CsORvval1iA6/UhU9fGdV9Zz1t6eyrMNatWk9yOO6uIq3NJe qotF5Hr5xSOK8jzFm7k4UUiBiQmv8IDh6UUOOXAzejxn61ZYPdA+aEIBiSoueNJe
AVqzW1bH3U8Ys+C7M/FHBskdSPnwgvANKb5hswadBkkRGep01HIJK5QdUj0W9CQ8 AffTd0ldG9HGm016X1uYrN63xNCRA6kVUWP+2c86CTGX2GKHb4YgtULBrVRW8hUR
obHQ1j0Rlzs70r6cxpruM9ddmGqP0/yRGncXHowrnf0ZnTzZr+Dhs+whA0V3Zg== KoofPhcaEVIUvrnMrPDIrp25Uh4DRakUMQUwsOjfliLmm03/07IJziTMWTZkYQ==
=jCXG =qR6M
-----END PGP MESSAGE----- -----END PGP MESSAGE-----
fp: 4BE7925262289B476DBBC17B76FD3810215AE097 fp: 4BE7925262289B476DBBC17B76FD3810215AE097
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -2,149 +2,170 @@ wireguard-twothreetunnel-winters-wgProxy-presharedKey: ENC[AES256_GCM,data:FZWAR
wireguard-twothreetunnel-moonside-wgProxy-presharedKey: ENC[AES256_GCM,data:Y/EwbaVbGljiz9XZmr7+/udBfeaY+CLMfnKzekXP50Hu8ek8aA1/SKs2qd0=,iv:BijEDkfpRWox8CPwCoZLA42WihYIqHJJgSgOfsOGcG4=,tag:8+qEnqTsqyNdD4oVPiuQuQ==,type:str] wireguard-twothreetunnel-moonside-wgProxy-presharedKey: ENC[AES256_GCM,data:Y/EwbaVbGljiz9XZmr7+/udBfeaY+CLMfnKzekXP50Hu8ek8aA1/SKs2qd0=,iv:BijEDkfpRWox8CPwCoZLA42WihYIqHJJgSgOfsOGcG4=,tag:8+qEnqTsqyNdD4oVPiuQuQ==,type:str]
wireguard-twothreetunnel-eagleland-wgProxy-presharedKey: ENC[AES256_GCM,data:dF8VPApd6iYKIZjBXB2rjIXIxyy2+U76TdyFuyUW0zSbtjzqn1ZKrhX4w/M=,iv:GqOHsS97di9sHqjndlq0EdWLcJ1EMLmDOnFJlBgTvYU=,tag:PdxEYlg3lPShUJYlANLjhg==,type:str] wireguard-twothreetunnel-eagleland-wgProxy-presharedKey: ENC[AES256_GCM,data:dF8VPApd6iYKIZjBXB2rjIXIxyy2+U76TdyFuyUW0zSbtjzqn1ZKrhX4w/M=,iv:GqOHsS97di9sHqjndlq0EdWLcJ1EMLmDOnFJlBgTvYU=,tag:PdxEYlg3lPShUJYlANLjhg==,type:str]
wireguard-twothreetunnel-belchsfactory-wgProxy-presharedKey: ENC[AES256_GCM,data:NAbVE7ysGDD6TT0RxdL6bTNloac4RBU1JWeTFqYo9PO6ZU2f/yq6aboi2AA=,iv:Ky4UvgRDEG1UgDmi+m5mHWHO+yUGzphQPYIuyAXDkhw=,tag:WP+/8q8jfitNC/rXN5Mp2A==,type:str] wireguard-twothreetunnel-belchsfactory-wgProxy-presharedKey: ENC[AES256_GCM,data:NAbVE7ysGDD6TT0RxdL6bTNloac4RBU1JWeTFqYo9PO6ZU2f/yq6aboi2AA=,iv:Ky4UvgRDEG1UgDmi+m5mHWHO+yUGzphQPYIuyAXDkhw=,tag:WP+/8q8jfitNC/rXN5Mp2A==,type:str]
wireguard-twothreetunnel-hintbooth-adguardhome-wgProxy-presharedKey: ENC[AES256_GCM,data:Gr9tP9SkizZOR4brFO3+7PqDC9pG5RojWa+xDDtqfZT4Xo6ZAN2002WGUXQ=,iv:Zj7oy/d/o5sNYTsyPaUQ9Th/xDuG7o82NpnP6TZzqeE=,tag:OI/DCxjJNpZC1C7foO4xsw==,type:str]
wireguard-hintbooth-winters-wgHome-presharedKey: ENC[AES256_GCM,data:57KGUxn1BibZ+9H9mXg9EYmcy1JBX+M79ACL3Qt0XEMl0dFlk9Wq6cr3JTg=,iv:9QHdykNlUU1H0uco21zA8leQH73PAeL+xTVi6V9zx7U=,tag:6mfSCddnVGMBEAqCHDIIrw==,type:str] wireguard-hintbooth-winters-wgHome-presharedKey: ENC[AES256_GCM,data:57KGUxn1BibZ+9H9mXg9EYmcy1JBX+M79ACL3Qt0XEMl0dFlk9Wq6cr3JTg=,iv:9QHdykNlUU1H0uco21zA8leQH73PAeL+xTVi6V9zx7U=,tag:6mfSCddnVGMBEAqCHDIIrw==,type:str]
wireguard-hintbooth-hintbooth-adguardhome-wgHome-presharedKey: ENC[AES256_GCM,data:zBfV5HMy3h6q7yEF6Cu7sCTONa8nJRmMDHgVFvHVinKmyj0qpf/WGfnyb3g=,iv:3JlNgsJHkE1EawLWIJaZsiZlu7pN9ymFQ5ZqdM7W+AU=,tag:pGfsh34HnL8mUhKyFkLniA==,type:str]
wireguard-hintbooth-hintbooth-nginx-wgHome-presharedKey: ENC[AES256_GCM,data:BGdVjcCyhrSgIIZtdoBUscCitNjBat56YjZOFx9Vao3vBMjoHFGY1WFV7zk=,iv:wxVClKJE6R178vCp/RE3PgBYYLIvOdSV97AfJagWZ8o=,tag:zbuMwlJYIKtV7ylwvgLutw==,type:str]
sops: sops:
age: age:
- recipient: age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza - recipient: age1s0vssf9fey2l456hucppzx2x58xep279nsdcglvkqm30sr9ht37s8rvpza
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaQ1VJOVQra2htZXhTQ1Jj YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOcGpVNWtxdTJLYWwxakNk
Q2xxYzBtQlJBcHp3OWdvK0phYmprNnY3S1Y0CnZ2c3lRWThEVnNmeGs2aGZXNlZZ dW5vRTNEOCtBNzlPbEpGR2g5MDhIYU5pWmlzCmo2YnRGU3FCZXBXUXNTdm5qNzBD
cEZaUnRrUFFZZGFRd25nTnBrVjhuc1kKLS0tIHg0WXBQVGh2eVl2TEl0RkFsNElP dWNHYy9kZTJwaWxHeFFmZFh2ZTBtbjgKLS0tIEliVHZIbWFFYUdOUDljNVNwUTNS
dXk5NmlTRHVENHRjbVVRd00vYkpoTGcKn4+hUSvHLU6xJA4UJSPWadFwPtyfKMii N0c2ZStaaU8wVFRKeTAwRmtDV25wc2sKjFO0FeMx3v5Zn4Ipm2549/boRorripM/
4wFBv1pRwUmxehIpS8C2HDnyBVnT0X/Sv00n27I2K4Z4/WzYTXPTdg== q11ro/tNhsSt+GJ4FTQA2hnmRj+fG7BQuTw/ewXC0posKS5optxAbw==
-----END AGE ENCRYPTED FILE-----
- recipient: age18cgqlely56hgmhscllkmafwpjdk6dwep6ej3vkk97dzemp8jtuksqrrjjl
enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBsTUVIQTFYanlUQWswRUg4
bSs4ZWZYcnFMVUlUUFdyVnE0T21IVkdWbTFnCkd4dndFcWR1RXRLeCtXWlYvTUFn
Uk81dHZXdTBSekJkaEZxUWZnZnUwR1kKLS0tIHc1a2tpSmNOc0s4akRCVzVjcVQv
cVNDL1JGd3dGNnIxSHhNckFLcTFJUWMKzqsDS/S3wHigjHBSgztEmg2na/2fR9As
JxUe/ZSdEaMKDj2ZJ3EM8u5aY6Sp79aNypHsPcOXjhX0VoAwPtRqFg==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d - recipient: age1g7atkxdlt4ymeh7v7aa2yzr2hq2qkvzrc4r49ugttm3n582ymv9qrmpk8d
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOM1VWRG5yRUx3MGNMK293 YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBrMjVXZVFnTEczbEg1ZXBG
RWJTQmgrUVRocHVuYkYwU0UwZXFrRm43cUZzCkFmMU9WT0M0cS9JQXJIMU1VZ1pu RmQ0c0RoZS9pWXdhT0ZVSURLVGxTWFBWM0FjCjV4cjVER05YZnFaclJnVEllSURy
TVZhc1lFNklRNCtzTmp0eldVaWhqUU0KLS0tIHJNbXV0U2VoejRCNWlFMG1RK2Nu YmtzUzdOK0pldjJiaFVKVDcwY3VzQncKLS0tIC9xMUd2OVlsZ3lmRDYyYlZpYjUv
UWNoak1BS3RIY0NGRTlxcDIyYVlHM3MKHaA3riInA4NMkWQDg69uxGdR5f5l6rm5 anFDWE1CNGljY3ltN1lpdk9ZK1JySXMK58PNBo74DHptQTfT1ozV3Ikgf5BccRIH
vywj80Mg/6Cy+mFtGc1y9RqqsFx3IpBW/ECeGrwtCLXvBKOnZ0gaZw== Bw26F4GF8hjJL1Gp8szouJ9iN/mSNR47NdQN0nWy0GfOs5fClFfWvA==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1ly2endyt0y9xyddj6yuj4nw6fa3ltvzlvew4cr4lzs6dv8dkavpqadmyxx - recipient: age1ly2endyt0y9xyddj6yuj4nw6fa3ltvzlvew4cr4lzs6dv8dkavpqadmyxx
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBUZDNzVFdlU0NYVTFsUkVB YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA4T014MWhrRjdpRGkvallr
OVhzbStSQTlEblhZdXh5cmZGTXVXNWIyQUhNCjc3ZlBHWDB5czlZcmVWU0dWUEVN cDIwME0yUzZseXZVUlBra2d5aXgvOFh1SXdzClM4QS9zanRhWU0xZVFSdktDaWc2
OHp3YmFRaTl3Q0FxSGxheU9RSUl1R1UKLS0tIDhNUmpkbkFlNzRlbWQ2dXdGcXVn TnFWL0N2M3VmUFVMWFN1OGxqSk05QWsKLS0tIG14L1BiVnJ0NFJCYUZnWXl6TU9v
dlJVaFEwNVN4RGNVNVN3djM5c244SmsKO/jb+qiWJUu7BE3VoVQDquSxAQWDcSj2 VTU1ajNOTWxWTG5OUWRFMStLRXJlTEkKR8JA3U5MLBwMnFDZtlbrkJxmY9nENsza
g+vLyNsrc1WsxyegfRYExGAx+DJHOCg9GyACXxifCP7xTVwfvH+yfg== JCmxPW1BTH+VadbefjGPAEwVj8XqgTCw5f8awNNZFUUe0SIud80pmQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age15klj4t7gpfp69472mne4ue62pp6m4e04dmjyw7yf30qtqd3vl3uqjmcyxm - recipient: age15klj4t7gpfp69472mne4ue62pp6m4e04dmjyw7yf30qtqd3vl3uqjmcyxm
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAzRVBMTXcyV29kVVcyRTlY YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBFWmpBbXY4YVZmVkVzQ3FW
SExraURsT2ZkamlGRGphRUpYYUJUb3hzV1JjClVTTzRHU0MvVkMvRnNid1ZYdkpP eGl1SWZqZWFSa3lmNFBNRUh4UG9qREhQR2ljCk00bElJcHk3dTFNaG5FT1NiOU81
ZTlUYnVhTHlKREtIK1N3MnRnZTNHWTQKLS0tIDdaTHRvV0s1dEJseXVSdTFXUjlY aENlNHpkckFoRUVpakpmb3lIYU4zOEUKLS0tIFBpQjFEa2xiMmNHM3NhKzMrMFl3
bndzMzRNSHVScDhCZkV3MDQwYnllcGcKOHUp8Q2Qmgt0CcOZZL6obGKDT8fTJ5eZ Vm91bU15TFJwSUd5WXI3VER5WnFEZlUK89Iu2PeG/7mXaTaCUClCVL44VFLJEZpM
hOeJzPoS0MY8BEICcxekOl0MICOhlIySXKx6m4MpRjgnMVX1Y5OMIQ== 1s6QFAemy/B5UYeZBQsWiN1v9yAktvA+B7BeS0lyZohpV6SypLgjGQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1k73gy5em3js9zklnnkzp5hme9k04lny32fgahmzddknjw5c295asdyr4x6 - recipient: age1k73gy5em3js9zklnnkzp5hme9k04lny32fgahmzddknjw5c295asdyr4x6
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBOZnR5YlZXN3N1WnFUcm1o YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA5RW9MOXMxcmZQRkhKcSt4
clJ4cVFoNng3WFNKWEd5K3l2TTUzWW54dUdjCnc1L2l6WkJBVHQ4RXNrV25kSW5s cXJRYnVPVytOVDY1dlAveFg1eWlMZmxqcTNZCmVhaVZyZU9VcmNVczFLemNuYTJJ
dE0rdnJqUmllUS9VVE93OG5idUdzUk0KLS0tIDNFaGQ4R2lwRUI3L1NxL0UyYVdM SG5WWnNJNExBanVJb1VlT0VIWUtmYzAKLS0tIFBtSDN5aEJRVC90ek4weENZSmhQ
VjJJdzBuNGsvazVEdzNKRW5OdTFFQlUK5Rz0X+FopwNYu8AuC7eJPxPAr/yiZSg7 QUMrY0dlMStHZXY3VzBkZ3NZMFVnYzAK9C1GRRqXNWesrK3JYwol3hDkmjaBBUNW
s0Di5Wy1kfKXdwRbgSgXFZifg7bC4wsetEGi3SPVOa5yIduoMyYmaw== 3CroUXgWDEQ5U8M3aFKSdhXND3WkPdDAKpt9cn34lEtlUOoy4MF/AQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8 - recipient: age1cmzh82q8k59yzceuuy2epmqu22g7m84gqvq056mhgehwpmvjadfsc3glc8
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoUkErTEtHSzJubXZXOEZa YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB2TTV6QTNBNzV1T1BVQUlq
Ymx3aTBjb01KbEtHUGROSllpMXV0UlpwVmgwCkRFcWs4RWJlUXIzeEtDVnJrQVpa OEVGUFpvNDlUT1lWanlQZ0E0cDhaY29vRUJVCkVVbzR2d2gwWGNESUZNSGJianBC
R09Ra0VOMHpGUUpUYWJyeks3TzRRRTgKLS0tIFA1cmJ4SmJEWXdaVGdwZjZZN01y ZDk5anJ2V0hwQUVEMUg1dmZFLzFLODAKLS0tIFlGR0xGamFKY3lwUkhaRFMzK1ds
aTF1ZnZvOHYvZDhxSG5JSDR4Zm41NlkKijbFP2InlSCYZNR/kPWiedeRCFpLDx0M U2dyTlNkdFVTYXJKQ0pBRnE2S295czQKy0E1Iajqkzg8cyTYNXoqf9bas8BaBP4+
susZTvBARIzPqR+nRNFQ/W7CvwPFPtWIBHR4lOhDmrFYjkCh085Ffg== x7kjIbKIgBbWpT3niLA6Zl+SN0tLva67ddau4undz7YA7OZ4VzZ2Sw==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx - recipient: age1wmx8y2hs83j2u5srdnfxljrzxm8jtxl6fr0mq7xf2ldxyglpzf2qq89rpx
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBJWEF2Vk5ZaWRFK29MTGht YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBnajNaMk9JcE1xSHpyOHV5
SGFPSmRndDA2L0E0Qlhxd2RVeVV1UDhMMTI4ClhORmRrb1c4RnZDTmdQZ0ROYkE2 L05FL2lPd0ZBNVBEQ2thRDZEdHFYL3Nnd2hJCjltSnJ3MUVvSGNyclppNTA5TGsw
eHhNbE95RkE1ZHYzYXluN3prUFRmSTAKLS0tIGVTcndEOWdvV0krOTRjd0dyZHow OVozcGJ6c3RCMXkxTnN0M25RcFhyVDQKLS0tIGljdHZUaTNhVEZKZE1FbXNaOGVu
NG9PZlBEaURzbDF0cGo2d2VvQnFocWsKmZk7kBvKqJMDBl8rIaLw3NrUbVxzrRMN T2k5RlNWWGt6a3NSSE9CQjFvK01mMncKuUQ8PeSkfj0RJgDRWbFXBFAuWAOvKAox
1xSb0iK/JDsCBDZiz+dmb4Kha/LGV2DM+AyXD0p/qSQ23yJM8WMukw== LxBKr1TZ4oHIYJjtgP9mnKpNL5ikda+EkdEAt7V7exy2m3SvV59frg==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1mjgw3nxlnqdj04mgjz3wn7fj2nl2nxla4p2r2fn4nkvayfgp09pqllxzyh - recipient: age1mjgw3nxlnqdj04mgjz3wn7fj2nl2nxla4p2r2fn4nkvayfgp09pqllxzyh
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4OS9Ib1ZITjVyTC9VS1JP YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB3TFR0dG5YVjRYZUs0bk5W
dkJRdGhEVlJab25zWmc1S0J0Tk9PL0lZdVFFClo1S2Rabk5qZ1R0NzZIT211N0Nw SE5aK0lRWGhMVFhNNmNKbCtLa2tibXhJL0JzCldGN1hNdldXVWJ0b3VwaVRFMzk5
M21scUlmZ1hVL2lSdGk4dEoyZW80UGsKLS0tIDIyMTdyWlNrMkxnSmlLamJJdksr OTdjTGpMS1NUTU50RjFRaVAxSHcrY1kKLS0tIHNvaEdING1kc2RMalhZL1FqL09K
QWpZejBTSHp2T0F1YWtwQmdjRmtKVXcKM4Hr5Y2eDOfwadbTSAJu62KGisljfOfI d29KMENYVEVyNzUwNEVvbitXSHVjUncKokOmKLepXUcsYf/5QUBlsd0G8ZyCsV6T
BiIqArmfyjo1upw676EyV5JeV3vbi2jTT1rn8QyodsSdnI9ms9Z4KQ== z9otd0AdEPeRTSbh5pJ05WYEIR929aEPlaLLGhIdEI3XCOHey6GpvQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl - recipient: age16vzhcvz8tyxj8e0f47fy0z4p3dsg0ak4vl52ut3l07a0tz465cxslmhevl
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBhSjlMNU5KNHEwdUZLejZq YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSB4ZFRFcDc1cWRLeHhmZ0dB
SlIvVUlvTyt5QktHeGs1QWYvcjN5Y2RrMkM4Ckkwcmx1MTUxWmoza0gxMW9pcVd4 RFNOVGVpMENydmRMRkxuWXpCaHdxUWVwa1IwCmRUMmUzampKS3BidFVLYjJEOU1F
Q0IyL3hSNFAzQVliOHZjelpjQXZJZk0KLS0tIFJzRys5czdmNUwxeUJtVFk2Z0VU eEFqVXRCakpTclpGOEpMbUdVbkZORkUKLS0tIGdjUkg5UmRuV1M2Rmc2Uk5VeS9t
cTZHRFRMczNvbjdLNGsvZEtTNHQySWcKgiQ+amm1xrvTrU0lZKIKg6VMaxiSkd1O Z0ZtWWFRdkl5NDQwVjcvYmxKVG1wNFEKrP04VYIFR2V48RqpAMXgp1sDbr1NH0+0
+ib0vqwWUXDjxxTYaLitRCB92fwem3lsUJgmhN1kcRS3v1COKimbtA== kvWoYuJcaKB1Tw3xBaLmrCjKt5Xd54linwpgidX4dOAqHjHWyNIHjQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age15cx90pnp54xp5gxlt02yn9j2pz968wp3l5ukdkx55xuecp34e5pszjku4m - recipient: age15cx90pnp54xp5gxlt02yn9j2pz968wp3l5ukdkx55xuecp34e5pszjku4m
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSAxUGRlWGplcGtDb25Ua3pV YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIeFFhbTRvQWNtaUNZWm5l
d3lIZWdmbno4bTJVMEtZVERUdkR2UlB1ekc4CjlnLzhMamxnYVd5OVQ0VzZuVjdy bnlBbVBlb28zd3hMRTFxRnlacUU5dng3SENVCnFDT0J0VWJmZXhueFFmTGs2TUlP
NVQxOU5UcXk3M0Y5M1hLWU1WM0o3S2MKLS0tIG9xQWRRZS9SQW9sTS9FOUtjQThE a1I4TkVnY2JPSkJlUmU2U3R0cFUzNmMKLS0tIGNLb2JVNnBZWDM0QngraUFkSXB4
ZDI1Um1RWm9jeFllY2dmTUdEZTJqU1kKh2Vm61sylFJwsLOjdFVRUXtabg0YzHvL ZHR1N1Ivejc2VzFVdUlKL0lvdXJja0UKENB2JzmrXT/sFVpVzxR64OpoGwq65Q3H
jHfr0ihHqMWQLQnMVFDrkTH84cnHDZm/yTijXXRF/yAkxlVUF7Tv/w== KamGdqdsD1+MYsbnklUdHSJqqAbfTH+BYpjKtF+ZsPqaXcKB9VjKyQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh - recipient: age18quey88vge7xytclg2nuq4ncme86dg04lxwczqxczmdchnjg3p0saehsnh
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBIR3MyS3NxWWNwRktuUGFy YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBoWXJ0NUlEbXZNdHlzcmlC
THJ6SkhuZEhRWWNXNzhIYW0yekV6bG9MNkZVCnVNZU5ITDRJUlVWLy9hUUZrNFps N3VoaEFKVXdMTjJSYXV3Vlp3dmtFVCtNang4Cm93RDFVVXgrQnM4K2lraWNSVjBo
bGtsTWxIT2NrRFR2ZlhDZndubUlUOTQKLS0tIFl4Z093dHlGRXk5MytLMk40ekRy emR1MUlEdWJxY2h6RlhTdEx1SnpmZm8KLS0tIFlLenQ5WC8vZnpGVEZmVG1MbFZU
Q2ZNT3NKZTRvdEZKWGhnQmhqVGp6a2cKbgjp8N1EOVRt1mcLBhWOl5vkNeeomu3L NkRQb3c0YjV1RnhzUm9CRVRtc3Z2MUEKbwFjrd9OxDUmw7SSMGYXjlzsMVL12iNv
ur5Orku3qMdm52Ff0msNzlPnrUmmblBcHSrsDvkWb3YI/Pe/zrRlJg== 31E4a7ZCPw0zucoJpB3kFkQ/0vveOHZU3bjj0htm89H1BIaW0AZkzw==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
- recipient: age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns - recipient: age1ax5hqk6e2ekgfx5u7pl8ayc3vvhrehyvtvf07llaxhs5azpnny0qpltrns
enc: | enc: |
-----BEGIN AGE ENCRYPTED FILE----- -----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBaY3ZqNHJSeVJlMlhnTXgy YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBCdDZ1QThYRGJ0Ni9QNk9D
QW92SXV2dlFsbjVTSlltWXJ6ajEvaEl6S1FVCk1oTkViQ2EvK0NiYlBZWGszRzVk eE41Y3BsMmJWVkRkV05FWjhlcXF6ZlhsOEFzClBzZGxpU1Y1TmJVOHN0czNNcjZn
T0U1UzNqTXE5aW5xL3JwU3kwMnlacDAKLS0tIElBVGhncUpvNE1BS1UvZ0VSZUww UGVQSm5RRWhwZjVDMDV6Qzk5RmljMjQKLS0tIGp5dUljSEExUGNxUnRZcHVTMFdj
THZaSXhMNldUbHpBMVZQWXYwaVVQYWsKpUbG+lC37W6bzOuu9MaUmEZ5T1b5EC9k ZW5MY1NJMmRJUmcyRTJnVDMzUzB3cHcK54+0I7202n4P1kZGaCI5kM5BRAnNh/ts
VIY9XUoA7h0Z6G5Jrx/lrf6qsghMqd59gPA1qh8KlCJBAUJPHzQKVg== 7ygeuksGvi+7gs2UFn3LCUdsaL7RsBuX3NBiVyBvE02gfKecT7W/XQ==
-----END AGE ENCRYPTED FILE----- -----END AGE ENCRYPTED FILE-----
lastmodified: "2025-12-22T09:11:50Z" - recipient: age1c2enwel9un28dcs4wg0vcyamx9a4a6g3walkhu8w5lqhmd804paq9d24as
mac: ENC[AES256_GCM,data:D6qKXhSuYGPm9K7Al/la3O++DmOTQN5++96k44IIvgSR5Q3kTkMYxPsf3PWNyjMm09+9aRauuHPHj098+W1rXaq43Iqr24JAuaZNwLyxtqkaibv/Zhx1RgEWGXyOHDtlfIPoULNKVZ0ls2mtk40oQHsfhnRyS42m+HMQnL+tCF4=,iv:uzKbpZu9P05KbaXnBUxN4rA9nYOXpeK+E/scWoFxpcs=,tag:PuMdBx3JOT1EfFkOPV0G2g==,type:str] enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKQ04yNzR6MXU3aEdFNU1J
c29qdk5pbjA0Q1FGcUZTaytrWFNyM3RXRVNVCmVyU2czclVjYmpmQmNuTmhHdUlv
MkpES2FmK1JLc0tmN1BBRW95YXl6SWcKLS0tIHhCendLQ0ZmbThYb2phTG1CWk53
TTErRmhuaDlkenNSdkxiWEVTSGFEazgKZj2nEn4bgT8+oVUG38UDGmNrq9wAk7sq
9PzYw3cjGwRUFwT4lV3vK8ZNU6DAepga7ebwxfPNjP35h9eMtRVQIg==
-----END AGE ENCRYPTED FILE-----
lastmodified: "2026-01-03T05:23:41Z"
mac: ENC[AES256_GCM,data:D1iqvJh7qLoC6GlwFItacyb15X7LrnXZfSQQVhFRQRnVbFc/ECqM6P9OP4PlCfAH5Up0c/iv84MsE/UFubGKGR0i19lCQ78nLPNkFfvJ+NXg0sr03FiFmW0Q8hwzauzdMUiQr9/36D/ax+BVBTQyWgZEneiCY7KoDaQKJWzOGT4=,iv:+AZ+1u+TZNqrLMaDcHU0fgPsvx5HFprlKQExH5pIjyM=,tag:ytnj7FQQ6YivKncyZUHigg==,type:str]
pgp: pgp:
- created_at: "2025-12-15T21:53:40Z" - created_at: "2026-01-02T21:17:55Z"
enc: |- enc: |-
-----BEGIN PGP MESSAGE----- -----BEGIN PGP MESSAGE-----
hQIMAwDh3VI7VctTARAAq7Q/kBF7Xgf1sPEfLLNnue7G+uErtVHLwyGwqDRAE9aw hQIMAwDh3VI7VctTARAA001QiHU3uO1goHUTsx+QnhCrfIBDjVAHhZtj8CEx1tqk
NQ9lg2xJIro3sJhaVz0EkKyuydkWw3vjAwltnRd6FVtfKnBeDirFJdoM2zOLNdQe YaxNUNDra1uyGQqwdH1Ly8h6cSzeUfEtPfkjsvegYo58PSkz5F6mrpROkB1mzzfG
OYbpGp0/C2szgYkBqVU5hDh0Gzgho0UzO0rhwf/c+uVNTKPfUJBym72p2OKJSUcm /H3MpCHTzroXPmrT3lNxXZyYqxGzcfLBLU05etEiFV+sV2mjoV1nYY2gTnH8XtV9
NWhf1On/aaHsLQ46y8TJxzoxI2PsziBXqMQGbKofAgnNPSyYRvzRWR5+1lShgt4e HVayfxR4cYZOS7ox8SkGoTvZHsbNT5+jaJn7GqRjrcjmjd7S3gvq83ROe82YHNA0
KYLgzGKbLp+ENptPOmqLbKuuVhFX8WXULyRvS3hRTKjezncPuRqxG/GE+4BzS7ih 1O04PSGwnaGC88E9Y/7segZC8Tl1e25Z0c8yMd8JHsn/RL8beHwUHTn6nuyo65Bj
6WZ+WBCeG4sNQaeTXDjtL18DyyzT9y+UihE8O+icIPvNpGkJgY5OiKfJU3W/Wqih Xmic9M5C16ur5yQtVr/+xU/FCbmkecsOL4u5YgECFt5w7zJZzfGUHa2Z5dIQ9T5o
wxl3Pqgb9BDvz/jHMUt2GN07JuX1at/Plx/kG3xMmgrSJfDi5ZA6oiBi5B4AqOl5 2oY/h+GsN9xTM/6ZVcgCbZrcHnIvP+5VmIEmXkdTtb4cvTFJMkDWxx7NrS8dI/Rh
okn635mBXFnfGuz65hrP05P7p58BXLXvMZMsrk8kNknQu7mCeXUpDvXCFRo9xZnz 76hoCStleuLpw8+zwIYC4QdJfFWBaQyw8w0nON/qp4E+kyU8E3syMsjqFOqclSeU
OeTc7LUP9Dp5rlSJSzkBibrZ4BxebFL4ujPQ+8cibIu2XAoSQPQUCmscq1D6K5aY vFDTvgl4/Z0nPxTl+IBzG0cBPMjUXgmvGZj4NAhZhE5nNwkA34GvmMcfjVhy8ROX
37GS/HWwNzz3PimT/D2FlKpbE9Krn9z+H9a19DIpfdWhxD06pu9pLO9cPBmYyeHs WWwgiFBP20Po7p3aHz57KA4UTkgIZfhK4BRbb4BhQoaYEcXL8Sata/SJOR3RT2vQ
jAnd0RRg20mF2MBy2f24nu8+ziCARJQC0H9heR386zEDCKMCo2XkC0DqbN5CL16F 8uB8H8orPpugdafS4wLv/qcwYn6pa2ubEQG59WfihIomDWh4jl+i+kfnM5fYwX+F
AgwDC9FRLmchgYQBEAC+cfiPynGPEFfdnt+Hta9/FMI5WMXMbV4XFqD0XW6VVRLe AgwDC9FRLmchgYQBEAC4bp8seECcmzLFnRZsABQI/TJg7jKDEZuudEiEGmKUhhOf
1o/kANe3TM2hFzf2qVfQ4oLPxOlQtJNylxYUl2Z9EJB+YLtuHgJ9ffx1Bkc2a6md Mz1pQEEHyh5aTFSJDVq2bNgPKt4NJ/bQL1QOq1lnsprpAAL6+HoyezA6ygfh6YmW
dxb2Qv6DaKv53EiD8quAIPhaC3XzVsfrAhwSL4pga11wFYEge1wXpGGFp2LNbghH 8kJOwJrVXlgo+H3XD4XeoA7VFVdcHkszFYgq4KCd8KX+haSkt0Wbj0s7sQkKQo/j
IW273sFPv6fBIqjM0dF4QtLFsphc6dRZdW6qzuFEkU++RvfZmoKdnrzMFTaYhiX1 PUUQN34pxfyJ0IiqlKuLgpu7ggMJkDqZGoYnXH91Qt9TYi/liMMx4wo82YOQFH0d
lwuHuiIWP3wX7YNGgTuKcecvlUo3kI67D6SGHBXVkeyejYH+wfzrApUGdHJ4NxY7 xJUewsVvUpjwmFotOBKdhk+zZlOoNNr7QnyZ2SRyXNUFI66fsw5QsbwDSXJ4Hy8C
l3xGkrWIwqWgqh5aNErgKAA8sUS/Gcn50UHlsmO5RY3qJQPmPK1p7nlH9IKktG+A 3RVRZ7baxw2p5wMyZQBtMyqu9quS/XED0cZA+sxvKOTrC24YbD+nb1ktc/9ZJghH
6AvzdgWqHnqaA/Cb90bGJZP4m447XQHIv9UrwB+6rffRA7Dvw7oFsNnh8I3Nl/W3 TZjhQLLhmrbHPNnrHIrnEJ6XrxbgNHWTFE+yX/e2lRIRGwz0cfgbY2pLFJ+6uhSu
WNlJ1vuXmZXQhlBS/95DvWDOzOpqIh8XSYAR44506n9u9ZRh00dB/SQ5yTA7AjSX PkodKyq/PCerYZPnUMjnLxogNtgZhf6jK4AzG2xuFZne37NBEaXY3q1ktwafpRia
+Jz4SAo+8I43CiBEUbGCoxRgwHa7h6UWK7LsXCGHkqHHS7VRWZ3MiZkrVdbwv8+D 1UrO4PC2cwJpNuIpMfHbA8xieppwRZbqBSSAM80V12963cFakUxLmZdMG0ApFTDU
fkcwHmxJQGxjhU5F/cdmMX2KYWXu93I2Ohk+vZ7IpDbP2H/G5epgn+pUHbEbBYrl 5NoAxwBaRooHjTgYwdfgtjikwsPOf/VFWrB2IkBqF/QhxdV2sxasmJCM04e1gidi
J874Pj2gKA8vJS7bm7tbMVyCebsRwzt2eh8qwAfJL9HAup7a+hIQaIVqxrvnz9Je 0prCX7KoMNtBnHpubfwV7sTNdhN15IKmyHNLw9hXfZZmN9UAh6LxUS/KHMZSv9Je
AcPIsNoAqTsZeGvL0LoLQJ5myKPsb9hs/pOYjRjjM6Fdyy1GwNCdTdcLFjTthVLI AR+Ty00mCszxvBco6ee6Tv7gEhBU2ZBhu4yyWZC5Kd0pNvr4ZtCGNNY5wIjv00jd
7JuiudM3Ce/c+mW7+57oKFAqGPB3HtAfye0A9bJ3R9co4LAvWSMk52ia+LanvQ== nNnMW7MrEF4Tz/So+1TJHiLLFuap2RpXifCHRiXDMHqOUuFUgGFSNNlhYXycXQ==
=Iisf =lDR9
-----END PGP MESSAGE----- -----END PGP MESSAGE-----
fp: 4BE7925262289B476DBBC17B76FD3810215AE097 fp: 4BE7925262289B476DBBC17B76FD3810215AE097
unencrypted_suffix: _unencrypted unencrypted_suffix: _unencrypted