diff options
| author | Gregor Kleen <gkleen@yggdrasil.li> | 2022-07-29 11:07:19 +0200 |
|---|---|---|
| committer | Gregor Kleen <gkleen@yggdrasil.li> | 2022-07-29 11:07:19 +0200 |
| commit | bda1a6b603a3944223707a6d090622b574ea7505 (patch) | |
| tree | e223290d0c3e4f91862f429e65f083d3ecb3b1cd /modules/netns.nix | |
| parent | ece84e99219c1d57dcee7ee93045edc81cd0cbc7 (diff) | |
| download | nixos-bda1a6b603a3944223707a6d090622b574ea7505.tar nixos-bda1a6b603a3944223707a6d090622b574ea7505.tar.gz nixos-bda1a6b603a3944223707a6d090622b574ea7505.tar.bz2 nixos-bda1a6b603a3944223707a6d090622b574ea7505.tar.xz nixos-bda1a6b603a3944223707a6d090622b574ea7505.zip | |
bump & vpn
Diffstat (limited to 'modules/netns.nix')
| -rw-r--r-- | modules/netns.nix | 155 |
1 files changed, 155 insertions, 0 deletions
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 @@ | |||
| 1 | { pkgs, config, lib, ... }: | ||
| 2 | |||
| 3 | with lib; | ||
| 4 | |||
| 5 | let | ||
| 6 | cfg = config.networking.namespaces; | ||
| 7 | |||
| 8 | containerOpts = { name, ... }: { | ||
| 9 | options = { | ||
| 10 | config = mkOption { | ||
| 11 | description = '' | ||
| 12 | A specification of the desired configuration of this | ||
| 13 | container, as a NixOS module. | ||
| 14 | ''; | ||
| 15 | type = let | ||
| 16 | confPkgs = if config.pkgs == null then pkgs else config.pkgs; | ||
| 17 | in mkOptionType { | ||
| 18 | name = "Toplevel NixOS config"; | ||
| 19 | merge = loc: defs: (import (pkgs.path + "/nixos/lib/eval-config.nix") { | ||
| 20 | inherit (config.nixpkgs.localSystem) system; | ||
| 21 | inherit pkgs; | ||
| 22 | baseModules = import (pkgs.path + "/nixos/modules/module-list.nix"); | ||
| 23 | inherit (pkgs) lib; | ||
| 24 | modules = | ||
| 25 | let | ||
| 26 | extraConfig = { | ||
| 27 | _file = "module at ${__curPos.file}:${toString __curPos.line}"; | ||
| 28 | config = { | ||
| 29 | boot.isContainer = true; | ||
| 30 | networking.hostName = mkDefault name; | ||
| 31 | system.stateVersion = config.system.nixos.release; # No state | ||
| 32 | }; | ||
| 33 | }; | ||
| 34 | in [ extraConfig ] ++ (map (x: x.value) defs); | ||
| 35 | prefix = [ "containers" "upstream" ]; | ||
| 36 | }).config; | ||
| 37 | }; | ||
| 38 | }; | ||
| 39 | |||
| 40 | netns = mkOption { | ||
| 41 | example = "upstream"; | ||
| 42 | type = types.str; | ||
| 43 | description = "Name of network namespace to put the container in."; | ||
| 44 | }; | ||
| 45 | }; | ||
| 46 | |||
| 47 | config = { | ||
| 48 | netns = mkDefault name; | ||
| 49 | }; | ||
| 50 | }; | ||
| 51 | |||
| 52 | mkContainerService = containerName: containerCfg: nameValuePair "netns-container@${containerName}" { | ||
| 53 | after = ["network.target" "systemd-udevd.service" "systemd-sysctl.service" "netns@${containerCfg.netns}.service"]; | ||
| 54 | bindsTo = ["netns@${containerCfg.netns}.service"]; | ||
| 55 | before = ["shutdown.target"]; | ||
| 56 | wants = ["network.target"]; | ||
| 57 | conflicts = ["shutdown.target"]; | ||
| 58 | |||
| 59 | path = with pkgs; [ iproute config.systemd.package ]; | ||
| 60 | |||
| 61 | serviceConfig = { | ||
| 62 | SyslogIdentifier = "netns container ${containerName}"; | ||
| 63 | Type = "notify"; | ||
| 64 | |||
| 65 | RestartForceExitStatus = "133"; | ||
| 66 | SuccessExitStatus = "133"; | ||
| 67 | |||
| 68 | Restart = "no"; | ||
| 69 | |||
| 70 | DevicePolicy = "closed"; | ||
| 71 | |||
| 72 | RuntimeDirectory = ["netns-containers/${containerName}"]; | ||
| 73 | }; | ||
| 74 | unitConfig = { | ||
| 75 | ConditionCapability = ["CAP_SYS_TTY_CONFIG" "CAP_NET_ADMIN" "CAP_NET_RAW" "CAP_SYS_ADMIN"]; | ||
| 76 | }; | ||
| 77 | |||
| 78 | script = let | ||
| 79 | containerInit = pkgs.writeScript "container-init" '' | ||
| 80 | #!${pkgs.runtimeShell} -e | ||
| 81 | exec "$1" | ||
| 82 | ''; | ||
| 83 | in '' | ||
| 84 | mkdir -p -m 0755 "''${RUNTIME_DIRECTORY}/etc" "''${RUNTIME_DIRECTORY}/var/lib" | ||
| 85 | mkdir -p -m 0700 "''${RUNTIME_DIRECTORY}/var/lib/private" "''${RUNTIME_DIRECTORY}/root" /run/containers | ||
| 86 | if ! [ -e "''${RUNTIME_DIRECTORY}/etc/os-release" ]; then | ||
| 87 | touch "''${RUNTIME_DIRECTORY}/etc/os-release" | ||
| 88 | fi | ||
| 89 | if ! [ -e "''${RUNTIME_DIRECTORY}/etc/machine-id" ]; then | ||
| 90 | touch "''${RUNTIME_DIRECTORY}/etc/machine-id" | ||
| 91 | fi | ||
| 92 | mkdir -p -m 0755 \ | ||
| 93 | "/nix/var/nix/profiles/per-container/${containerName}" \ | ||
| 94 | "/nix/var/nix/gcroots/per-container/${containerName}" | ||
| 95 | credsBind="" | ||
| 96 | if [ -n "''${CREDENTIALS_DIRECTORY}" ]; then | ||
| 97 | credsBind="--bind-ro=''${CREDENTIALS_DIRECTORY}:/run/host/credentials" | ||
| 98 | fi | ||
| 99 | # Run systemd-nspawn without startup notification (we'll | ||
| 100 | # wait for the container systemd to signal readiness). | ||
| 101 | exec ${config.systemd.package}/bin/systemd-nspawn \ | ||
| 102 | --keep-unit \ | ||
| 103 | -M "${containerName}" -D "''${RUNTIME_DIRECTORY}" \ | ||
| 104 | --notify-ready=yes \ | ||
| 105 | --bind-ro=/nix/store \ | ||
| 106 | --bind-ro=/nix/var/nix/db \ | ||
| 107 | --bind-ro=/nix/var/nix/daemon-socket \ | ||
| 108 | $credsBind \ | ||
| 109 | --bind="/nix/var/nix/profiles/per-container/${containerName}:/nix/var/nix/profiles" \ | ||
| 110 | --bind="/nix/var/nix/gcroots/per-container/${containerName}:/nix/var/nix/gcroots" \ | ||
| 111 | --setenv PATH="$PATH" \ | ||
| 112 | --capability=CAP_SYS_TTY_CONFIG,CAP_NET_ADMIN,CAP_NET_RAW,CAP_SYS_ADMIN \ | ||
| 113 | --ephemeral \ | ||
| 114 | --network-namespace-path=/run/netns/${containerCfg.netns} \ | ||
| 115 | ${containerInit} "${containerCfg.config.system.build.toplevel}/init" | ||
| 116 | ''; | ||
| 117 | }; | ||
| 118 | in { | ||
| 119 | options = { | ||
| 120 | networking.namespaces = { | ||
| 121 | enable = mkEnableOption "netns@ service template"; | ||
| 122 | |||
| 123 | containers = mkOption { | ||
| 124 | default = {}; | ||
| 125 | type = types.attrsOf (types.submodule containerOpts); | ||
| 126 | }; | ||
| 127 | }; | ||
| 128 | }; | ||
| 129 | |||
| 130 | config = { | ||
| 131 | assertions = [ | ||
| 132 | { assertion = cfg.containers != {} -> cfg.enable; message = "netns containers require netns@ service template"; } | ||
| 133 | ]; | ||
| 134 | |||
| 135 | systemd.services = { | ||
| 136 | "netns@" = mkIf cfg.enable { | ||
| 137 | description = "%I network namspace"; | ||
| 138 | before = [ "network-pre.target" ]; | ||
| 139 | wants = [ "network-pre.target" ]; | ||
| 140 | path = with pkgs; [ iproute utillinux ]; | ||
| 141 | serviceConfig = { | ||
| 142 | Type = "oneshot"; | ||
| 143 | RemainAfterExit = true; | ||
| 144 | PrivateNetwork = true; | ||
| 145 | ExecStart = "${pkgs.writers.writeDash "netns-up" '' | ||
| 146 | ip netns add "$1" | ||
| 147 | umount /var/run/netns/"$1" | ||
| 148 | mount --bind /proc/self/ns/net /var/run/netns/"$1" | ||
| 149 | ''} %I"; | ||
| 150 | ExecStop = "${pkgs.iproute}/bin/ip netns del %I"; | ||
| 151 | }; | ||
| 152 | }; | ||
| 153 | } // mapAttrs' mkContainerService cfg.containers; | ||
| 154 | }; | ||
| 155 | } | ||
