Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

nixos/containers: custom network namespaces #71328

Draft
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

d-xo
Copy link
Contributor

@d-xo d-xo commented Oct 18, 2019

Motivation for this change

This change provides a declarative interface for creating named network namespaces, and spawning nixos containers within them.

This is useful if you:

  • Want multiple containers to communicate over localhost ("sidecar" containers)
  • Want to modify the network namespace from outside of the container

I use this for the second purpose. I want to be able to move interfaces in and out of a container's network namespace as part of a namespace based whole internet wireguard VPN solution (see here).

Things done
  • Tested using sandboxing (nix.useSandbox on NixOS, or option sandbox in nix.conf on non-NixOS)
  • Built on platform(s)
    • NixOS
    • macOS
    • other Linux distributions
  • Tested via one or more NixOS test(s) if existing and applicable for the change (look inside nixos/tests)
  • Tested compilation of all pkgs that depend on this change using nix-shell -p nix-review --run "nix-review wip"
  • Tested execution of all binary files (usually in ./result/bin/)
  • Determined the impact on package closure size (by running nix path-info -S before and after)
  • Ensured that relevant documentation is up to date
  • Fits CONTRIBUTING.md.

@d-xo d-xo requested a review from infinisil as a code owner October 18, 2019 10:46
Copy link
Contributor

@asymmetric asymmetric left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tested this and it works as inteded 🎉 🎆. Other than the few nits, LGTM.

One thing: ideally systemd would implement network namespace creation natively. Until that day, we have to resort to scripting.

nixos/modules/virtualisation/containers.nix Outdated Show resolved Hide resolved
nixos/modules/virtualisation/containers.nix Outdated Show resolved Hide resolved
nixos/modules/virtualisation/containers.nix Outdated Show resolved Hide resolved
nixos/modules/tasks/network-namespaces.nix Show resolved Hide resolved
nixos/tests/containers-network-namespace.nix Outdated Show resolved Hide resolved
nixos/tests/containers-network-namespace.nix Outdated Show resolved Hide resolved
@d-xo
Copy link
Contributor Author

d-xo commented Nov 15, 2019

rebased onto master and addressed review comments, much appreciated @asymmetric 🙏 🙂

Copy link
Contributor

@asymmetric asymmetric left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One additional comment.

