Run systemd service in network namespace

I could prepend ip netns exec xx where applicable (e.g. serviceConfig.ExecStart). But ip netns requires root privileges. What can I do if serviceConfig.User isn’t "root"?

maybe using JoinNamespaceOf (see man systemd.unit) on another unit that is running as root ?

1 Like

@azazel75 thanks a lot! got it working:

{ config, pkgs, lib, ... }: {
  systemd.services."netns@" = {
    description = "%I network namespace";
    before = [ "network.target" ];
    serviceConfig = {
      Type = "oneshot";
      RemainAfterExit = true;
      PrivateNetwork = true;
      ExecStart = (pkgs.writeScript "netns-up" ''
        #! ${pkgs.bash}/bin/bash
        ${pkgs.iproute}/bin/ip netns add $1
        ${pkgs.utillinux}/bin/umount /var/run/netns/$1
        ${pkgs.utillinux}/bin/mount --bind /proc/self/ns/net /var/run/netns/$1
      '') + " %I";
      ExecStop = "${pkgs.iproute}/bin/ip netns del %I";
    };
  };
}

Any systemd.services.<name> can join with:

bindsTo = [ "netns@wg.service" ];
after = [ "netns@wg.service" ];
unitConfig.JoinsNamespaceOf = "netns@wg.service";
serviceConfig.PrivateNetwork = true;

stolen from https://github.com/systemd/systemd/issues/2741#issuecomment-336736214

3 Likes

I might write a blog post soon about using this to sandbox transmission in a network namespace with wireguard, since I have a working setup. My Raspberry Pi is a NixOS seedbox, yay!

1 Like

ok, here we go:
https://www.mth.st/blog/nixos-wireguard-netns/

5 Likes

For your interest, in NixOS 19.09 you’ll be able to directly specify the netns for a service to Join

https://github.com/systemd/systemd/blob/4b259b3c63eeefe4cd52fa3b169b1ca4b19f13e9/NEWS#L525-L527

So this could simplify your code a bit

# netns@.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=${pkgs.iproute}/bin/ip netns add %I
ExecStop=${pkgs.iproute}/bin/ip netns del %I

# myservice.service
[Unit]
BindsTo=netns@wg.service
After=netns@wg.service
NetworkNamespacePath=/var/run/netns/wg
[Service]
ExecStart=myservice
3 Likes

This one must be changed to move NetworkNamespacePath into the [Serice] section as when it is in [Unit] you get an Unknown key name ‘NetworkNamespacePath’ in section ‘Unit’, ignoring warning in the log.

With the modification it works like a charm thank you for documenting it.

Correcting a typo: This should be JoinsNamespaceOf, with an s.

This mistake made it into examples/mautrix.nix · ff782189f05f48f28a8292b0e3c9bb579ebe93e5 · Coffee Tables / nix-matrix-appservices · GitLab

1 Like