config: nixify everything

yggdrasil
Astro 2 years ago
parent 6446c6b8a3
commit 32c0def45b

4
.gitignore vendored

@ -1 +1,3 @@
contact.md
/contact.md
/config/secrets-production.nix
/config/secrets-production.nix.old

@ -34,8 +34,8 @@ Wir, ein kleiner Kreis von Menschen die das Netzwerk im Zentralwerk betreuen, ha
- [x] Einlesen der Salt-Daten in Nix
- [x] Containererstellung
- [x] Migration der Container
- [ ] device-scripts auf Site Config umstellen
- [ ] Site Config ohne Entschlüsselung dumpen, Salt-Daten löschen
- [x] device-scripts auf Site Config umstellen
- [x] Site Config ohne Entschlüsselung dumpen, Salt-Daten löschen
### Development Setup
@ -77,8 +77,8 @@ auch `/etc/nixos` so dass `nixos-rebuild switch` problemlos
klappt. Ausserdem ist dieser lokale Checkout in der `nix registry`
eingetragen, was von bspw. von `build-container` verwendet wird.
Der Flake-input `zentralwerk-network-key` ist mit einem lokalen
Repository überschrieben, weshalb die `flake.lock` dirty ist.
Ausserdem wurden dort `nix run .#switch-to-production` und immer
wieder `.#decrypt-secrets` ausgeführt.
### LXC-Containers auf Server

File diff suppressed because it is too large Load Diff

@ -0,0 +1,8 @@
{
imports = [
./config.nix
./secrets.nix
./vlan.nix
];
}

@ -0,0 +1,59 @@
-----BEGIN PGP MESSAGE-----
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
4HgSB8+r8YhJXiSu
=Hqtq
-----END PGP MESSAGE-----

