From bda1a6b603a3944223707a6d090622b574ea7505 Mon Sep 17 00:00:00 2001 From: Gregor Kleen Date: Fri, 29 Jul 2022 11:07:19 +0200 Subject: bump & vpn --- modules/netns.nix | 155 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 155 insertions(+) create mode 100644 modules/netns.nix (limited to 'modules/netns.nix') diff --git a/modules/netns.nix b/modules/netns.nix new file mode 100644 index 00000000..18e066e5 --- /dev/null +++ b/modules/netns.nix @@ -0,0 +1,155 @@ +{ pkgs, config, lib, ... }: + +with lib; + +let + cfg = config.networking.namespaces; + + containerOpts = { name, ... }: { + options = { + config = mkOption { + description = '' + A specification of the desired configuration of this + container, as a NixOS module. + ''; + type = let + confPkgs = if config.pkgs == null then pkgs else config.pkgs; + in mkOptionType { + name = "Toplevel NixOS config"; + merge = loc: defs: (import (pkgs.path + "/nixos/lib/eval-config.nix") { + inherit (config.nixpkgs.localSystem) system; + inherit pkgs; + baseModules = import (pkgs.path + "/nixos/modules/module-list.nix"); + inherit (pkgs) lib; + modules = + let + extraConfig = { + _file = "module at ${__curPos.file}:${toString __curPos.line}"; + config = { + boot.isContainer = true; + networking.hostName = mkDefault name; + system.stateVersion = config.system.nixos.release; # No state + }; + }; + in [ extraConfig ] ++ (map (x: x.value) defs); + prefix = [ "containers" "upstream" ]; + }).config; + }; + }; + + netns = mkOption { + example = "upstream"; + type = types.str; + description = "Name of network namespace to put the container in."; + }; + }; + + config = { + netns = mkDefault name; + }; + }; + + mkContainerService = containerName: containerCfg: nameValuePair "netns-container@${containerName}" { + after = ["network.target" "systemd-udevd.service" "systemd-sysctl.service" "netns@${containerCfg.netns}.service"]; + bindsTo = ["netns@${containerCfg.netns}.service"]; + before = ["shutdown.target"]; + wants = ["network.target"]; + conflicts = ["shutdown.target"]; + + path = with pkgs; [ iproute config.systemd.package ]; + + serviceConfig = { + SyslogIdentifier = "netns container ${containerName}"; + Type = "notify"; + + RestartForceExitStatus = "133"; + SuccessExitStatus = "133"; + + Restart = "no"; + + DevicePolicy = "closed"; + + RuntimeDirectory = ["netns-containers/${containerName}"]; + }; + unitConfig = { + ConditionCapability = ["CAP_SYS_TTY_CONFIG" "CAP_NET_ADMIN" "CAP_NET_RAW" "CAP_SYS_ADMIN"]; + }; + + script = let + containerInit = pkgs.writeScript "container-init" '' + #!${pkgs.runtimeShell} -e + exec "$1" + ''; + in '' + mkdir -p -m 0755 "''${RUNTIME_DIRECTORY}/etc" "''${RUNTIME_DIRECTORY}/var/lib" + mkdir -p -m 0700 "''${RUNTIME_DIRECTORY}/var/lib/private" "''${RUNTIME_DIRECTORY}/root" /run/containers + if ! [ -e "''${RUNTIME_DIRECTORY}/etc/os-release" ]; then + touch "''${RUNTIME_DIRECTORY}/etc/os-release" + fi + if ! [ -e "''${RUNTIME_DIRECTORY}/etc/machine-id" ]; then + touch "''${RUNTIME_DIRECTORY}/etc/machine-id" + fi + mkdir -p -m 0755 \ + "/nix/var/nix/profiles/per-container/${containerName}" \ + "/nix/var/nix/gcroots/per-container/${containerName}" + credsBind="" + if [ -n "''${CREDENTIALS_DIRECTORY}" ]; then + credsBind="--bind-ro=''${CREDENTIALS_DIRECTORY}:/run/host/credentials" + fi + # Run systemd-nspawn without startup notification (we'll + # wait for the container systemd to signal readiness). + exec ${config.systemd.package}/bin/systemd-nspawn \ + --keep-unit \ + -M "${containerName}" -D "''${RUNTIME_DIRECTORY}" \ + --notify-ready=yes \ + --bind-ro=/nix/store \ + --bind-ro=/nix/var/nix/db \ + --bind-ro=/nix/var/nix/daemon-socket \ + $credsBind \ + --bind="/nix/var/nix/profiles/per-container/${containerName}:/nix/var/nix/profiles" \ + --bind="/nix/var/nix/gcroots/per-container/${containerName}:/nix/var/nix/gcroots" \ + --setenv PATH="$PATH" \ + --capability=CAP_SYS_TTY_CONFIG,CAP_NET_ADMIN,CAP_NET_RAW,CAP_SYS_ADMIN \ + --ephemeral \ + --network-namespace-path=/run/netns/${containerCfg.netns} \ + ${containerInit} "${containerCfg.config.system.build.toplevel}/init" + ''; + }; +in { + options = { + networking.namespaces = { + enable = mkEnableOption "netns@ service template"; + + containers = mkOption { + default = {}; + type = types.attrsOf (types.submodule containerOpts); + }; + }; + }; + + config = { + assertions = [ + { assertion = cfg.containers != {} -> cfg.enable; message = "netns containers require netns@ service template"; } + ]; + + systemd.services = { + "netns@" = mkIf cfg.enable { + description = "%I network namspace"; + before = [ "network-pre.target" ]; + wants = [ "network-pre.target" ]; + path = with pkgs; [ iproute utillinux ]; + serviceConfig = { + Type = "oneshot"; + RemainAfterExit = true; + PrivateNetwork = true; + ExecStart = "${pkgs.writers.writeDash "netns-up" '' + ip netns add "$1" + umount /var/run/netns/"$1" + mount --bind /proc/self/ns/net /var/run/netns/"$1" + ''} %I"; + ExecStop = "${pkgs.iproute}/bin/ip netns del %I"; + }; + }; + } // mapAttrs' mkContainerService cfg.containers; + }; +} -- cgit v1.2.3