network/nix/nixos-module/container/anon.nix

119 lines
3.0 KiB
Nix

{ hostName, config, lib, pkgs, ... }:
let
gateway = "upstream1";
tunnels = lib.filterAttrs (_: wireguard:
wireguard != null
) config.site.hosts.${hostName}.wireguard;
firstTunnel =
if builtins.length (builtins.attrNames tunnels) > 0
then builtins.head (builtins.attrNames tunnels)
else null;
enabled = firstTunnel != null;
privateKeyFile = ifName:
"/run/wireguard-keys/${ifName}.key";
wireguardMark = 1;
vpn4Table = 100;
in
{
systemd.services = builtins.foldl' (services: ifName: services // {
"wireguard-key-${ifName}" = {
description = "Create key file for wireguard interface '${ifName}'";
requiredBy = [ "systemd-networkd.service" ];
before = [ "systemd-networkd.service" ];
serviceConfig.Type = "oneshot";
script = ''
#! ${pkgs.runtimeShell} -e
F=${privateKeyFile ifName}
mkdir -p -m 0700 $(dirname $F)
chown systemd-network:systemd-network $(dirname $F)
rm -f $F
cat >$F <<EOF
${tunnels.${ifName}.privateKey}
EOF
chmod 0400 $F
chown systemd-network:systemd-network $F
'';
};
}) {} (builtins.attrNames tunnels);
environment.systemPackages = lib.optionals enabled [
pkgs.wireguard-tools
];
systemd.network.netdevs = builtins.mapAttrs (ifName: wireguard: {
netdevConfig = {
Name = ifName;
Kind = "wireguard";
};
wireguardConfig = {
PrivateKeyFile = privateKeyFile ifName;
# Mark for routing with another routing table
FirewallMark = wireguardMark;
};
wireguardPeers = [ {
wireguardPeerConfig = {
PublicKey = wireguard.publicKey;
Endpoint = wireguard.endpoint;
AllowedIPs = "0.0.0.0/0, ::/0";
};
} ];
}) tunnels;
systemd.network.networks = {
# Wireguard transported through another routing table
# (containing upstream by bird ospf)
core.routingPolicyRules = [ {
# Marked wireguard packets take the vpn4 routing table
routingPolicyRuleConfig = {
Table = vpn4Table;
FirewallMark = wireguardMark;
};
} ];
} // builtins.mapAttrs (ifName: wireguard: {
# Wireguard interfaces
matchConfig.Name = ifName;
addresses = map (addr: {
addressConfig.Address = addr;
}) wireguard.addresses;
# IPv4 default route
networkConfig.DefaultRouteOnDevice = true;
# IPv6 default route
routes = [ {
routeConfig.Destination = "::/0";
} ];
extraConfig = ''
[CAKE]
Parent = root
# DOCSIS overhead
OverheadBytes = 18
Bandwidth = ${toString wireguard.upBandwidth}K
'';
}) tunnels;
networking.nat = lib.optionalAttrs enabled {
enable = true;
enableIPv6 = true;
internalInterfaces = [ "core" ];
externalInterface = firstTunnel;
inherit (config.site.hosts.${hostName}) forwardPorts;
};
# Configure rt_table name
networking.iproute2 = {
enable = true;
rttablesExtraConfig = ''
${toString vpn4Table} vpn4
'';
};
# TODO: firewall
}