1
1
Fork 1
mirror of https://github.com/oddlama/nix-config.git synced 2025-10-11 07:10:39 +02:00

feat: add preliminary wireguard module

This commit is contained in:
oddlama 2023-04-11 01:27:58 +02:00
parent 83a543b266
commit ea48c316cc
No known key found for this signature in database
GPG key ID: 14EFE510775FE39A
8 changed files with 207 additions and 93 deletions

View file

@ -16,7 +16,7 @@ This is my personal nix config.
- `secrets.nix.age` Repository-wide local secrets. Decrypted on import via `builtins.extraBuiltins.rageImportEncrypted`. - `secrets.nix.age` Repository-wide local secrets. Decrypted on import via `builtins.extraBuiltins.rageImportEncrypted`.
- `host.pub` This host's public key. Used for agenix rekeying. - `host.pub` This host's public key. Used for agenix rekeying.
- `default.nix` The actual system definition. Follow the imports from there to see what it entails. - `default.nix` The actual system definition. Follow the imports from there to see what it entails.
- `meta.nix` Determines the type and architecture of this system, and some other optional meta information. Used e.g. by `nix/colmena.nix` to know which hosts are NixOS and which are home-manger only. - `meta.nix` Determines the type and architecture of this system, and some other optional meta information. Used e.g. by `nix/colmena.nix` to know which hosts are real NixOS hosts, and which are VMs or some other type.
- `fs.nix` Filesystem setup. - `fs.nix` Filesystem setup.
- `net.nix` Networking setup. - `net.nix` Networking setup.
- `nom/` - My laptop and main development machine - `nom/` - My laptop and main development machine
@ -36,7 +36,6 @@ This is my personal nix config.
- `colmena.nix` Setup for distributed deployment using colmena (actually defines all NixOS hosts) - `colmena.nix` Setup for distributed deployment using colmena (actually defines all NixOS hosts)
- `dev-shell.nix` Environment setup for `nix develop` for using this flake - `dev-shell.nix` Environment setup for `nix develop` for using this flake
- `extra-builtins.nix` Extra builtins via nix-plugins to support transparent repository-wide secrets - `extra-builtins.nix` Extra builtins via nix-plugins to support transparent repository-wide secrets
- `home-manager.nix` Definition of home-manager only hosts (not used currently)
- `hosts.nix` Wrapper that extracts all defined hosts from `hosts/` - `hosts.nix` Wrapper that extracts all defined hosts from `hosts/`
- `rage-decrypt.sh` Auxiliary script for repository-wide secrets - `rage-decrypt.sh` Auxiliary script for repository-wide secrets
- `secrets.nix` Helper to access repository-wide secrets, used by colmena.nix - `secrets.nix` Helper to access repository-wide secrets, used by colmena.nix

View file

