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 config option to disable networking entirely #63541

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

Conversation

jameysharp
Copy link
Contributor

Motivation for this change

I've had some success at building single-purpose read-only root filesystem images by heavily customizing NixOS configuration options and package overrides. (I'd like to see NixOS supplant Yocto 😈)

But one of the things I couldn't disable was support for networking. I could turn off most individual services, like a DHCP client, but there was still some core stuff wasting space and boot time in my images. Most NixOS users will leave networking enabled, but for specialized applications it's really helpful to just turn it off entirely.

Things done

Even after reading the manual I don't understand how to run the tests. I ran:

nix-build tests/networking.nix --arg networkd true

I don't know what it would look like if it failed, but I got 12 result* symlinks at the end, and spot-checking logs looks okay I guess?

  • 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)
  • Assured whether relevant documentation is up to date
  • Fits CONTRIBUTING.md.

config.environment.etc."nsswitch.conf".source
config.environment.etc."nscd.conf".source
];
] ++ optional config.networking.enable config.environment.etc.hosts.source;
Copy link
Contributor

Choose a reason for hiding this comment

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

why is this change required?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fair question, I should probably have called that out. It's because if networking is disabled, /etc/hosts doesn't get created at all, and config.environment.etc.hosts is undefined. But nscd is still usable without network so it shouldn't get automatically disabled entirely.

Thanks for reviewing!

@jameysharp jameysharp mentioned this pull request Jul 15, 2019
10 tasks
@abbradar
Copy link
Member

@GrahamcOfBorg test networking.scripted.loopback networking.scripted.static networking.scripted.dhcpSimple networking.networkd.loopback networking.networkd.static networking.networkd.dhcpSimple

@abbradar
Copy link
Member

621ec1d

This could actually be converted into a system-wide check for broken targets.

@jameysharp
Copy link
Contributor Author

Sure, I suppose so! I'm not sure whether it should be an assertion in general though. That commit helped me find services which were implied by something in my configuration but didn't make sense without a network, but maybe it's over-zealous.

Maybe in general it should work like this:

  • requires/bindsTo/requisite indicate that if the referenced unit does not exist, this unit can't possibly work. So add assertions for those.
  • wants indicates that some functionality might be missing without it, so add warnings.
  • wantedBy/requiredBy mean that without the referenced unit, maybe this unit won't be started, I guess? But the admin could still start it manually, so I guess that's also warnings.
  • Maybe partOf should be in the same category as conflicts: if the referenced unit doesn't exist, the directive has no effect, but the unit still works, so don't report it at all.
  • before/after sometimes seems to be used as "if that unit is started, then I need to be ordered relative to it, but I don't care otherwise." So maybe don't report missing references for those either?

Does that seem right?

If you'd like I can drop that commit from this PR and try putting the more general version together.

@abbradar
Copy link
Member

