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

[RFC 0141] Private Derivations #141

Closed
wants to merge 13 commits into from
95 changes: 95 additions & 0 deletions rfcs/0141-private-derivations.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
feature: private-derivations
start-date: 2023-02-03
author: poscat
co-authors: (find a buddy later to help out with the RFC)
shepherd-team: (names, to be nominated and accepted by RFC steering committee)
shepherd-leader: (name to be appointed by RFC steering committee)
related-issues: (will contain links to implementation PRs)
---

# Summary
[summary]: #summary

This RFC proposes to add a special type of derivation called private derivation, which, upon being built, will have their file permissions set to 000/111 instead of the usual 444/555.

# Motivation
[motivation]: #motivation

In short: This RFC mainly concerns with how to safely manage credentials using nix (as opposed to using impure methods like manually copying them over) on NixOS.

The world readability of nix store means that, to safely store credentials, they must first somehow be encrypted before written into the store. They also need to be decrypted before the services are started.

This is less than ideal because one needs to setup a key (which is stored as plaintext on disk) on every machine just to prevent unauthorized users from seeting the credentials.
poscat0x04 marked this conversation as resolved.
Show resolved Hide resolved

Furthermore, if encryption is done before the evaluation of the system configuration (as is the case with [agenix](https://github.com/ryantm/agenix) and [sops-nix](https://github.com/Mic92/sops-nix)), then the nixos module system cannot be utilized to generate configs that contain credentials and one must write them manually.
Copy link
Member

Choose a reason for hiding this comment

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

I think you mean the right thing but the module system can handle that the credentials are in files but most config files do not handle this to well.


All of this can be prevented if we added the ability to make derivation outputs as not readable by anyone other than root, by setting the file mode to 111 (directories and executables) or 000 (regular files). We can then use a trustworthy credential manager, for example systemd with its `LoadCredential=`, to distribute these derivations to the consumers safely.
Copy link
Member

Choose a reason for hiding this comment

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

What about substituter and caches?


# Detailed design
[design]: #detailed-design

We propose adding a `noReadAccess` option to `builtins.derivation`, which, when set to true, makes this derivation a private derivation.

The only difference between a private derivation and a normal derivation, apart
Copy link
Member

Choose a reason for hiding this comment

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

How to handle backwards compatibility?

Copy link
Author

Choose a reason for hiding this comment

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

Hmm, what is the main challenge of backwards compatibility? A machine with outdated nix versions trying to build private derivations?

Copy link
Author

Choose a reason for hiding this comment

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

We should look into how content-addressed paths are implemented, since they also change the store model.

from the hash, is that upon instantiation and after building, the read bit of
the `.drv` file and the output path will be removed (recursively).


## Credential Managers

In our design, the responsibility of access control is to be delegated to a separate process called the credential manager, which is a process with
the `CAP_DAC_OVERRIDE` capability. This frees us from further bloating the store model.

# Examples and Interactions
[examples-and-interactions]: #examples-and-interactions

## Intended usage in NixOS modules
On NixOS there are many modules where configurations that might contain sensitive
information get written into nix store in plaintext (for example the wpa_supplicant module). Private derivations can solve this issue by

1. Writing a helper function `writeTextPrivate` that functions similar to
`writeText`, but instead outputs a private derivation
2. Replace the `writeText` function with `writeTextPrivate` inside the module
3. Use `LoadCredential=` to load the private derivation
4. Replace the derivation output path with `%d/<credName>` (see systemd.exec)

# Drawbacks
[drawbacks]: #drawbacks

- Adding private derivations further complicates the nix store model.
- In the intended use case, the credential remains plaintext at all time, and while the resulting derivation is unreadable, the inputs aren't.
This means the necessary materials that can be used to reconstruct the credential are exposed during build until the inputs are
garbage collected. A dedicated attacker can in theory monitor for file system changes, save the inputs before they are being GC'd
and later reconstruct the final derivation.

# Alternatives
[alternatives]: #alternatives

- Supporting more complicated ACLs as described in [this](https://github.com/NixOS/nix/issues/8) Nix issue.
- Storing private derivations in a separate store path, for example
`/nix/private-store` that have its executable bit removed so that the hashes
are not visible to non-root users.

# Unresolved questions
[unresolved]: #unresolved-questions
Copy link
Contributor

Choose a reason for hiding this comment

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

What about starting a build to access this path? It could just copy out the value. Or would private derivations not be able to be used as input to other derivations? But in that case how would you use these in NixOS? (Maybe the path can be referenced in a build but the actual contents isn't available? That would probably require sandboxing.)

Copy link
Author

@poscat0x04 poscat0x04 Feb 7, 2023

Choose a reason for hiding this comment

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

Yes, the path can be referenced but the contents are not accessible during build. This is possible because the build is carried out by nixbld* users which do not have read access of private derivations.

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 good to explicitly list this in the RFC. Along with other security properties such as nix copy, and interfacing with binary caches.


## Binary caches and copying
How do we prevent the attacker from using `nix copy` to simply copy out the
Copy link
Member

Choose a reason for hiding this comment

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

This is more general: how to prevent copying derivations onto machines with older nix versions or caches?

Copy link
Author

Choose a reason for hiding this comment

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

Hmm, I'm not very familiar with how store and copying works. Do we need assistance on the receiving end or is it just like scp-ing some files?

private derivation to another machine?

What changes are needed for binary cache providers such as `nix-serve` to handle
Copy link
Member

Choose a reason for hiding this comment

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

and hydra, harmonia, etc

private derivations?

## Leaking metadata
The hash is still exposed to the attacker, which opens up some possible attacks.
Copy link
Member

Choose a reason for hiding this comment

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

how to prevent leaking credentials in build logs?

Copy link
Author

@poscat0x04 poscat0x04 Feb 3, 2023

Choose a reason for hiding this comment

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

They definitely might leak, but for the usual use case, which is to write some string into a file like writeText, this shouldn't be a problem. Maybe we can add this to the future works section?

How does this impact the security?

## Content-Addressed paths
It is not yet known how this might interact with content addressed paths.

# Future work
[future]: #future-work

What future work, if any, would be implied or impacted by this feature
without being directly part of the work?