in
{
options = {
networking.namespaces = mkOption {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could split this into its own PR actually. This would make the current PR pretty straightforward and uncontroversial, and the two options are anyway orthogonal.

WDYT?

nixos/modules/tasks/network-namespaces.nix Outdated Show resolved Hide resolved
nixos/modules/tasks/network-namespaces.nix Outdated Show resolved Hide resolved
nixos/modules/tasks/network-namespaces.nix Outdated Show resolved Hide resolved
nixos/modules/tasks/network-namespaces.nix Outdated Show resolved Hide resolved
nixos/tests/containers-network-namespace.nix Outdated Show resolved Hide resolved
@flokli
Copy link
Contributor

flokli commented Nov 25, 2019

I'm also not entirely sure about whether we should add this - this will delete all namespaces previously configured every time if you add a new one and do a rebuild switch.

WDYT about something like systemd/systemd#11710?

@flokli flokli requested review from fpletz and andir November 25, 2019 00:11
Copy link
Member

@andir andir left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would be in favor of having this (one unit per NS) instead of waiting for a networkd implementation. Going with this PR will enable users with scripted networking the ability to use this (without handcrafting the units). Also being able to restart things that are being setup is nice. networkd doesn't have that support yet and probably wont for a while.

The main pain point I see is that we are providing users with a new foot gun. If you tear down a NS with your physical interfaces in it those will be gone until you reboot/do some unknown udev incarnations. Since we aren't really providing the tooling to move interfaces in the container that should e fine tho…

nixos/modules/tasks/network-namespaces.nix Outdated Show resolved Hide resolved
nixos/modules/tasks/network-namespaces.nix Outdated Show resolved Hide resolved
@d-xo
Copy link
Contributor Author

d-xo commented Nov 26, 2019

rebased on master and addressed PR comments. Big thanks to @flokli and @andir for the review 🙏 🙂.

I made the following changes:

  • create one systemd unit per network namespace
  • escaped network namespace name when passing it into the unit definition
  • ported test to python and expanded it to test creation of multiple namespaces

@flokli I had not noticed that my previous approach could result in the deletion of already created network namespaces, thanks a lot for pointing this out. I believe that the one systemd unit per netns approach suggested by @andir should fix this, do you agree?

Regarding systemd/systemd#11710, I would be very happy to use it if and when it lands, but I wanted something simple and declarative that I could use in my config today. I would also note that since 412f6a9 we have modules in master that take network namespace names as arguments, so I think having a nixos native way to create them is beneficial today.

@andir
Copy link
Member

andir commented Nov 26, 2019

Regarding systemd/systemd#11710, I would be very happy to use it if and when it lands, but I wanted something simple and declarative that I could use in my config today. I would also note that since 412f6a9 we have modules in master that take network namespace names as arguments, so I think having a nixos native way to create them is beneficial today.

Now that you are raising that I come to question if we should perhaps modify the wireguard module to make use of this instead of it rolling it's own. That would be a much more consistent user experience.

Also we should think about ordering the systemd units accordingly and by changing the wireguard module to make us of this PRs functionality we can even provide an example (and test?) of how to properly interact with it.

@d-xo
Copy link
Contributor Author

d-xo commented Nov 27, 2019

Now that you are raising that I come to question if we should perhaps modify the wireguard module to make use of this instead of it rolling it's own. That would be a much more consistent user experience.

It's a good point, but I feel that network namespaces are a pretty generic feature with more uses than just wireguard VPN's, so I would prefer to keep facilities for their creation separate from the wireguard module. @asymmetric you added the namespace support to the wireguard module, what do you think?

we should think about ordering the systemd units accordingly

I currently have the namespace units set to before = [ "network-pre.target" ], and the wireguard units are set to after = [ "network-online.target" ]. Looking at it again now, the current before condition seems excessive, and I think that before = [ "network-online.target" ] should be sufficient?

by changing the wireguard module to make us of this PRs functionality we can even provide an example (and test?) of how to properly interact with it.

Very good point. I have added a commit to this PR updating the wireguard namespace tests to use this module for namespace creation.

@asymmetric
Copy link
Contributor

asymmetric commented Dec 3, 2019

Now that you are raising that I come to question if we should perhaps modify the wireguard module to make use of this instead of it rolling it's own. That would be a much more consistent user experience.

It's a good point, but I feel that network namespaces are a pretty generic feature with more uses than just wireguard VPN's, so I would prefer to keep facilities for their creation separate from the wireguard module. @asymmetric you added the namespace support to the wireguard module, what do you think?

I'm not sure I know what we're talking about. The Wireguard module doesn't create namespaces, and the feature I've added only expects them to already exist, so this change seems pretty orthogonal.

If you mean in the Wiregurad namespaces tests, then sure, I think it's good to use the new attirube there.

I think this is a good interim solution until networkd has native support for namespace creation.

@d-xo
Copy link
Contributor Author

d-xo commented Dec 10, 2019

rebased on master and addressed review comments.

I'm not sure I know what we're talking about. The Wireguard module doesn't create namespaces, and the feature I've added only expects them to already exist, so this change seems pretty orthogonal.

@asymmetric I had understood the question to be whether the wireguard module should start creating network namespaces itself. Although reading back I may have been getting a little confused :/

Allow declarative creation of named network namespaces
Allow nixos containers to be launched in a pre-existing named network
namespace
@d-xo
Copy link
Contributor Author

d-xo commented Dec 11, 2019

rebased on master and cleaned up the tests.

@asymmetric
Copy link
Contributor

@asymmetric I had understood the question to be whether the wireguard module should start creating network namespaces itself.

@xwvvvvwx @andir I think the two concerns are pretty orthogonal, and by not tying them together too much we leave the option open for other ways of creating the namespace to emerge in the future. As long as it's documented (which it is), I think users should be tasked with creating the namespace however they see fit.

Also, if the namespace already exists, the wireguard module will then break, unless you make namespace creation idempotent, which seems pretty hacky.

All in all, I think we shouldn't do it. WDYT?

Type = "oneshot";
RemainAfterExit = true;
ExecStart = "${pkgs.iproute}/bin/ip netns add ${strings.escapeShellArg netns}";
ExecStop = "${pkgs.iproute}/bin/ip netns del ${strings.escapeShellArg netns}";
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to the ip-netns manpage:

             It is possible to lose the physical device when it was moved
              to netns and then this netns was deleted with a running
              process:

                 $ ip netns add net0
                 $ ip link set dev eth0 netns net0
                 $ ip netns exec net0 SOME_PROCESS_IN_BACKGROUND
                 $ ip netns del net0

              and eth0 will appear in the default netns only after
              SOME_PROCESS_IN_BACKGROUND will exit or will be killed. To
              prevent this the processes running in net0 should be killed
              before deleting the netns:

                 $ ip netns pids net0 | xargs kill
                 $ ip netns del net0

Do you think it's necessary to document this in the module?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is usually used to move wg* interfaces into a namespace, right?

So it's probably not too much of an issue. Adding a link to these docs sounds like a good idea, but we don't need to copy this paragraph in.

@netvl
Copy link

netvl commented May 9, 2020

Hello,

Is there any chance for this to get merged? This seems like a very useful piece of functionality.

value = {
description = "Network Namespace: ${netns}";
before = [ "network-pre.target" ];
wantedBy = [ "multi-user.target" ];
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: According to this documentation page, one should set Wants=network-pre.target.

I don't t know if there will be a difference in practice for most users, but I do think there's some dissonance in binding namespace creation to the multi-user.target.

OTOH the wireguard module also does WantedBy=multi-user.target, so maybe this is a convention that makes sense in NixOS?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Citing from above docs:

Services that want to be run before the network is configured should place Before=network-pre.target and also set Wants=network-pre.target to pull it in.

We should add Wants=network-pre.target.

I don't understand the question regarding multi-user.target.

@errnoh
Copy link
Contributor

errnoh commented Jun 10, 2020

Started using this as well, everything works as advertised on 20.03. Wouldn't mind getting this functionality merged at some point.

@asymmetric
Copy link
Contributor

asymmetric commented Jun 11, 2020

I would like to see this land too, it's been way too long and it's already shown itself to be useful to several people.

One day networkd will support this usecase natively, we will remove scripted networking and everything will be simpler. But that day is not here yet, and I see no reason not to incrementally improve the status quo, when we can.

@stale
Copy link

stale bot commented Jun 4, 2021

I marked this as stale due to inactivity. → More info

@stale stale bot added 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md and removed 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md labels Jun 4, 2021
@asymmetric
Copy link
Contributor

Still relevant

@stale
Copy link

stale bot commented Jan 9, 2022

I marked this as stale due to inactivity. → More info

@stale stale bot added the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Jan 9, 2022
@wegank wegank marked this pull request as draft March 20, 2024 15:10
@stale stale bot removed the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Mar 20, 2024
@wegank wegank added the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Mar 20, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

8 participants