@ -62,10 +62,11 @@
hosts = import ./nix/hosts.nix inputs; hosts = import ./nix/hosts.nix inputs;
colmena = import ./nix/colmena.nix inputs; colmena = import ./nix/colmena.nix inputs;
homeConfigurations = import ./nix/home-manager.nix inputs; colmenaNodes = ((colmena.lib.makeHive self.colmena).introspect (x: x)).nodes;
microVms = import ./nix/microvms.nix inputs; microvmNodes = import ./nix/microvms.nix inputs;
inherit ((colmena.lib.makeHive self.colmena).introspect (x: x)) nodes; # All nixos based hosts collected together
nodes = self.colmenaNodes // self.microvmNodes;
} }
// flake-utils.lib.eachDefaultSystem (system: rec { // flake-utils.lib.eachDefaultSystem (system: rec {
pkgs = import nixpkgs { pkgs = import nixpkgs {

View file

@ -1,7 +1,8 @@
{nodeSecrets, ...}: let {
wgName = "wg-vms"; lib,
wgPort = 51820; nodeSecrets,
in { ...
}: {
networking.hostId = "49ce3b71"; networking.hostId = "49ce3b71";
systemd.network.networks = { systemd.network.networks = {
@ -21,41 +22,14 @@ in {
}; };
}; };
#systemd.network.netdevs."20-${wgName}" = { imports = [../../modules/wireguard.nix];
# netdevConfig = { extra.wireguard.networks.vms = {
# Kind = "wireguard"; address = ["10.0.0.1/24"];
# Name = "${wgName}"; listen = true;
# Description = "Wireguard network ${wgName}"; listenPort = 51822;
# }; openFirewall = true;
# wireguardConfig = { externalPeers = {
# PrivateKeyFile = wireguardPrivateKey wgName nodeMeta.name; test = ["10.0.0.91/32"];
# ListenPort = wgPort; };
# }; };
# wireguardPeers = [
# {
# wireguardPeerConfig = {
# PublicKey = wireguardPublicKey wgName nodeMeta.name;;
# PresharedKey = wireguardPresharedKey wgName nodeMeta.name;;
# AllowedIPs = [ "10.66.66.10/32" ];
# PersistentKeepalive = 25;
# };
# }
# {
# wireguardPeerConfig = {
# AllowedIPs = [ "10.66.66.100/32" ];
# PersistentKeepalive = 25;
# };
# }
# ];
#};
#networks."20-${wgName}" = {
# matchConfig.Name = wgName;
# networkConfig = {
# Address = "10.66.66.1/24";
# IPForward = "ipv4";
# };
#};
#extra.wireguard.servers.home = {
#};
} }

172
modules/wireguard.nix Normal file
View file

@ -0,0 +1,172 @@
{
config,
lib,
pkgs,
nodes,
nodeName,
...
}: let
inherit
(lib)
attrNames
concatMapAttrs
filter
foldl'
genAttrs
mapAttrsToList
mapAttrs'
mdDoc
mkIf
mkOption
nameValuePair
recursiveUpdate
types
;
cfg = config.extra.wireguard;
peerPublicKey = wgName: peerName: builtins.readFile (../secrets/wireguard + "/${wgName}/${peerName}.pub");
peerPrivateKeyFile = wgName: peerName: ../secrets/wireguard + "/${wgName}/${peerName}.priv.age";
peerPrivateKeySecret = wgName: peerName: "wireguard-${wgName}-${peerName}.priv";
peerPresharedKeyFile = wgName: peerA: peerB: let
sortedPeers =
if peerA < peerB
then {
peer1 = peerA;
peer2 = peerB;
}
else {
peer1 = peerB;
peer2 = peerA;
};
inherit (sortedPeers) peer1 peer2;
in
../secrets/wireguard + "/${wgName}/${peer1}-${peer2}.psk.age";
peerPresharedKeySecret = wgName: peerA: peerB: let
sortedPeers =
if peerA < peerB
then {
peer1 = peerA;
peer2 = peerB;
}
else {
peer1 = peerB;
peer2 = peerA;
};
inherit (sortedPeers) peer1 peer2;
in "wireguard-${wgName}-${peer1}-${peer2}.psk";
peerDefinition = wgName: peerName: peerAllowedIPs: {
wireguardPeerConfig = {
PublicKey = peerPublicKey wgName peerName;
PresharedKeyFile = config.rekey.secrets.${peerPresharedKeySecret wgName nodeName peerName}.path;
AllowedIPs = peerAllowedIPs;
# TODO only if we are the ones listening
PersistentKeepalive = 25;
};
};
configForNetwork = wgName: wg: let
# All peers that are other nodes
nodePeerNames = filter (n: n != nodeName && builtins.hasAttr wgName nodes.${n}.config.extra.wireguard.networks) (attrNames nodes);
nodePeers = genAttrs nodePeerNames (n: nodes.${n}.config.extra.wireguard.networks.${wgName}.address);
# All peers that are defined as externalPeers on any node. Also prepends "external-" to their name.
externalPeers = foldl' recursiveUpdate {} (map (n: mapAttrs' (extPeerName: nameValuePair "external-${extPeerName}") nodes.${n}.config.extra.wireguard.networks.${wgName}.externalPeers) (attrNames nodes));
peers = nodePeers // externalPeers;
in {
rekey.secrets =
foldl' recursiveUpdate {
${peerPrivateKeySecret wgName nodeName}.file = peerPrivateKeyFile wgName nodeName;
} (map (peerName: {
${peerPresharedKeySecret wgName nodeName peerName}.file = peerPresharedKeyFile wgName nodeName peerName;
}) (attrNames peers));
systemd.network = {
netdevs."${wg.priority}-${wgName}" = {
netdevConfig = {
Kind = "wireguard";
Name = "${wgName}";
Description = "Wireguard network ${wgName}";
};
wireguardConfig = {
PrivateKeyFile = config.rekey.secrets.${peerPrivateKeySecret wgName nodeName}.path;
ListenPort = wg.listenPort;
};
wireguardPeers = mapAttrsToList (peerDefinition wgName) peers;
};
networks."${wg.priority}-${wgName}" = {
matchConfig.Name = wgName;
networkConfig.Address = wg.address;
};
};
};
in {
options = {
networks = mkOption {
default = {};
description = "";
type = types.attrsOf (types.submodule {
options = {
address = mkOption {
type = types.listOf types.str;
description = mdDoc ''
The addresses to configure for this interface. Will automatically be added
as this peer's allowed addresses to all other peers.
'';
};
listen = mkOption {
type = types.bool;
default = false;
description = mdDoc ''
Enables listening for incoming wireguard connections.
This also causes all other peers to include this as an endpoint in their configuration.
'';
};
listenPort = mkOption {
default = 51820;
type = types.int;
description = mdDoc "The port to listen on, if {option}`listen` is `true`.";
};
priority = mkOption {
default = "20";
type = types.str;
description = mdDoc "The order priority used when creating systemd netdev and network files.";
};
openFirewall = mkOption {
default = false;
type = types.bool;
description = mdDoc "Whether to open the firewall for the specified `listenPort`, if {option}`listen` is `true`.";
};
externalPeers = mkOption {
type = types.attrsOf (types.listOf types.str);
default = {};
example = {my-android-phone = ["10.0.0.97/32"];};
description = mdDoc ''
Allows defining extra set of external peers that should be added to the configuration.
For each external peers you can define one or multiple allowed ips.
'';
};
};
});
};
};
config = mkIf (cfg.networks != {}) ({
# TODO assert that at least one peer has listen true
# TODO assert that no external peers are specified twice in different node configs
#assertions = [];
networking.firewall.allowedUDPPorts = mkIf (cfg.listen && cfg.openFirewall) [cfg.listenPort];
}
// foldl' recursiveUpdate {} (map configForNetwork cfg.networks));
}

View file

@ -28,8 +28,9 @@
${filterMapAttrsToLines (_: v: v.matchConfig ? MACAddress) renderNic node.config.systemd.network.networks} ${filterMapAttrsToLines (_: v: v.matchConfig ? MACAddress) renderNic node.config.systemd.network.networks}
} }
''; '';
# TODO vms
graph = '' graph = ''
${mapAttrsToLines renderNode self.nodes} ${mapAttrsToLines renderNode self.colmenaNodes}
''; '';
in in
pkgs.writeShellScript "draw-graph" '' pkgs.writeShellScript "draw-graph" ''

