nix icon indicating copy to clipboard operation
nix copied to clipboard

Pluggable authentication

Open edolstra opened this issue 1 year ago • 13 comments

Motivation

This PR makes several improvements to HTTP authentication in Nix:

  • It allows the use of Git credential helpers to obtain authentication data (issue #8635). This is configured by the new auth-sources setting. For instance, adding extra-auth-sources = git-credential-libsecret allows Nix to obtain usernames/passwords from the KDE/Gnome keyrings.
  • It adds another builtin authentication source (enabled by adding builtin:nix to auth-sources), which reads usernames/passwords from files in ~/.local/share/nix/auth. The advantage over the netrc authentication source (now known as builtin:netrc) is that it has a file per secret, which makes it easier for scripts/installers to add authentication data.
  • The client will now interactively ask the user for a username/password (via $SSH_ASKPASS) and store this in the configured auth-sources for future use.
  • The Nix daemon can now request authentication data from the client (for trusted users only). E.g. if the user passes --substituters http://my-cache, the daemon will trigger the client to ask the user for the username/password for that cache.
  • Similarly, builtin:fetchurl requests authentication from the parent (outside of the sandbox), so e.g.
    nix build --expr 'import <nix/fetchurl.nix> { url = https://httpbin.org/basic-auth/foo/bar; hash = "sha256-zRy0rqgpwiXQg6mBNsKUqDHHNkW/Dk+3/QHdUlrBURg="; }'
    
    now works.

Context

Priorities and Process

Add :+1: to pull requests you find important.

The Nix maintainer team uses a GitHub project board to schedule and track reviews.

edolstra avatar Jan 26 '24 13:01 edolstra

Separate from the low level protocol minutiae, I think I've considered solving the same problem in a different way, which is having a user-specific remote builder for fixed output derivations. See https://github.com/NixOS/nix/issues/9344

Ericson2314 avatar Jan 26 '24 15:01 Ericson2314

Client-side building would be great but is a much bigger project (and probably wouldn't work on platforms like macOS).

edolstra avatar Jan 26 '24 21:01 edolstra

I don't think it's that big of a project. It's just a client side build + use daemon to add to store. (And the current registerValidPaths is awfully close to that.)

I think for fixed-output derivations without references it should work on macOS just fine. Since there are no references, there is no need to do fake roots / make $out appear in the store dir.

Ericson2314 avatar Jan 26 '24 22:01 Ericson2314

Triaged during the Nix maintainers meeting on 2024-02-16. To discuss further

  • Needs more docs, probably also more tests
  • Requires careful review

To discuss

thufschmitt avatar Feb 16 '24 14:02 thufschmitt

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2024-02-16-nix-team-meeting-minutes-124/39870/1

nixos-discourse avatar Feb 16 '24 14:02 nixos-discourse

This looks great! I have one question:

The Nix daemon can now request authentication data from the client (for trusted users only). E.g. if the user passes --substituters http://my-cache, the daemon will trigger the client to ask the user for the username/password for that cache.

Could we also do this for the s3:// substituter? It is super unergonomic that when e.g. you want to push to s3 bucket in CI that the AWS credentials need to be available to the nix daemon instead of the caller. e.g. this doesn't work if you have a nix-daemon in CI:

steps:
- uses: DeterminateSystems/nix-installer-action@main
# this step sets some AWS_ env vars
- uses: aws-actions/configure-aws-credentials@main
  with:
    role-arn: my-role
# This doesn't work as nix-daemon cant access the env vars
- run: nix copy --to s3://my-bucket

Instead you need to massage the credentials into a /root/.aws/credentials file which is awkard

arianvp avatar Feb 16 '24 16:02 arianvp

Team meeting notes:

  • Needs more documentation.
  • Maybe the extra Unix domain socket can be replaced with a new STDERR_* message to have the daemon request auth from the client. Then it would work over ssh-ng as well.
  • Should be an experimental feature.
  • Currently auth tunneling is only supported for trusted users, but it might be okay to support it for all users. (Though we have to be careful with e.g. Attic since we don't want the client to override the user name used to connect to Attic, since then the server will return a different (possibly untrused) slice of the binary cache.)
  • Maybe the client should ask the user to approve sending credentials to the daemon, so that e.g. a remote SSH daemon cannot exfiltrate arbitrary secrets from the client.

edolstra avatar Feb 19 '24 14:02 edolstra

Sorry I need to clarify on my previous comment:

nix copy --to s3:// works fine as it doesn't involve the nix daemon

but setting an s3 bucket as a substituter e.g.:


nix build --extra-substituters s3://my-bucket

doesn't work as the nix daemon doesn't have access to my local environment variables or my $HOME/.aws folder

So it would be cool if we can use the solution for the https substituter for the s3 substituter as well?

Edit:

I think it's not that easy actually. As all the credential logic is in the AWS SDK itself... So maybe this is not feasible

arianvp avatar Feb 23 '24 17:02 arianvp

This pull request has been mentioned on NixOS Discourse. There might be relevant details there:

https://discourse.nixos.org/t/2024-02-19-nix-team-meeting-minutes-126/40308/1

nixos-discourse avatar Feb 26 '24 07:02 nixos-discourse

Some status updates:

  • There are now two experimental features: auth-forwarding (whether to support forwarding auth from the client to the daemon) and pluggable-auth (whether to support credential helpers).
  • There is a setting store-auth that controls whether to attempt to store interactively prompted auth data into one of the auth sources.
  • The ~/.local/share/nix/auth auth source now supports storing auth data.
  • There is a setting auth-forwarding that determines what users are allowed to forward auth to the daemon: false (nobody), trusted-users or all-users.
  • More tests.

edolstra avatar Mar 08 '24 15:03 edolstra

Some thoughts:

  • From what I can tell, this only does plain http auth, but most services these days authenticate through headers. GitHub (Authorization), GitLab (Private-Token/Job-Token), etc. So ideally there was a way to configure the authentication method as well. But this can be added later on, just worth keeping this in mind.
  • I still think client-side fetching is the preferred long-term solution as it solves a lot of security concerns of passing around credentials. Especially when considering remote builds. If passing credentials to the daemon gets stabilized, it might end up having to support both methods. So worth being careful with how this is exposed. I know this is behind an experimental flag, but given how important this feature is, I expect this will get adopted by a lot of people very soon. Edit: I guessauth-forwarding and pluggable-auth are separate features so they can be stabilized separately.

szlend avatar Mar 09 '24 21:03 szlend

IMO this goes in the wrong direction. Introduces lots of complexity to the Nix codebase. Instead, I suggest working on making fetchers as a whole pluggable. The complexity around builtins.fetchGit should be reduced, and it be used as a "bootstrap fetcher" to fetch fetchers. The fetched fetchers can then do more fancy things such as asking for credentials.

I comment motivated by the exchange in #10567.

cc @roberth

lorenzleutgeb avatar May 21 '24 09:05 lorenzleutgeb

Introduces lots of complexity to the Nix codebase

I'm sympathetic to that.

"bootstrap fetcher" to fetch fetchers

This has security implications; any Nixpkgs package (or otherwise) could then steal credentials, by doing a builtin fetch with a malicious fetching plugin. The beauty of fixed-output derivations is that they sandbox the fetching logic, preventing this. We should take great care to only un-sandbox or pass credentials to fetchers that are trustworthy. That doesn't mean that opening a devshell on an unknown repo is safe (it's not); it's a defense in depth measure.

roberth avatar May 21 '24 11:05 roberth