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/netbird: harden and extend options #287236

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

nazarewk
Copy link
Member

@nazarewk nazarewk commented Feb 8, 2024

Description of changes

I have recently extensively tested and fixed all features of Netbird in my own implementation of multi-instance Netbird installations.

While doing so I discovered another multi-instance implementation got merged into nixpkgs #246055 which is slightly different, but still a solid base to upstream the rest of my changes:

  • running as DynamicUser it's own user with minimal set of permissions
    • it was there before, but was lacking some of capabilities,
  • made some configurations situational
  • add more unmanaged interface configurations
  • quality of life improvements:
    • configure log level for each interface
    • optionally turn off starting during boot
    • openFirewall by default
    • add shortcuts/wrappers for each created instance

I think it's a pretty good time to upstream, because I will be extensively using it at work: just launched my first Colmena-managed NixOS into GCE.

There are plans to support multi-account connections on the same daemon in Q2/2024 (see the slack message), but it's not known what shape it will take at all.

I decided to implement following significant changes:

  • instances must specify a port they will be listening on as it doesn't make much sense to give an immediately conflicting default,
  • aliased tunnels to clients, because a word tunnel does not exist in Netbird's nomenclature (unlike some other VPNs) and is pretty misleading. Also clients.* play nicely with my plan to implement a server in near future.
  • skipped destructuring expressions (eg: {name, ...}: name -> client: client.name) because they make the code very hard to follow and update with increased number of options,

Things done

  • Built on platform(s)
    • x86_64-linux
    • aarch64-linux
    • x86_64-darwin
    • aarch64-darwin
  • For non-Linux: Is sandboxing enabled in nix.conf? (See Nix manual)
    • sandbox = relaxed
    • sandbox = true
  • Tested, as applicable:
  • Tested compilation of all packages that depend on this change using nix-shell -p nixpkgs-review --run "nixpkgs-review rev HEAD". Note: all changes have to be committed, also see nixpkgs-review usage
  • Tested basic functionality of all binary files (usually in ./result/bin/)
  • 24.05 Release Notes (or backporting 23.05 and 23.11 Release notes)
    • (Package updates) Added a release notes entry if the change is major or breaking
    • (Module updates) Added a release notes entry if the change is significant
    • (Module addition) Added a release notes entry if adding a new NixOS module
  • Fits CONTRIBUTING.md.

Add a 👍 reaction to pull requests you find important.

@nazarewk nazarewk changed the title nixos/netbird: run as DynamicUser with more configuration options nixos/netbird: bring back DynamicUser with more configuration options Feb 9, 2024
@nazarewk nazarewk marked this pull request as draft February 9, 2024 08:43
@nazarewk nazarewk changed the title nixos/netbird: bring back DynamicUser with more configuration options nixos/netbird: harden and extend options Feb 9, 2024
@nazarewk nazarewk force-pushed the netbird-improvements branch 5 times, most recently from 0cf761f to 4179661 Compare February 9, 2024 12:47
@nazarewk nazarewk marked this pull request as ready for review February 9, 2024 12:54
nazarewk added a commit to nazarewk-iac/nix-configs that referenced this pull request Feb 9, 2024
Signed-off-by: Krzysztof Nazarewski <gpg@kdn.im>
@Tom-Hubrecht Tom-Hubrecht assigned mlvzk and unassigned mlvzk Feb 10, 2024
nixos/modules/services/networking/netbird.nix Show resolved Hide resolved
nixos/modules/services/networking/netbird.nix Show resolved Hide resolved
nixos/modules/services/networking/netbird.nix Outdated Show resolved Hide resolved
nixos/modules/services/networking/netbird.nix Outdated Show resolved Hide resolved
{ config
, lib
, pkgs
, ...
Copy link
Contributor

Choose a reason for hiding this comment

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

Reformatting this should not be commited

Copy link
Member Author

Choose a reason for hiding this comment

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

this is what nixpkgs-fmt does, as far as i remember the code should be formatted with it?

nixos/modules/services/networking/netbird.nix Outdated Show resolved Hide resolved
Comment on lines 96 to 118
suffix = mkOption {
type = str;
default = "-${name}";
description = ''
Suffix to use for this further naming of the service pieces.
'';
};
Copy link
Contributor

Choose a reason for hiding this comment

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

This seems overly complicated, as it is only used for defaults, you should use the name for this

Copy link
Member Author

Choose a reason for hiding this comment

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

It is also used for the wrapper, but yeah might make more sense to not drop -wt0 from the default config. The raw "unwrapped" package should work with it anyway.

Copy link
Member Author

@nazarewk nazarewk Feb 13, 2024

Choose a reason for hiding this comment

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

it made more sense when there were 3 wrappers

nixos/modules/services/networking/netbird.md Outdated Show resolved Hide resolved
@@ -12,6 +12,7 @@ import ./make-test-python.nix ({ pkgs, lib, ... }:
};
};

# TODO: confirm DynamicUser is working if/after netbird server is implemented
Copy link
Contributor

Choose a reason for hiding this comment

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

There is no netbird server in this PR

Copy link
Member Author

@nazarewk nazarewk Feb 13, 2024

Choose a reason for hiding this comment

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

yeah, but it is very much relevant for the test, there is no confirmation the client actually works until we have a server to connect to.