@ -0,0 +1,242 @@
{
site.net = {
core.ospf.secret = "SECRET";
};
site.hosts = {
ap1.password = "SECRET";
ap2.password = "SECRET";
ap3.password = "SECRET";
ap4.password = "SECRET";
ap5.password = "SECRET";
ap6.password = "SECRET";
ap7.password = "SECRET";
ap8.password = "SECRET";
ap9.password = "SECRET";
ap10.password = "SECRET";
ap11.password = "SECRET";
ap12.password = "SECRET";
ap15.password = "SECRET";
ap17.password = "SECRET";
ap18.password = "SECRET";
ap19.password = "SECRET";
ap21.password = "SECRET";
ap22.password = "SECRET";
ap23.password = "SECRET";
ap24.password = "SECRET";
ap25.password = "SECRET";
ap26.password = "SECRET";
ap27.password = "SECRET";
ap28.password = "SECRET";
ap29.password = "SECRET";
ap30.password = "SECRET";
ap31.password = "SECRET";
ap32.password = "SECRET";
ap33.password = "SECRET";
ap34.password = "SECRET";
ap35.password = "SECRET";
ap36.password = "SECRET";
ap37.password = "SECRET";
ap38.password = "SECRET";
ap39.password = "SECRET";
ap40.password = "SECRET";
ap41.password = "SECRET";
ap42.password = "SECRET";
ap43.password = "SECRET";
ap44.password = "SECRET";
ap45.password = "SECRET";
ap46.password = "SECRET";
ap47.password = "SECRET";
ap48.password = "SECRET";
ap49.password = "SECRET";
ap50.password = "SECRET";
ap51.password = "SECRET";
ap52.password = "SECRET";
ap53.password = "SECRET";
ap54.password = "SECRET";
ap55.password = "SECRET";
ap56.password = "SECRET";
switch-a1.password = "SECRET";
switch-b1.password = "SECRET";
switch-b2.password = "SECRET";
switch-c1.password = "SECRET";
switch-c3d2-main.password = "SECRET";
switch-d1.password = "SECRET";
switch-dach.password = "SECRET";
upstream4.interfaces.up4-pppoe.upstream = {
user = "SECRET";
password = "SECRET";
};
anon1.wireguard.njalla = {
addresses = [ "fec0::1/64" "192.168.0.1/24" ];
endpoint = "0.0.0.1";
privateKey = "SECRET";
publicKey = "SECRET";
upBandwidth = 45000;
};
ap1.wifi."platform/qca953x_wmac".ssids."uebergangsnetz".psk = "SECRET";
ap10.wifi."platform/qca953x_wmac".ssids = {
"Ebs 2000".psk = "SECRET";
"iz-dresden.org".psk = "SECRET";
};
ap11.wifi."platform/qca955x_wmac".ssids."braeunigkoschnik".psk = "SECRET";
ap12.wifi."platform/ar934x_wmac".ssids = {
"IrèneMélix".psk = "SECRET";
"paperheart".psk = "SECRET";
};
ap15.wifi."platform/qca955x_wmac".ssids."etz250".psk = "SECRET";
ap17.wifi."platform/qca955x_wmac".ssids = {
"EDUB".psk = "SECRET";
"Zweitwohnsitz".psk = "SECRET";
"e-Stuetzpunkt".psk = "SECRET";
};
ap18.wifi."platform/qca953x_wmac".ssids."Restaurierung Wolff/Kober".psk = "SECRET";
ap19.wifi."platform/qca953x_wmac".ssids = {
"Studio 01127".psk = "SECRET";
"Walter".psk = "SECRET";
};
ap2.wifi = {
"pci0000:01/0000:01:00.0".ssids."C3D2".psk = "SECRET";
"platform/qca955x_wmac".ssids."C3D2 legacy".psk = "SECRET";
};
ap21.wifi = {
"pci0000:00/0000:00:00.0".ssids."ZW stage".psk = "SECRET";
"platform/qca956x_wmac".ssids."ZW stage legacy".psk = "SECRET";
};
ap23.wifi = {
"pci0000:00/0000:00:00.0".ssids."LBK Network".psk = "SECRET";
"platform/qca956x_wmac".ssids."LBK Network".psk = "SECRET";
};
ap24.wifi."platform/ar933x_wmac".ssids."farbwerk".psk = "SECRET";
ap25.wifi."platform/ar933x_wmac".ssids."farbwerk".psk = "SECRET";
ap26.wifi."pci0000:00/0000:00:00.0".ssids."Dezember".psk = "SECRET";
ap29.wifi = {
"pci0000:00/0000:00:00.0".ssids."jungnickel-fotografie".psk = "SECRET";
"platform/qca956x_wmac".ssids."jungnickel-fotografie".psk = "SECRET";
};
ap3.wifi = {
"pci0000:00/0000:00:00.0".ssids."C3D2".psk = "SECRET";
"platform/ar934x_wmac".ssids."C3D2 legacy".psk = "SECRET";
};
ap30.wifi."platform/qca956x_wmac".ssids."WLANb0402".psk = "SECRET";
ap31.wifi = {
"pci0000:00/0000:00:00.0".ssids."C3D2".psk = "SECRET";
"platform/qca956x_wmac".ssids = {
"C3D2 legacy" = { "psk" = "SECRET"; };
"FOTOAKADEMIEdd" = { "psk" = "SECRET"; };
};
};
ap32.wifi = {
"pci0000:00/0000:00:00.0".ssids."ZW stage".psk = "SECRET";
"platform/qca956x_wmac".ssids."ZW stage legacy".psk = "SECRET";
};
ap33.wifi = {
"pci0000:00/0000:00:00.0".ssids."C3D2".psk = "SECRET";
"platform/qca956x_wmac".ssids."C3D2 legacy".psk = "SECRET";
};
ap35.wifi."platform/qca956x_wmac".ssids."Koch".psk = "SECRET";
ap36.wifi."platform/ar933x_wmac".ssids."C3D2 legacy".psk = "SECRET";
ap37.wifi = {
"pci0000:00/0000:00:00.0".ssids."hechtfilm.de".psk = "SECRET";
"platform/ahb/18100000.wmac".ssids."hechtfilm.de legacy".psk = "SECRET";
};
ap38.wifi = {
"pci0000:00/0000:00:00.0".ssids = {
"ZW heinrichsgarten" = { "psk" = "SECRET"; };
"plop" = { "psk" = "SECRET"; };
};
"platform/qca956x_wmac".ssids = {
"ZW heinrichsgarten" = { "psk" = "SECRET"; };
"plop" = { "psk" = "SECRET"; };
};
};
ap39.wifi."platform/10180000.wmac".ssids."EckiTino".psk = "SECRET";
ap4.wifi."platform/qca955x_wmac".ssids."jam-circle.de".psk = "SECRET";
ap40.wifi = {
"pci0000:00/0000:00:00.0".ssids."M".psk = "SECRET";
"platform/qca956x_wmac".ssids."M legacy".psk = "SECRET";
};
ap41.wifi = {
"pci0000:00/0000:00:00.0".ssids."Walter".psk = "SECRET";
"platform/qca956x_wmac".ssids."Walter".psk = "SECRET";
};
ap42.wifi = {
"pci0000:00/0000:00:00.0".ssids."jam-circle.de".psk = "SECRET";
"platform/qca956x_wmac".ssids."jam-circle.de legacy".psk = "SECRET";
};
ap43.wifi."platform/qca955x_wmac".ssids."Kaffeetasse".psk = "SECRET";
ap44.wifi = {
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids."ZW stage legacy".psk = "SECRET";
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."ZW stage".psk = "SECRET";
};
ap45.wifi = {
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids."ZW stage legacy".psk = "SECRET";
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."ZW stage".psk = "SECRET";
};
ap46.wifi = {
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids = {
"EWW".psk = "SECRET";
"ZW stage legacy".psk = "SECRET";
};
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids = {
"EWW".psk = "SECRET";
"ZW stage".psk = "SECRET";
};
};
ap47.wifi = {
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids."ZW stage legacy".psk = "SECRET";
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."ZW stage".psk = "SECRET";
};
ap48.wifi = {
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids."ZW stage legacy".psk = "SECRET";
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."ZW stage".psk = "SECRET";
};
ap49.wifi = {
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids."ZW stage legacy".psk = "SECRET";
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."ZW stage".psk = "SECRET";
};
ap5.wifi."platform/qca955x_wmac".ssids."verbalwerk.de".psk = "SECRET";
ap50.wifi = {
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids = {
"ZW stage legacy".psk = "SECRET";
"gerdwork".psk = "SECRET";
};
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."ZW stage".psk = "SECRET";
};
ap51.wifi = {
"pci0000:01/0000:01:00.0".ssids."antrares".psk = "SECRET";
"platform/qca955x_wmac".ssids."antrares".psk = "SECRET";
};
ap52.wifi = {
"1e140000.pcie/pci0000:00/0000:00:00.0/0000:01:00.0".ssids."ZW stage legacy".psk = "SECRET";
"1e140000.pcie/pci0000:00/0000:00:01.0/0000:02:00.0".ssids."ZW stage".psk = "SECRET";
};
ap53.wifi."platform/qca953x_wmac".ssids."Karen Koschnick".psk = "SECRET";
ap54.wifi = {
"pci0000:00/0000:00:00.0".ssids."Abyssinia".psk = "SECRET";
"platform/qca956x_wmac".ssids."Abyssinia".psk = "SECRET";
};
ap55.wifi = {
"pci0000:00/0000:00:00.0".ssids."MagLAN".psk = "SECRET";
"platform/qca956x_wmac".ssids."MagLAN (legacy)".psk = "SECRET";
};
ap56.wifi = {
"pci0000:00/0000:00:00.0".ssids."MagLAN".psk = "SECRET";
"platform/qca956x_wmac".ssids."MagLAN (legacy)".psk = "SECRET";
};
ap7.wifi."platform/qca953x_wmac".ssids."mino".psk = "SECRET";
ap8.wifi = {
"pci0000:00/0000:00:00.0".ssids."C3D2".psk = "SECRET";
"platform/ar934x_wmac".ssids = {
"C3D2 legacy".psk = "SECRET";
"teknologi".psk = "SECRET";
};
};
ap9.wifi."platform/qca953x_wmac".ssids."Herzzbuehne".psk = "SECRET";
};
site.dyndnsKey = "SECRET";
}

