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

Flake authentication #2849

Open
edolstra opened this issue Mar 19, 2019 · 10 comments
Open

Flake authentication #2849

edolstra opened this issue Mar 19, 2019 · 10 comments
Labels
feature Feature request or proposal flakes

Comments

@edolstra
Copy link
Member

Inspired by NixOS/rfcs#34 discussion:

Currently we don't have any way to authenticate flakes. We only have transport security, e.g. by downloading via https or ssh, so if the server is compromised, it can serve Trojaned flakes. Thus, we would like to have the ability to require that flakes are signed in some way.

Authentication is only needed when fetching from a mutable flake reference (i.e. one that doesn't include a Git revision or content hash). It will be assumed that the immutable flake references in a lock file were authenticated at the time the lock file was generated. [Actually it just occurs to me that for security, github flakes must include a content hash in the lock file, since we have no way to verify that the Git revision corresponds to the contents.]

Ideally, the flake registry would contain public keys that are allowed to sign the trees fetched from a mutable flake reference. For example,

{
    "version": 1,
    "flakes": {
        "dwarffs": {
            "uri": "github:edolstra/dwarffs/flake",
            "publicKeys": ["E52y5ZkdNLl3LUYl3TiwR7XTZAPU7jgkEYDvsmbavio="]
        },
        "nixpkgs": {
            "uri": "github:NixOS/nixpkgs-channels",
            "publicKeys": ["FioIjAooQuwH200U4u5H2asLDCNZXaHpmxQnj2fcggQ="]
        }
    }
}

Alternatively, public keys could be part of a flake URI, e.g. a flake dependency could specify a public key like this:

{
  requires = [
    github:edolstra/dwarffs?publicKey=E52y5ZkdNLl3LUYl3TiwR7XTZAPU7jgkEYDvsmbavio=
  ];
}

However, the main issue is how to associate a signature with the downloaded flake.

  • For github flakes, GPG signatures can be fetched out-of-band via the GitHub API, but I would prefer to avoid GPG because 1) it's 1990s crypto; 2) I don't want to make Nix dependent on GPG when we already have libsodium; 3) GPG keys/signatures are much more unwieldy than libsodium's ed25519; 4) it would be nice to use the exact same mechanism as binary caches. We could use Git notes to attach ed25519 signatures, but I don't think they can be queried via the GitHub API.

  • For git flakes, since we're cloning the whole repo, we do have the ability to use Git notes.

  • For tarball flakes, the signature could be included in the tarball, or delivered as a separate file (e.g. http://example.org/flake.tar.xz.sig). However, the latter is racy because there is a time window between flake.tar.xz and flake.tar.xz.sig get updated.

Another possibility is to fetch the signature from some content-addressable source specified in the flake registry, e.g. "nixpkgs": { "sigs": "https://nixos.org/flake-sigs", ... }. The client would compute the hash of the data to sign (see below) and then download the signature from https://nixos.org/flake-sigs/<hash>.

Signature contents: The signature should be over the string <content-hash>:<git-revision>:<git-ref>:<refcount-or-commit-date>. The git-ref (branch or tag name) is included to prevent an attack where the attacker replaces one channel (e.g. nixos-19.03) with another (e.g. nixos-unstable). refcount-or-commit-date could be used to prevent rollback attacks, but this requires the client to keep some state about the last refcount or date it saw from a mutable flake.

Registry authentication: The registry should also be signed. The public signing key will be hard-coded in Nix.

Certificates: We should allow the private signing key ("cold key") for a flake to be kept offline. This can be done by signing the flake using a hot key, and including in the signature file a certificate where the hot key signs the cold key. Revoked keys could be listed in the registry. (This would be pretty nice to have for binary cache signing as well.)

@CSVdB CSVdB assigned CSVdB and unassigned CSVdB Apr 6, 2019
@CSVdB
Copy link
Contributor

CSVdB commented Apr 6, 2019

How can you sign mutable references? They can by definition change, so including anything like a content hash is impossible. Who would be able to sign these things exactly? Is that GitHub itself?

For immutable references, I would definitely try to include some sort of content hash to secure against GitHub being hacked.

@grahamc grahamc transferred this issue from another repository May 16, 2019
@grahamc grahamc added the flakes label May 16, 2019
@edolstra
Copy link
Member Author

You don't sign mutable references, you sign particular versions of a flake. This could be done as a signature over an immutable reference. But the real question is where to get the signatures from.

@edolstra edolstra added the feature Feature request or proposal label Jan 30, 2020
@stale
Copy link

stale bot commented Feb 16, 2021

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

@stale stale bot added the stale label Feb 16, 2021
@hmenke
Copy link
Member

hmenke commented Feb 27, 2021

This is still important to me. I don't know whether that is feasible in general but at least for Git Nix could just use existing commit signatures. That's sort of portable because there already exists instrumentation in Git and it would also work for non-flake references to Git repos.

@L-as
Copy link
Member

L-as commented Aug 14, 2021

Relevant: NixOS/rfcs#100

@stale
Copy link

stale bot commented Apr 17, 2022

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

@stale stale bot added the stale label Apr 17, 2022
@hmenke
Copy link
Member

hmenke commented Apr 17, 2022

Begone, bot!

@stale stale bot removed the stale label Apr 17, 2022
@stale stale bot added the stale label Oct 30, 2022
@cyntheticfox
Copy link

I'm particularly concerned about this, but mostly about what was a footnote: registry signing.

While it's a good idea to validate/sign the flakes themselves, the global registry itself should be signed and validated, since otherwise that opens up the possibility of server spoofing (DNS poisoning most likely).

The two issues can probably be solved separately even: checking whether or not the list of aliases provided by the registry is provided securely doesn't have to be tied to whether or not the resulting reference is secure.

Even then, that would mean you could then build a secure registry by providing aliases to specific revisions (possibly with hashing? idk about that part).

@stale stale bot removed the stale label Nov 16, 2022
@benaryorg
Copy link

This is still important to me. I don't know whether that is feasible in general but at least for Git Nix could just use existing commit signatures. That's sort of portable because there already exists instrumentation in Git and it would also work for non-flake references to Git repos.

I fully agree.
Specifically using built in git GPG signatures means that, given a trust store is provided out-of-band, any git repository with any hoster can be used, whether it be GitHub, GitLab, self-hosted Gitea, whatever Smart HTTP implementation or just bare repositories via SSH, it incurs no dependency on infrastructure that can be compromised other than the developer of the flake.
The signatures do not only apply to commits, they also apply to tags, which would allow one to mirror an upstream flake repository without tags and push signed tags to the mirror for commits which have been verified in some form (code review for external sources is important in hardened environments).
Furthermore all signatures apply to the commit, which includes the tree-reference among other data, which by extension is also verified, thus we can rely on the provided flake.lock being verified, and as long as the refs and proposed content-hashes provided therein can be fetched we also have a theoretical verification of the entire supply chain.

As an added benefit this does not require any additional tooling for the developers of flakes; everything requires is built-in and ships with git, provided the runtime dependencies are met (gpg is in your PATH).

While I am a strong proponent of ed25519 signatures everywhere, git already provides plenty of tooling for this use-case.
If additional tooling was required or even new workflows (such as signing release tarballs) I am sure this would lead to either less adoption, or adoption in ways that actually reduce security (think of CI pipelines signing code; opening up side-channels).

but I would prefer to avoid GPG because 1) it's 1990s crypto

I'd like to remind you that the Linux kernel is 1990s stuff too, as is Plan9, as is SSH, all of which are several years older than GPG actually (which is a 1999 thing), making it four years younger than the initial IPv6 drafts.

@cyntheticfox
Copy link

cyntheticfox commented Mar 31, 2023

Given the added support for git signing with ssh keys since I last commented, and that recent debacle of GitHub exposing their SSH host key, it might be an increasingly decent idea...

EDIT: Would <sigstore.dev> be of use here? Haven't used it so I have no idea.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Feature request or proposal flakes
Projects
None yet
Development

No branches or pull requests

7 participants