Comment on lines 179 to 192
exports = pipe config.environment [
(mapAttrsToList (name: default:
# Couldn't default with `''${${name}:${escapeShellArg default}}`
# because `escapeShellArg` wraps values in single quotes,
# which in turn works differenty (or rather doesn't) than double-quotes
# in this shell parameter expansion
''test "''${${name}+X}" == X || export ${toShellVar name default}''))
(concatStringsSep "\n")
];
in
pkgs.writeShellScriptBin "netbird${config.suffix}" ''
${exports}
${lib.getExe' cfg.package "netbird"} "$@"
'';
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 very weird, nixpkgs has a machinery already to wrap programs c.f. https://nixos.org/manual/nixpkgs/stable/#fun-wrapProgram

Copy link
Member Author

Choose a reason for hiding this comment

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

I'm pretty sure it would be significantly longer with wrapProgram, something like:

mkDerivation {
	pname = "xxx";
    installPhase = 
	    let
	  		exports = pipe config.environment [
	          (mapAttrsToList (name: default:
	            "--set-default '${name}' '${default}'"))
	          (concatStringsSep " ")
	        ];
		in
		"wrapProgram ${lib.getExe' cfg.package "netbird"} $out/bin/netbird${config.suffix} ${exports}";
}

actually makes more sense after prototyping it and seeing with own eyes

Copy link
Contributor

Choose a reason for hiding this comment

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

You can do something like

    stdenv.mkDerivation {
      intallPhase = ''
        wrapProgram ${lib.getExe cfg.package} $out/bin/netbird${config.suffix} ${
          concatMapStringsSep " " ({ name, value }: "--set-default '${name}' '${default}'") (
            attrsToList config.environment
          )
        }
      '';

The issue I had was not because of the size of the code, but reinventing the wheel ^^

Copy link
Member Author

Choose a reason for hiding this comment

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

not so short anymore:

let
  makeWrapperArgs = flatten (mapAttrsToList
    (key: value: [ "--set-default" key value ])
    config.environment
  );
in
pkgs.stdenv.mkDerivation {
  name = "${cfg.package.name}-wrapper-${name}";
  meta.mainProgram = config.name;
  nativeBuildInputs = with pkgs; [ makeWrapper ];
  phases = [ "installPhase" ];
  installPhase = ''
    mkdir -p "$out/bin"
    makeWrapper ${lib.getExe cfg.package} "$out/bin/${config.name}" \
      ${escapeShellArgs makeWrapperArgs}
  '';
}


A single daemon is fully operational.

Multiple daemons will interfere with each other's DNS resolution, but otherwise should remain operational.
Copy link
Contributor

Choose a reason for hiding this comment

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

When the networks have different domains, there is no interference, the only issue is when then share the same domain

Copy link
Member Author

Choose a reason for hiding this comment

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

I don't think the domain is configurable at all on the Netbird server side?

Copy link
Contributor

Choose a reason for hiding this comment

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

It is when you self-host your server

Copy link
Member Author

Choose a reason for hiding this comment

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

FYI:

Hello[@nazarewk, we plan a custom DNS zone support coming next quarter. That would allow you to create custom domains for applications and peers

https://netbirdio.slack.com/archives/C02KHAE8VLZ/p1707820381270479?thread_ts=1707819591.188209&cid=C02KHAE8VLZ

Copy link
Member

Choose a reason for hiding this comment

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

Custom DNS zone support is already implemented for self-hosted,

        ${pkgs.netbird}/bin/netbird-mgmt management \
        --dns-domain dns.domain

Will place every machine under dns.domain subdomain: machine1.dns.domain, machine2.dns.domain

nixos/modules/services/networking/netbird.nix Outdated Show resolved Hide resolved
nixos/modules/services/networking/netbird.nix Outdated Show resolved Hide resolved
nixos/modules/services/networking/netbird.nix Outdated Show resolved Hide resolved
@nazarewk nazarewk force-pushed the netbird-improvements branch 3 times, most recently from a734f1e to 35a7c67 Compare February 13, 2024 11:08
name = mkOption {
type = str;
default = name;
apply = value: "netbird-${value}";
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it would be better style to force the prefix in the relevant locations, otherwise /var/lib/${cfg.name} will always look problematic since it implies any name is possible.

Copy link
Member Author

Choose a reason for hiding this comment

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

sounds reasonable

@nazarewk nazarewk force-pushed the netbird-improvements branch 2 times, most recently from de1630c to f3047d3 Compare June 4, 2024 09:24
Copy link
Contributor

@oddlama oddlama left a comment

Choose a reason for hiding this comment

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

I think you'll have to adjust the release notes to apply to 24.11 now that 24.05 is out the door. But the important details look fine to me, so this is good to go from my side. We can iron out any possible details separately if necessary.

@oddlama
Copy link
Contributor

oddlama commented Jun 9, 2024

There are still changes to nixos/doc/manual/release-notes/rl-2405.section.md

@nazarewk
Copy link
Member Author

nazarewk commented Jun 9, 2024

There are still changes to nixos/doc/manual/release-notes/rl-2405.section.md

Yeah, the nixos manual command refused to pass, assumed it was expecting me to change it?

@oddlama
Copy link
Contributor

oddlama commented Jun 9, 2024

Yeah, the nixos manual command refused to pass, assumed it was expecting me to change it?

I guess it complains because you cannot edit old release notes

@nazarewk
Copy link
Member Author

Yeah, the nixos manual command refused to pass, assumed it was expecting me to change it?

I guess it complains because you cannot edit old release notes

it refused to pass without changes https://github.com/NixOS/nixpkgs/actions/runs/9399057023/job/25885722356

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.

7 participants