@ -0,0 +1,39 @@
let
range = cur: max:
if cur <= max
then [ cur ] ++ range (cur + 1) max
else [];
in
{
site.net = builtins.mapAttrs (_: vlan: { inherit vlan; }) {
# switches and CPE only have IP addresses configured in the management vlan
mgmt = 1;
# routers, OSPF area 0
core = 2;
# servers...
serv = 3;
# ZW public
pub = 4;
# C3D2 home network
c3d2 = 5;
cluster = 6;
bmx = 7;
# Modems
up1 = 10;
up2 = 11;
up3 = 12;
up4 = 13;
# Isolated neighbors directly connectied with their modems
iso1 = 101;
iso2 = 102;
iso3 = 103;
iso4 = 104;
iso5 = 105;
iso6 = 106;
} // builtins.foldl' (result: i:
# Neighbor subnets
result // {
"priv${toString i}".vlan = i + 39;
}
) {} (range 1 61);
}

@ -52,25 +52,7 @@
"inputs": {
"nixpkgs": "nixpkgs",
"nixpkgs-master": "nixpkgs-master",
"openwrt": "openwrt",
"zentralwerk-network-key": "zentralwerk-network-key"
}
},
"zentralwerk-network-key": {
"locked": {
"dir": "nix/key",
"lastModified": 1631808463,
"narHash": "sha256-5xMZkqqQbpXECnKEK2THT7u4+/vL7SPp3Jvoicm1Moc=",
"ref": "master",
"rev": "e4a5aee0e44ca058d2f12d6c6f34db6d484187fc",
"revCount": 1172,
"type": "git",
"url": "https://gitea.c3d2.de/zentralwerk/network.git?dir=nix%2fkey"
},
"original": {
"dir": "nix/key",
"type": "git",
"url": "https://gitea.c3d2.de/zentralwerk/network.git?dir=nix%2fkey"
"openwrt": "openwrt"
}
}
},

@ -6,13 +6,9 @@
nixpkgs-master.url = "github:NixOS/nixpkgs";
openwrt.url = "git+https://git.openwrt.org/openwrt/openwrt.git?ref=openwrt-21.02";
openwrt.flake = false;
# `nix flake update --override-flake zentralwerk-network-key git+file:///...`
# to provide the GPG secret key
zentralwerk-network-key.url = "git+https://gitea.c3d2.de/zentralwerk/network.git?dir=nix/key";
};
outputs = inputs@{ self, nixpkgs, nixpkgs-master, openwrt, zentralwerk-network-key }:
outputs = inputs@{ self, nixpkgs, nixpkgs-master, openwrt }:
let
system = "x86_64-linux";
systems = [ system ];
@ -33,7 +29,6 @@
lib = nixpkgs.lib.extend (final: prev:
import ./nix/lib {
inherit self;
inherit (zentralwerk-network-key.lib) gpgKey;
inherit openwrt;
pkgs = nixpkgs.legacyPackages.x86_64-linux;
});