That sounds about right (maybe even warnings won't be convenient), but anyway let's not do this now, this was more of an "idea of future improvement".

@abbradar
Copy link
Member

abbradar commented Jul 17, 2019

@jameysharp You have a conflict there (I suppose introduced by my resolvconf merge).

These are the only networking-related units that are in the list of
upstreamSystemUnits, which prevents users from configuring them out.

By analogy with network-related services like networkd, resolved, and
timesyncd, let's keep the networking targets with the settings that
configure them.
Apparently something else I'm working on made it a problem for config
declarations in this module to depend on evaluating utils.nix. I don't
understand where the evaluation cycle is, but in this case it's shorter
to reference `utils.` explicitly once than it is to say `with utils;`,
so I'm not bothering to think about it very hard.
@jameysharp
Copy link
Contributor Author

Ah, I added things right next to where you removed things, and merge didn't know what to do... I've rebased it and fixed the conflicts. I'm going to go re-run my original ad-hoc tests now but I wanted to get the bot started on this in parallel, so:

@GrahamcOfBorg test networking.scripted.loopback networking.scripted.static networking.scripted.dhcpSimple networking.networkd.loopback networking.networkd.static networking.networkd.dhcpSimple

@jameysharp
Copy link
Contributor Author

I... don't think the bot actually ran these tests? Maybe because it was still running the initial checks from when I pushed the rebased commits?

@GrahamcOfBorg test networking.scripted.loopback networking.scripted.static networking.scripted.dhcpSimple networking.networkd.loopback networking.networkd.static networking.networkd.dhcpSimple

On a system with nss-myhostname configured, as it is by default on
NixOS, /etc/hosts is not necessary for most people. Although NixOS
currently creates it unconditionally, this patch allows for setting
`environment.etc.hosts.enable = false`, and also clears the way for
NixOS to someday not create the file in the first place.
I want to be able to turn off all services which require a network.
Some of them had existing configuration options, but several core
modules did not, so it wasn't possible to turn networking off
completely.
@jameysharp jameysharp force-pushed the no-net branch 2 times, most recently from e9e36fa to 66a9d20 Compare July 17, 2019 20:08
@jameysharp
Copy link
Contributor Author

I guess the bot is ignoring me.

After trying to figure out how the new resolvconf module should interact with this setting, I'm having second thoughts about some of this. I've changed the etc.hosts.source bit to just check whether the file exists rather than checking whether networking is enabled... and I'd appreciate feedback on the following questions!

The big issue is that settings like services.resolved.enable need to evaluate to false when networking is disabled, because other modules like config/nsswitch.nix change behavior accordingly... but I only changed e.g. system/boot/resolved.nix to check that both services.resolved.enable and networking.enable are true, so whether resolved is actually enabled isn't fully determined by services.resolved.enable.

How should that work instead? We should be setting the config option itself based on the value of networking.enable, right? But how strongly should that be enforced?

  • services.resolved.enable = mkIf (!config.networking.enable) (mkDefault false) means someone can override it somewhere else.
  • services.resolved.enable = mkIf (!config.networking.enable) false means someone can override it somewhere else, but only using mkForce.
  • services.resolved.enable = mkIf (!config.networking.enable) (mkForce false) means even a mkForce somewhere else can't override it.

This pattern should probably be packaged up in config.lib.networking.required or something like that, so the assignments look like services.resolved.enable = networking.required.

Another question is, should every module that accesses anything in the config.networking hierarchy perhaps be disabling itself if networking is disabled? And if so, is there a better way than just adding something like the above in all ~93 such modules and hoping that authors of new modules will do the same?

Finally of course there's @abbradar's observation that the check for unsatisfiable systemd units could be a global thing rather than special for networking. I've dropped my patch for that from this pull request because I think it should get more thought.

@danbst
Copy link
Contributor

danbst commented Jul 17, 2019

@jameysharp you should request ofborg rights, see examples https://github.com/NixOS/ofborg/pulls?q=is%3Apr+is%3Aclosed

But how strongly should that be enforced?

I don't think it is a thing to bother. If someone defines resolved.enable = true; and networking.enable = false;, just disable network. Disabled network isn't a thing used daily, so shouldn't cause much headache in long run.

should every module that accesses anything in the config.networking hierarchy perhaps be disabling itself if networking is disabled?

Probably yes, but luckily this can be done incrementally after this is merged.

@abbradar
Copy link
Member

abbradar commented Jul 18, 2019

@jameysharp I think if you patch all services that somehow require networking you'd be playing whack-a-mole and it's easy to make a mistake and disable a module which can actually be useful without networking for some obscure use case.

Instead I'd:

  1. Make a best effort in disabling the networking itself (so networkd and network scripts should behave according to services.networking.enable). Other modules that manage interfaces should probably be disabled too, like VPN modules. This approach limits the scope and makes it easier to reason about whether the module should make notice of networking.enable.
  2. Add assertions to limit truly impossible configurations (your check of units that require networking.target and friends was good; unfortunately that doesn't cover cases of systemd.packages and upstream units).

Other networking services like resolved could just be left alone - even if someone enables them they just run idle. This corresponds to other cases like services.xserver.enable and various modules that de-facto need X11 but are harmless without it (even desktop environments!).

Finally, one shouldn't use mkForce in a module; this function exists precisely to enable people who know what are they doing to build even the craziest of configurations.

EDIT: Also, services like resolvconf which cannot usually be disabled should also disable themselves if networking is disabled, but this is an edge case.

upstreamNetworkUnits = [
"network.target"
"network-pre.target"
"network-online.target"
Copy link
Member

@Mic92 Mic92 Jul 18, 2019

Choose a reason for hiding this comment

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

Would the absent of these targets not break many services? Since there are just text files do we really gain a lot by leaving them out?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

In order: The absence of these targets should break exactly those services which this new option is meant to disable; and leaving them out doesn't have anything to do with closure size, since they're shipped in systemd's examples/ directory regardless. Does that help?

@danbst
Copy link
Contributor

danbst commented Aug 6, 2019

@Mic92 @abbradar is general consensus to merge this as is, and polish things on demand? Networking is still enabled by default.

If so, then I'll test it on my machine and merge if it works.

@jameysharp
Copy link
Contributor Author

@danbst Thanks for the ping, I got distracted.

I think before this is merged I probably ought to take yours and @abbradar's advice on which modules should respect the new option, at least to the extent of dropping the resolved and timesyncd changes.

I'd also like to fix networkd so that its enable option reflects the overall networking.enable setting unless the user does mkForce to override it, I think by merging a systemd.network.enable = mkIf (!config.networking.enable) false assignment into the config. (e.g. my option 2 above)

After that I think anything else would be fine to defer to later work. Does that seem reasonable?

@stale
Copy link

stale bot commented Jun 1, 2020

Thank you for your contributions.
This has been automatically marked as stale because it has had no activity for 180 days.
If this is still important to you, we ask that you leave a comment below. Your comment can be as simple as "still important to me". This lets people see that at least one person still cares about this. Someone will have to do this at most twice a year if there is no other activity.
Here are suggestions that might help resolve this more quickly:

  1. Search for maintainers and people that previously touched the
    related code and @ mention them in a comment.
  2. Ask on the NixOS Discourse. 3. Ask on the #nixos channel on
    irc.freenode.net.

@stale stale bot added the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Jun 1, 2020
@stale stale bot removed the 2.status: stale https://github.com/NixOS/nixpkgs/blob/master/.github/STALE-BOT.md label Oct 3, 2020
@stale
Copy link

stale bot commented Jun 7, 2021

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 Jun 7, 2021
@wegank wegank marked this pull request as draft March 20, 2024 15:08
@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

6 participants