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:
parent
83a543b266
commit
ea48c316cc
8 changed files with 207 additions and 93 deletions
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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
172
modules/wireguard.nix
Normal 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));
|
||||||
|
}
|
|
@ -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" ''
|
||||||
|
|
12
nix/apps/show-wireguard-qr.nix
Normal file
12
nix/apps/show-wireguard-qr.nix
Normal 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
|
||||||
|
''
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
|
Loading…
Add table
Add a link
Reference in a new issue