@ -1,14 +0,0 @@
{
description = "Zentralwerk network secret GPG key";
outputs = { ... }: {
lib.gpgKey = null;
# test key
lib.dyndnsKey = "Dr1QHSfNtAwgbdoNBtCgl5NxsSXlaw9+qo7juiVTv58=";
# test credentials
lib.pppoe.upstream4 = {
user = "test@example.com";
password = "secret";
};
};
}

@ -1,6 +1,5 @@
{ self
, pkgs ? import <nixpkgs> {}
, gpgKey
}:
let
@ -22,18 +21,13 @@ let
default = [];
internal = true;
};
options.gpgKey = mkOption {
type = with types; nullOr path;
};
config = {
inherit gpgKey;
};
}
)
./options.nix
./legacy.nix
../../../config
];
};
inherit (result) config;
warn = result:
@ -47,9 +41,9 @@ let
error = result:
let
failed =
builtins.filter ({ assertion, ... }: !assertion)
config.assertions;
failed = builtins.filter ({ assertion, ... }:
!assertion
) config.assertions;
in
if failed != []
then throw ''
@ -58,9 +52,9 @@ let
${self.lib.concatMapStringsSep "\n" ({ message, ... }: message) failed}
''
else result;
in
warn (
error (
builtins.removeAttrs config [ "assertions" "warnings" "gpgKey" "salt-pillar" ]
)
)
in warn (error ({
inherit (result) options;
config = builtins.removeAttrs config [ "assertions" "warnings" ];
}))

