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

WIP: implement a secret vars store in nixpkgs #370444

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

Conversation

Lassulus
Copy link
Member

@Lassulus Lassulus commented Jan 3, 2025

This allows to create secrets (and public files) outside or inside the nix store in a more delclarative way. This is shipped with an example (working) implementation of an on-machine storage. The vars options can easily be used to implement custom backends and extend the behaviour to integrate with already existing solutions, like sops-nix or agenix.

I wanted to upstream this, since we use code similiar to this in https://clan.lol now for a while. Happy to discuss it a bit more. I'm not very fond of the name vars anymore, so maybe a first change could be to come up with a better name :)

I'm not sure if this code is working yet, I will try to develop it a bit more in the next coming days, but I wanted to get this out earlier so other people can throw in some feedback already :)

@Lassulus Lassulus requested a review from oddlama January 3, 2025 01:49
@github-actions github-actions bot added 6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` labels Jan 3, 2025
@lucasew
Copy link
Contributor

lucasew commented Jan 3, 2025

How this compares to sops-nix?

@Lassulus
Copy link
Member Author

Lassulus commented Jan 4, 2025

How this compares to sops-nix?

This enhances sops-nix, It is more of an upstream evolution of agenix-rekey.

The gist is: This supports declaring how to generate the secrets you store in sops-nix in nixpkgs in the service module.

I will add a declaration to a service soon, so it is easier to understand :)

@Lassulus
Copy link
Member Author

Lassulus commented Jan 7, 2025

alright, removed some features to make the first implementation easier.
Some things are still missing in the on-machine backend like dependencies and prompts. but the rough shape should be more clear now :)

@github-actions github-actions bot added 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin 10.rebuild-linux: 1-10 labels Jan 7, 2025
@Lassulus Lassulus force-pushed the nixos-vars branch 3 times, most recently from 3f0acbe to 339d2bc Compare January 7, 2025 23:43
@nixos-discourse
Copy link

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

https://discourse.nixos.org/t/2025-01-08-clan-weekly-changelog/58501/1

@oddlama
Copy link
Contributor

oddlama commented Jan 8, 2025

This looks awesome, I'll have to play around with it a bit more to understand all the details.

Have you already thought about how this would work when someone wants to use vars/secrets in the initrd in stage1? I imagine there could be some kind of hen-egg problem since the initrd will be generated pretty early on when a new generation is activated. The configured vars/secrets may probably not exist at that time, so this might require activating twice (?)

@lucasew
Copy link
Contributor

lucasew commented Jan 8, 2025

I am curious about how it would work in stage 1 because AFAIK / is not mounted yet in this phase, so how it will read the host key to decrypt the secrets.

@Lassulus
Copy link
Member Author

Lassulus commented Jan 9, 2025

Have you already thought about how this would work when someone wants to use vars/secrets in the initrd in stage1? I imagine there could be some kind of hen-egg problem since the initrd will be generated pretty early on when a new generation is activated.

The current code here doesn't run during activation but creates a script that can be run before activation. in clan.lol we solved that issue differently by having a requiredBy option which can take "activation". We would create the files necessary for activation beforehand in that case, but I think this adds too much complexity to this initial PR.
But this can be something we can add later on top of it.
For now just having all the files created in one phase would be easier and since the creation script can be run at any time (even before installation) they should be available for all phases.

Another problem is also the prompts which some vars can ask for. Having the generation run in the activation would make prompting for input very hard. So I think a better way would be to prompt in nixos-install/nixos-rebuild, so before running activation. But this is also something I will add in a later iteration :)

@Lassulus
Copy link
Member Author

Lassulus commented Jan 9, 2025

I am curious about how it would work in stage 1 because AFAIK / is not mounted yet in this phase, so how it will read the host key to decrypt the secrets.

This is not really in scope for this PR. The current on-machine implementation I added here, doesn't encrypt the secrets (yet?) so there should be no issue with stage-1. secrets can still be added to initrd if they are required to early boot and they should be available at that time.

@Lassulus Lassulus force-pushed the nixos-vars branch 3 times, most recently from 46b881c to b6b0bed Compare January 12, 2025 00:50
nixos/modules/system/vars/options.nix Outdated Show resolved Hide resolved
Comment on lines +123 to +118
prompts = lib.mkOption {
description = ''
A set of prompts to ask the user for values.
Prompts are available to the generator script as files.
For example, a prompt named 'prompt1' will be available via $prompts/prompt1
'';
default = { };
Copy link
Contributor

Choose a reason for hiding this comment

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

Can we add a value option or something similar to each prompt? I would like to be able to pre-define the value of the prompt to ensure that a user can always opt-in to a purely declarative configuration.

Btw, I currently don't understand when an author of a nixos module would decide to utilize a prompt instead of a generated random value. If I am writing a generator for my personal configuration, I can understand that I might want to use prompt for certain things - but when would I want to use a prompt in an upstream module and force interactivity on every user?

I'm just a little worried right now that introducing prompts without a way to declaratively set their value will sooner or later result in some generators being added to nixpkgs which depend on some form of interactivity. Therefore I'd like to have a way to specify the value of a prompt ahead of time, so the generation script can then just copy the specified file to prompts/$name instead of asking the user a question.

Copy link
Member Author

Choose a reason for hiding this comment

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

we mainly use prompts for API keys, which we usually don't want to leak into the config. I guess we can think about pre declaring things, this would also make the testing code a bit easier which I worked on last time I touched that code. But this increases the surface every backend implementation has to take care of.

nixos/modules/system/vars/options.nix Outdated Show resolved Hide resolved
Comment on lines +31 to +32
lib.types.submodule (generator: {
options = {
Copy link
Contributor

Choose a reason for hiding this comment

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

I would like to propose an additional option for each generator called backend, which is just an empty submodule by default and can be extended by the used backend similar to how you designed the fileModule:

backend = lib.mkOption {
  type = lib.types.submodule {
    imports = [
      config.vars.settings.backendModule
    ];
  };
  default = {};
  description = ''
    Additional options for the backend in use.
  '';
};

This would allow the specific backend implementation to expose additional options for each generator, allowing users who opt-in to a specific backend to use additional features of that generator:

  • One example would be a generator which can both generate secrets before deploying a machine in the repository as well as on the machine to have selected vars be generated on the machine (e.g. dhparams, temporary keys, ...).
  • Another example is specifying an owner/group for the generated secrets, in case they are stored in the repository (as with sops-nix/agenix) so the backend knows which key to use to encrypt a generated secret when there are multiple administrators involved in writing a single configuration.

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 like the idea, but I'm not sure yet what complexities this can introduce. It sounds like a good idea for a follow up PR maybe? :)

Also how do we force modules in nixpkgs to be backend agnostic? since it would be sad, if some generators use backend specific features and lock out other backends this way?

Copy link
Member Author

Choose a reason for hiding this comment

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

also I don't think we need to use the backendModule here, defining the additional options in a new module should just work? we use the fileModule in that way, because we need to set some values in every file for a specific backend, but this wouldn't be the case here, right?

This allows to create secrets (and public files) outside or inside the
nix store in a more delclarative way. This is shipped with an example
(working) implementation of an on-machine storage. The vars options can
easily be used to implement custom backends and extend the behaviour to
integrate with already existing solutions, like sops-nix or agenix.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
6.topic: nixos Issues or PRs affecting NixOS modules, or package usability issues specific to NixOS 8.has: module (update) This PR changes an existing module in `nixos/` 10.rebuild-darwin: 0 This PR does not cause any packages to rebuild on Darwin 10.rebuild-linux: 1-10
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants