0

I have a nspawn service that needs to take a WireGuard interface from the host.

fw0.nspawn
[Network]
Interface=wg0

According to nspawn man page, I will also need this systemd drop-in.

[Unit]
Wants=sys-subsystem-net-devices-wg0.device
After=sys-subsystem-net-devices-wg0.device

The WireGuard interface needs to be added and configured before moving to the container namespace. I do not use wg-quick in here because I don't want the interface to UP at the host.

ip link add wg0 type wireguard
wg setconf wg0 /root/wg0.conf

The problem is how to abstract out the above two commands using systemd service and dependency, instead of putting it into ExecStartPre and ExecStopPost.

The caveat is that normally the WG interface will be removed from the host when the nspawn container start, and it will move back to the host when the container stops. But if the container fails to start, the WG interface will be disappeared, and I will need to ip link add again.

3
  • I think you need to clarify a few things. First of all, is this some quirky (IMO) setup that you are only moving the wg interface into the nspawn while having the tunnel relying on the host's network namespace for the traffics to the peer? (Assuming that's even possible with wg.) Or, does the container have other interface(s) that connects the nspawn to the container host? Besides, is this a "boot mode" nspawn we are talking about? And if you don't want the interface to UP at the host, why would need to ip link add again be a problem? (Aren't you looking for automation for that anyway?) Commented May 1, 2024 at 10:00
  • abstract out the above two commands using systemd service and dependency write a oneshot service for them? Commented May 1, 2024 at 10:01
  • Move WG interface to different namespace after configured it, is documented in wireguard.com/netns. In my use case, I want to ensure all traffic can only go out via VPN, networkly (not rely on firewall). Abstract out means elegantly. I do not want WG interface creation logic in nspawn's service. Also, I want to handle that nspawn behavior (interface disappear when container fails to start) elegantly. Commented May 1, 2024 at 15:50

1 Answer 1

1

It is unclear what exactly you have tried / been using, but I do have an approach for you:

$ cat /etc/systemd/system/netns-wg.service
[Unit]
Description=netns for wg
BindsTo=nspawn-fail.service
# You cannot have After= for the nspawn here
# even if you need / want whatever extra effect
# that BindTo= + After= might pose, obviously

[Service]
Type=oneshot
RemainAfterExit=yes

# I still have no idea if you want this
# to be automated or not
ExecStart=ip link add wg0 type wireguard

ExecStart=ip netns add wg
ExecStart=ip link set wg0 netns wg

# The conf file will need to be on the host side, obviously
# ExecStart=ip netns exec wg wg setconf wg0 /root/wg0.conf

# 1 means pid 1 here
ExecStop=ip -n wg link set wg0 netns 1
ExecStop=ip netns delete wg

# I still have no idea if you want this
# to be automated or not
ExecStop=ip link del wg0
$ cat /etc/systemd/system/nspawn-fail.service
[Unit]
Description=mimic a failed nspawn

# switch to Requires= or Wants= as necessary
BindsTo=netns-wg.service

After=netns-wg.service

[Service]
# I don't know if you can use this instead of
# --network-namespace-path=, but since you
# wouldn't be having any Interface= in your
# .nspawn, you will probably need to replace
# ExecStart= of systemd-nspawn@some_name
# with a command line that has no --network-veth
# anyway
NetworkNamespacePath=/run/netns/wg

# Change `false` to e.g. `sleep 1d` if you want
# to see if it works in a successful case
ExecStart=bash -c 'ip l; false'

As you can see, the idea is that you manage the whole netns with a service (on the host side). And as you wished, it (well ip netns exec) allows you to bring up the wg after it has been moved to the alternate netns. (I'll leave it for you to confirm whether or not wg actually supports that.)

So when you configure your nspawn, you'll need to attach it to "an existing netns" (which is brought up and down along the nspawn) instead of assigning an interface to it.

Note that it is expected the netns (and wg) will be brought up anyway, because it will not and cannot even wait until systemd attempt to start the nspawn, so let alone after. What this approach offers is just that the netns (and wg) will be brought down if the nspawn failed (or were cleanly stopped).

P.S. You might need yet another ExecStart= line that brings up the lo interface in the alternate netns.

2
  • Thank you. Although this is not what I look for, you give me another approach that I hasn't think about. Nspawn do work with NetworkNamespacePath when --private-network is off, but it is un-documented hacks. Using this approach do not involve moving interface during container start and stop so it actually solved the interface disappear problem. I will keep finding more elegant approach. Commented May 1, 2024 at 17:48
  • when --private-network is off Now I recall the difference between NetworkNamespacePath= and --network-namespace-path=. The former would actually put the systemd-nspawn "supervisor" process into the specified netns, whereas the latter would only make the actual container (the "payload", or its "pid 1") spawns inside the netns, which is why with the latter way, if you want to ip netns attach the netns of an nspawn, you'll need the pid of the "pid 1" of the container as the second argument instead of the pid of the "supervisor" process (i.e. main pid of the nspawn service). Commented May 1, 2024 at 18:38

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.