@ -1,588 +0,0 @@
{ config, pkgs, lib, self, ... }:
let
mainServers = [ "server1" "server2" ];
cephMonServers = [ "server5" "server6" "server8" ];
pillar = self.lib.saltPillarFor "*";
clusterServerNets = [
"mgmt" "pub" "core" "serv"
"c3d2" "cluster" "bmx" "priv23"
];
clusterServerInterfaces = builtins.foldl' (result: net:
result // {
"${net}".type = "bridge";
}
) {} clusterServerNets;
renameAttr = from: to: attrset:
builtins.foldl' (result: name:
if name == from
then result // { "${to}" = attrset.${name}; }
else result // { "${name}" = attrset.${name}; }
) {} (builtins.attrNames attrset);
# HACK: `type = "phys"` works but once an LXC container is stopped
# the VLAN interface is not moved back.
forceVeth = interface: interface // {
type = "veth";
};
netHasDHCP = net:
net == "pub" ||
net == "serv" ||
builtins.match "priv[[:digit:]]+" net != null;
whoLinksTo = target:
builtins.attrNames (
lib.filterAttrs (hostName: { ports, ... }:
hostName != target &&
ports ? ${target}
) pillar.switches
);
in
{
options.salt-pillar = lib.mkOption {};
config.salt-pillar = pillar;
config.site.net = lib.mkMerge ([
(builtins.mapAttrs (_: vlan: { vlan = vlan; }) pillar.vlans)
(builtins.mapAttrs (_: subnet4: { inherit subnet4; }) pillar.subnets-inet)
(builtins.mapAttrs (_: hosts4: { inherit hosts4; }) pillar.hosts-inet)
(builtins.mapAttrs (net: dhcpData: {
dhcp = {
inherit (dhcpData) start end time max-time;
server =
if netHasDHCP net
then "${net}-gw"
else null;
fixed-hosts =
if dhcpData ? fixed-hosts
then dhcpData.fixed-hosts
else {};
router = dhcpData.host-opts.routers;
};
domainName = dhcpData.string-opts.domain-name;
}) pillar.dhcp)
{
core.ospf.secret = pillar.ospf.secret;
pub.dynamicDomain = true;
cluster.extraRecords = map (host: {
name = "_ceph-mon._tcp";
type = "SRV";
data = "1 1 6789 ${host}";
}) cephMonServers ++
lib.lists.imap0 (i: host: {
name = "mon${toString i}";
type = "CNAME";
data = "${host}";
}) cephMonServers;
c3d2.dynamicDomain = true;
c3d2.dhcp = {
server = "c3d2-gw3";
router = "c3d2-anon";
start = "172.22.99.100";
end = "172.22.99.199";
fixed-hosts = {
"astron.hq.c3d2.de" = "aa:00:5b:08:f0:5b";
"astrom.hq.c3d2.de" = "aa:00:5b:08:f0:5c";
"www1.hq.c3d2.de" = "aa:00:13:8b:03:47";
"dn42.hq.c3d2.de" = "aa:00:42:7a:32:46";
"icq.hq.c3d2.de" = "aa:00:30:f6:27:89";
"jabber1.hq.c3d2.de" = "aa:00:0b:19:8f:14";
"jabber2.hq.c3d2.de" = "aa:00:3d:6a:23:b8";
"wiefelspuetz.hq.c3d2.de" = "aa:00:7f:01:8a:d0";
"git.hq.c3d2.de" = "aa:00:47:d8:57:10";
"fernandopoo.hq.c3d2.de" = "aa:00:f7:52:85:27";
"moleflap.hq.c3d2.de" = "aa:00:0d:b1:6c:67";
"wormhole.hq.c3d2.de" = "00:23:c3:d2:00:76";
"sharing.hq.c3d2.de" = "00:23:c3:d2:75:18";
"drucker.hq.c3d2.de" = "00:23:c3:d2:12:0f";
"knot.hq.c3d2.de" = "52:54:cf:fd:ce:3f";
"bender.hq.c3de.de" = "00:23:df:7e:c8:0a";
"sofafon.hq.c3d2.de" = "b8:27:eb:23:8d:01";
"schalter.hq.c3d2.de" = "b8:27:eb:4c:be:ff";
"beere.hq.c3d2.de" = "b8:27:eb:ac:65:d2";
"ledball1.hq.c3d2.de" = "b8:27:eb:53:0b:27";
"cider.hq.c3d2.de" = "00:0d:93:75:ee:fa";
"semanta.hq.c3d2.de" = "00:ff:e4:bb:ea:2a";
"leviathan.hq.c3d2.de" = "00:ff:08:31:db:e5";
"beere2.hq.c3d2.de" = "b8:27:eb:53:0b:27";
"feile.hq.c3d2.de" = "aa:00:5b:12:c1:f7";
"matemat.hq.c3d2.de" = "a2:1b:7c:e8:19:72";
"172.22.99.98" = "08:00:27:aa:90:e2";
"172.22.99.96" = "08:00:27:bb:8c:b3";
"batman.hq.c3d2.de" = "5c:cf:7f:c0:05:28";
"monit.hq.c3d2.de" = "00:23:ae:94:e7:19";
"storage2.hq.c3d2.de" = "42:5e:0f:4e:f3:cc";
"server2.hq.c3d2.de" = "d0:67:e5:f3:57:10";
"server3.hq.c3d2.de" = "e4:1f:13:2e:4f:c0";
"server4.hq.c3d2.de" = "00:9c:02:a9:26:01";
"minecraft.hq.c3d2.de" = "4a:57:d3:64:fe:e9";
"ustriper.hq.c3d2.de" = "aa:bb:95:33:bb:aa";
"lisbeth.hq.c3d2.de" = "b8:27:eb:a5:ee:5c";
"ruststripe1.hq.c3d2.de" = "06:32:0e:39:21:69";
"fhem.hq.c3d2.de" = "b8:27:eb:9e:8b:db";
"glotzbert.hq.c3d2.de" = "ec:a8:6b:fe:b4:cb";
"pulsebert.hq.c3d2.de" = "b8:27:eb:16:31:61";
"dacbert.hq.c3d2.de" = "dc:a6:32:31:b6:32";
"public-access-proxy.hq.c3d2.de" = "12:24:5f:bd:9b:e7";
"marenz-build.hq.c3d2.de" = "44:1e:a1:59:2e:e8";
"ledbeere.hq.c3d2.de" = "b8:27:eb:60:99:59";
};
time = 86400;
max-time = 30 * 86400;
};
}
# net priv* settings
(
builtins.mapAttrs (netName: _: {
dynamicDomain = true;
}) (
lib.filterAttrs (netName: _:
builtins.match "priv[[:digit:]]+" netName != null
) pillar.hosts-inet
)
)
] ++ (
map (ctx:
builtins.mapAttrs (_: subnet: { subnets6.${ctx} = subnet; }) pillar.subnets-inet6.${ctx}
) (builtins.attrNames pillar.subnets-inet6)
) ++ (
map (ctx:
builtins.mapAttrs (_: subnet: { hosts6.${ctx} = subnet; }) pillar.hosts-inet6.${ctx}
) (builtins.attrNames pillar.hosts-inet6)
));
config.site.hosts = lib.mkMerge (
[
{ # Static definitions
mgmt-gw.firewall.enable = true;
priv13-gw.firewall.enable = true;
dns.services.dns.enable = true;
dnscache = {
role = "container";
interfaces.serv = {
gw4 = "serv-gw";
gw6 = "serv-gw";
type = "veth";
};
services.dnscache.enable = true;
};
upstream1.interfaces.up1.upstream = {
provider = "vodafone";
staticIpv4Address = "24.134.104.53";
noNat.subnets6 = [
"2a02:8106:208:5200::/56"
];
};
upstream2.interfaces.up2.upstream = {
provider = "vodafone";
noNat.subnets6 = [
"2a02:8106:208:e900::/56"
];
};
upstream3.interfaces.up3.upstream.provider = "starlink";
upstream4.interfaces.up4-pppoe = {
type = "pppoe";
upstream = {
provider = "dsi";
link = "up4";
staticIpv4Address = "81.201.149.152";
upBandwidth = 98000;
noNat.subnets6 = [
"2a00:8180:2000:37::1/128"
"2a00:8180:2c00:200::/56"
];
};
};
upstream1.ospf.upstreamInstance = 3;
upstream2.ospf.upstreamInstance = 4;
anon1.ospf.upstreamInstance = 5;
freifunk.ospf.upstreamInstance = 6;
upstream3.ospf.upstreamInstance = 7;
upstream4.ospf.upstreamInstance = 8;
c3d2-gw1.ospf.allowedUpstreams = [ "upstream3" "upstream4" "upstream1" "anon1" "freifunk" ];
c3d2-gw2.ospf.allowedUpstreams = [ "upstream1" "upstream3" "upstream4" "anon1" "freifunk" ];
c3d2-gw3.ospf.allowedUpstreams = [ "upstream4" "upstream3" "upstream1" "anon1" "freifunk" ];
serv-gw.ospf.allowedUpstreams = [ "upstream4" "upstream1" "upstream3" "anon1" "freifunk" ];
cls-gw.ospf.allowedUpstreams = [ "upstream4" "upstream1" "upstream3" "anon1" "freifunk" ];
mgmt-gw.ospf.allowedUpstreams = [ "upstream4" "upstream1" "upstream3" "anon1" "freifunk" ];
bgp.ospf.allowedUpstreams = [ "upstream4" "upstream1" "upstream3" "anon1" "freifunk" ];
anon1.ospf.allowedUpstreams = [ "upstream1" "upstream3" "upstream4" "freifunk" ];
priv17-gw-up3.ospf.allowedUpstreams = [ "upstream3" "upstream4" "upstream1" "anon1" "freifunk" ];
pub-gw.ospf.allowedUpstreams = [ "anon1" "freifunk" ];
c3d2-anon.ospf.allowedUpstreams = [ "anon1" "freifunk" ];
upstream4.forwardPorts = [
{
destination = config.site.net.serv.hosts4.public-access-proxy;
proto = "tcp";
sourcePort = 80;
}
{
destination = config.site.net.serv.hosts4.public-access-proxy;
proto = "tcp";
sourcePort = 443;
}
{
destination = config.site.net.serv.hosts4.bind;
proto = "tcp";
sourcePort = 53;
reflect = false;
}
{
destination = config.site.net.serv.hosts4.bind;
proto = "udp";
sourcePort = 53;
reflect = false;
}
{
destination = config.site.net.c3d2.hosts4.dn42;
proto = "udp";
sourcePort = 2325;
}
{
destination = config.site.net.c3d2.hosts4.dn42;
proto = "udp";
sourcePort = 2399;
}
{
destination = config.site.net.c3d2.hosts4.dn42;
proto = "udp";
sourcePort = 2327;
}
{
destination = config.site.net.c3d2.hosts4.dn42;
proto = "udp";
sourcePort = 2338;
}
{
destination = config.site.net.c3d2.hosts4.dn42;
proto = "udp";
sourcePort = 2339;
}
{
destination = config.site.net.c3d2.hosts4.dn42;
proto = "udp";
sourcePort = 40533;
}
{
destination = config.site.net.c3d2.hosts4.dn42;
proto = "udp";
sourcePort = 61699;
}
{
destination = "${config.site.net.serv.hosts4.leonos}:22";
proto = "tcp";
sourcePort = 2223;
}
{
destination = config.site.net.serv.hosts4.minetest;
proto = "udp";
sourcePort = 30000;
}
{
destination = "172.22.99.175:22";
proto = "tcp";
sourcePort = 2224;
}
{ # Gitea ssh
destination = config.site.net.serv.hosts4.gitea;
proto = "tcp";
sourcePort = 22;
}
{ # Jabber C2S
destination = config.site.net.serv.hosts4.jabber;
proto = "tcp";
sourcePort = 5222;
}
{ # Jabber C2S+SSL
destination = config.site.net.serv.hosts4.jabber;
proto = "tcp";
sourcePort = 5223;
}
{ # Jabber S2S
destination = config.site.net.serv.hosts4.jabber;
proto = "tcp";
sourcePort = 5269;
}
{ # Jabber TURN
destination = config.site.net.serv.hosts4.jabber;
proto = "tcp";
sourcePort = 3478;
}
{ # Jabber TURN
destination = config.site.net.serv.hosts4.jabber;
proto = "tcp";
sourcePort = 3479;
}
{ # Jabber TURN
destination = config.site.net.serv.hosts4.jabber;
proto = "udp";
sourcePort = 3478;
}
{ # Jabber TURN
destination = config.site.net.serv.hosts4.jabber;
proto = "udp";
sourcePort = 3479;
}
{
destination = "${config.site.net.serv.hosts4.vps1}:22";
proto = "tcp";
sourcePort = 2225;
}
] ++ map (port: {
destination = config.site.net.serv.hosts4.mail;
proto = "tcp";
sourcePort = port;
}) [ 25 465 587 110 143 993 995 ];
server3.interfaces = clusterServerInterfaces;
server5.interfaces = clusterServerInterfaces;
server6.interfaces = clusterServerInterfaces;
server7.interfaces = clusterServerInterfaces;
server8.interfaces = clusterServerInterfaces;
server9.interfaces = clusterServerInterfaces;
ap-test1.interfaces = {
mgmt.type = "phys";
pub.type = "bridge";
c3d2.type = "bridge";
bmx.type = "bridge";
};
ap-test2.interfaces = {
mgmt.type = "phys";
pub.type = "bridge";
c3d2.type = "bridge";
bmx.type = "bridge";
};
ap4.links.switch-b2.ports = [ "wan" ];
ap6.links.switch-b2.ports = [ "wan" ];
ap21.links.switch-a1.ports = [ "lan" ];
ap27.links.switch-b2.ports = [ "wan" ];
ap32.links.switch-b2.ports = [ "lan" ];
ap33.links.switch-b2.ports = [ "lan" ];
ap36.links.switch-b2.ports = [ "wan" ];
ap43.links.switch-a1.ports = [ "wan" ];
ap44.links.switch-a1.ports = [ "lan" ];
ap45.links.switch-a1.ports = [ "lan" ];
ap46.links.switch-a1.ports = [ "lan" ];
ap47.links.switch-a1.ports = [ "lan" ];
ap48.links.switch-a1.ports = [ "lan" ];
ap49.links.switch-a1.ports = [ "lan" ];
ap50.links.switch-a1.ports = [ "lan" ];
ap52.links.switch-a1.ports = [ "lan" ];
ap28.links.ap3.ports = [ "wan" ];
ap3.links.ap28.ports = [ "lan:1" ];
ap3.links.c3d2.ports = lib.mkForce [
"lan:2"
"lan:3"
"lan:4"
];
ap34.links.ap42.ports = [ "lan" ];
ap42.links.priv4.ports = lib.mkForce [
"lan:1"
"lan:2"
"lan:4"
];
ap42.links.ap34.ports = [ "lan:3" ];
}
# host priv*-gw settings
(
builtins.mapAttrs (hostName: _: {
ospf.allowedUpstreams = [ "upstream4" "upstream3" "upstream1" "anon1" "freifunk" ];
}) (
lib.filterAttrs (hostName: _:
builtins.match "priv[[:digit:]]+-gw" hostName != null
) pillar.containers
)
)
(builtins.foldl' (result: hostName: result // {
"${hostName}" = {
role = "server";
interfaces = builtins.mapAttrs (net: _: {
type = "phys";
} // lib.optionalAttrs (net == "cluster") {
gw4 = "cls-gw";
gw6 = "cls-gw";
}) (
lib.filterAttrs (_: hosts: hosts ? ${hostName}) (
pillar.hosts-inet // (
builtins.foldl' (result: hosts: result // hosts) {} (builtins.attrValues pillar.hosts-inet6)
)
)
) // builtins.foldl' (result: container:
result // builtins.mapAttrs (net: interface: {
type = "bridge";
}) container.interfaces
) {} (builtins.attrValues pillar.containers);
};
}) {} mainServers)
(builtins.mapAttrs (_: switch: {
inherit (switch) model location password;
role = "switch";
interfaces.mgmt.type = "phys";
links = builtins.mapAttrs (_: { ports, group ? null, ... }: {
group = if group != null
then toString group
else null;
ports = map toString (
if builtins.isList ports
then ports
else [ ports ]
);
}) switch.ports;
}) pillar.switches)
(builtins.mapAttrs (hostName: ap: {
inherit (ap) model location password;
role = "ap";
interfaces = builtins.foldl' (interfaces: net: interfaces // {
"${net}" = {
type = "bridge";
};
}) {
mgmt = {
type = "phys";
gw4 = "mgmt-gw";
gw6 = "mgmt-gw";
};
} (
builtins.concatMap ({ ssids, ... }:
map ({ net, ... }: net) (builtins.attrValues ssids)
) (builtins.attrValues ap.radios)
);
links =
let
wanTargets = whoLinksTo hostName;
model = self.lib.getOpenwrtModel ap.model;
getPorts = regex:
map (port: {
port = port.port;
phys = port.port;
}.${port.type}) (
builtins.filter (port:
port ? port &&
builtins.match regex port.port != null
) (builtins.attrValues model.ports)
);
in
if model ? ports
then
if getPorts "wan" == [] && builtins.length wanTargets > 0
then {
# Only 1 Ethernet port, treat lan as uplink
"${builtins.head wanTargets}".ports = getPorts "lan";
}
else
lib.optionalAttrs (builtins.length wanTargets > 0) {
"${builtins.head wanTargets}".ports = getPorts "wan";
} // lib.optionalAttrs (ap ? lan-access) {
"${ap.lan-access}".ports = self.lib.unique (
getPorts "lan.*"
);
}
else
builtins.trace "No known ports for OpenWRT model ${ap.model}"
{};
wifi = ap.radios;
}) pillar.cpe)
(builtins.mapAttrs (name: container:
let
ctPillar = self.lib.saltPillarFor name;
in {
role = "container";
interfaces =
builtins.mapAttrs (net: interface:
renameAttr "gw" "gw4"
(forceVeth interface) // (
if ctPillar ? upstream &&
ctPillar.upstream.interface == net
then {
upstream.upBandwidth = ctPillar.upstream.up-bandwidth;
}
else {}
)
) container.interfaces;
wireguard =
lib.optionalAttrs (ctPillar ? wireguard-instances) (
builtins.mapAttrs (net: wgData: {
inherit (builtins.head wgData.peers) endpoint;
publicKey = (builtins.head wgData.peers).public_key;
privateKey = wgData.private_key;
addresses = builtins.filter builtins.isString (
builtins.split "[, ]+" wgData.addr
);
upBandwidth = ctPillar.upstream.up-bandwidth;
}) ctPillar.wireguard-instances);
ospf =
let
ospfConf = ctPillar.ospf;
in lib.optionalAttrs (ctPillar ? ospf && ospfConf ? stubnets-inet) {
stubNets4 = ospfConf.stubnets-inet;
} // lib.optionalAttrs (ctPillar ? ospf && ospfConf ? stubnets-inet6) {
stubNets6 = ospfConf.stubnets-inet6;
};
bgp =
if ctPillar ? bgp
then
let
bgpConf = ctPillar.bgp;
in {
inherit (bgpConf) asn;
peers = bgpConf.peers-inet // bgpConf.peers-inet6;
}
else null;
forwardPorts =
if ctPillar ? port-forwarding
then map ({ proto, port, to }: {
proto = proto;
sourcePort = port;
destination = to;
}) ctPillar.port-forwarding
else [];
}) pillar.containers)
] ++
(map (net:
builtins.mapAttrs (_: addr4: {
}) pillar.hosts-inet.${net}
) (builtins.attrNames pillar.hosts-inet)) ++
(builtins.concatMap (ctx:
map (net:
builtins.mapAttrs (_: addr6: {
}) pillar.hosts-inet6.${ctx}.${net}
) (builtins.attrNames pillar.hosts-inet6.${ctx})
) (builtins.attrNames pillar.hosts-inet6))
);
config.site.sshPubKeys = [
"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAACAQDOFs2LdK23ysS0SSkXZuULUOCZHe1ZxvfOKj002J6rkvAaDLar9g5aKuiIV70ZR33A2rchoLMiM4pLLwoSAPJg1FgIgJjU+DFoWtiW+IjzKXdHHVspb2iOIhpfbfk8WC5HZ/6fPz4RUqadGQ43ImnMhSN0ge3s/oM48hpc96ne6tH+mGiugdPx8097NE9yTqJHi8deBhi3daeJH4eQeg66Fi+kDIAZv5TJ0Oca5h7PBd253/vf3l21jRH8u1D1trALv9KStGycTk5Nwih+OHx+Rnvue/B/nxgAz4I3mmQa+jhRlGaQVG0MtOBRY3Ae7ZNqhjuefDUCM2hwG70toU9xDUw0AihC2ownY+P2PjssoG1O8f/D7ilw7qrXJHEeM8HwzqMH8X4ELYHaHTwjeWfZTTFev1Djr969LjdS1UZzqCZHO0jmQ5Pa3eXw8xcoprtt620kYLTKSMs6exLstE48o57Yqfn+eTJDy7EkcjiLN6GNIi42b9Z73xXNpZx1WR9O6OulJf/6pWgrApasvxiGmxxILq98s1/VnZkOFXR8JXnpvKHEIOIr3bFQu3GLCrzY2Yuh4NL5wy6lcZNTr/0rr6AO24IbEWM7TApbXnKA5XQhAbThrVsuFBdT3+bBP2nedvWQ0W+Q6SUf+8T2o5InnFqs5ABnTixBItiWw+9BiQ== root@server1"
];
}