View file

@ -0,0 +1,12 @@
{
self,
pkgs,
...
}: let
inherit (pkgs.lib) escapeShellArg;
in
# TODO fzf selection of all external peers pls
pkgs.writeShellScript "generate-wireguard-keys" ''
set -euo pipefail
echo TODO
''

View file

@ -23,6 +23,7 @@ in
inherit inputs; inherit inputs;
inherit nodeName; inherit nodeName;
inherit nodeMeta; inherit nodeMeta;
inherit (self) nodes;
secrets = self.secrets.content; secrets = self.secrets.content;
nodeSecrets = self.secrets.content.nodes.${nodeName}; nodeSecrets = self.secrets.content.nodes.${nodeName};
nixos-hardware = nixos-hardware.nixosModules; nixos-hardware = nixos-hardware.nixosModules;

View file

@ -1,46 +0,0 @@
{
self,
home-manager,
nixpkgs,
templates,
...
}:
with nixpkgs.lib; let
homeManagerHosts = filterAttrs (_: x: x.type == "homeManager") self.hosts;
moduleForHost = hostName: {homeDirectory, ...}: {
config,
pkgs,
...
}: {
imports = [(../hosts + "/${hostName}")];
nix.registry = {
nixpkgs.flake = nixpkgs;
p.flake = nixpkgs;
pkgs.flake = nixpkgs;
templates.flake = templates;
};
home = {
inherit homeDirectory;
sessionVariables.NIX_PATH = concatStringsSep ":" [
"nixpkgs=${config.xdg.dataHome}/nixpkgs"
];
};
xdg = {
dataFile = {
nixpkgs.source = nixpkgs;
};
configFile."nix/nix.conf".text = ''
flake-registry = ${config.xdg.configHome}/nix/registry.json
'';
};
};
genConfiguration = hostName: {system, ...} @ attrs:
home-manager.lib.homeManagerConfiguration {
pkgs = self.pkgs.${system};
modules = [(moduleForHost hostName attrs)];
};
in
mapAttrs genConfiguration hostManagerHosts