Uv2nix: Unable to fetch packages with authentication credentials

Hi,

I am trying to set up uv2nix to manage fetching and building my python project from within a Nix flake. Some of my dependencies are hosted on a private Git instance, which requires authentication using a developer specific API-token and user id. The issue is figuring out how to pass this token to the flake.

The documentation for uv2nix lists a recommended way to do this by passing the netrc-file to curl, like so:

manualOverrides = final: prev: {
  internally-hosted-py-lib = prev.internally-hosted-py-lib.overrideAttrs(old: {
    src = old.src.overrideAttrs(_: {
      curlOpts = "--netrc-file /etc/nix/.netrc";
      SSL_CERT_FILE = "${pkgs.cacert}/etc/ssl/certs/ca-bundle.crt";
    });
  });
};

However, even when running nix develop with the option --option extra-sandbox-paths /etc/nix/.netrc as the documentation states, this fails with the error:

trying https://git.domain.tld/api/…/internally-hosted-py-lib.whl
curl: (26) .netrc error: no such file

Attempting to pass .netrc to the flake through extra-sandbox-paths gives an immediate error:

error:
   … while setting up the build environment
   error: getting status of "/home/fkedi/.netrc": Permission denied

This failing, I tried passing the credentials directly to curl, using the switch -u name:token, and passing the name and token in through environment variables - but that fails, since Nix flakes simply return empty strings when attempting to read environment variables. If this token was simply a single token shared between the entire team, we could probably use a tool like agenix to safely share the secret, but each developer has their own token that needs to be used automatically.

If anyone has any insight into what might be causing this issue, I would be very appreciative of any help.

And just for transparency: I posted yesterday about this same issue, but I had buried the fact that this was a uv2nix issue in the replies (since I thought it was an issue unrelated to that), and so I was recommended by another user to create a new post that clearly stated this, so that the people with the right knowledge are more likely to find it.

Edit: updated for clarity between two separate issues.

Is the typo there intentional, and/or reflected on the actual system? You’re missing a ., compared to the error message.

That was just a typo in the post - thank you for pointing that out, I’ve edited the post to fix it.

I just figured out what the issue is: The flake can only read the netrc file if it has global read permissions. So running chmod a+r /etc/nix/.netrc fixes the issue, and allows uv2nix to fetch the private repository correctly!

This is not the most ideal solution though, since from what I can gather, it is general best practice to only make .netrc readable by the owner. But it is adequate for my purposes for now.

Right, the “flake” can’t read anything, that’s a nonsensical statement. A flake is an inert data file. It’s no more capable of reading files than your wallpaper.

However, nix, and the builders that nix spawns while building a derivation, can. During evaluation, nix runs as a process started by your user, so builtins.readFile & co can read any files you can, but once nix has evaluated your expressions and decided which derivations need to be built, nix will defer to a nix daemon (which may or may not be running locally) to build stuff.

The nix daemon has root permissions on the host where it runs, but will spawn build processes with the various nixbld<number> users, who are all part of the nixbld group. Those users are the ones who need to have the correct permissions to read any paths they need at build time.

So the correct fix is not to make your key world-readable, but to make it readable by the nix build users:

# chown root:nixbld /etc/nix/.netrc
# chmod u=rw,g=r,o= /etc/nix/.netrc

This makes it so only users allowed to schedule builds with nix can use the secret (though it’s pretty easy to exfiltrate by building a derivation that just copies the key to $out), and only the nix build-related users can read it. To be fair, by default that still means literally all users can use it, because everyone is trusted to execute nix builds by default, but a very sensible way to limit that is to add this to your NixOS config:

{
  nix.settings.allowed-users = [
    # Assuming people who should be able to run nix builds
    # have wheel permissions on their machines
    "@wheel"

    # Or, alternatively, at least only "human" users
    # "@users"
  ];
}

Obviously, if you ever start farming out your builds to a build server, that build server will also need a key in /etc/nix/.netrc and appropriate nix configuration to use it.

2 Likes