@ -208,6 +208,14 @@ let
default = [];
description = "Do not NAT66 traffic from these public static subnets";
};
user = mkOption {
type = with types; nullOr str;
default = null;
};
password = mkOption {
type = with types; nullOr str;
default = null;
};
};
interfaceOpts = { name, ... }: {
@ -503,6 +511,10 @@ in
sshPubKeys = mkOption {
type = with types; listOf str;
};
dyndnsKey = mkOption {
type = types.str;
};
};
config.warnings =

@ -1,13 +1,7 @@
{ self, gpgKey, pkgs, openwrt }:
{ self, pkgs, openwrt }:
rec {
config = import ./config { inherit self pkgs gpgKey; };
saltPillarFor = import ./salt-support/salt-pillar.nix {
inherit pkgs gpgKey;
};
expandSaltTemplate = import ./salt-support/expand-template.nix { inherit pkgs; };
config = (import ./config { inherit self pkgs; }).config;
netmasks = import ./netmasks.nix;

@ -1,23 +0,0 @@
{ pkgs ? import <nixpkgs> {}
}:
name: template: data:
let
jsonFile =
builtins.toFile "data.json" (builtins.toJSON data);
j2custom =
builtins.toFile "j2custom.py" ''
def j2_environment(env):
env.globals.update(
zip=zip
)
return env
'';
in
pkgs.runCommandLocal name {
nativeBuildInputs = with pkgs; [
pythonPackages.j2cli yaml2json
];
} ''
j2 --customize ${j2custom} -f json ${template} ${jsonFile} > $out