Repository navigation
(Draft) NixOS vars #547171
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
base: master
Are you sure you want to change the base?
(Draft) NixOS vars #547171
Changes from all commits
2439c9d
a03772f
3c571ea
b9cc660
daa8644
5007ad2
3583718
4071077
102c75a
58b788f
45a15e5
31835e5
1cfd433
e146655
1f699cf
1e910dd
f40e08b
17d2198
63f122c
5192f1e
17db18c
d7a94e0
a272c57
5585533
3247215
6c62e01
c08f494
af07a3c
9fb943b
5e66c46
75f123d
15ba998
0fcf4a2
d9e3cfe
2707f94
59a52d9
252c74a
4e5e300
cf9d4b4
7081aaa
647ed69
a29852b
2b4f766
1f13743
e2e957a
28d78d0
f76bf65
dbe25c8
7383c89
8a3102a
5526a33
61da959
bea3061
99b24ae
5bbdc91
ce63855
a6746cd
e257890
60a869a
ac0ae23
6d3d2a9
96730d2
c31a1c5
45890b9
1d4257b
6dd5919
fea0c56
44abd4e
6bcc599
4ba74a2
6017235
d4ccad0
c524600
c34c368
09710c3
93de1e1
9dd8e79
5606de0
e8f627c
6c24add
4d772bc
7341343
d050f9d
8f00619
89f634f
ef83dcd
7c23ff0
fdbed44
7cf936e
e8c6629
9d063ee
a1083c3
29f3456
44c834c
6c34f61
1510538
bf2ca64
042be5d
c1a5b1d
673289b
0b8e389
5ca2a69
da6355a
1a43068
6805332
28d8fc9
2638a44
d9ea6e9
2921e05
d6c1234
8863f16
bbc83d7
81bafcc
e9550db
79a05ba
1f83507
781a47e
5243bc4
3576171
7d8c30d
86d0904
110c89f
3af061f
5e62fb0
4ad0d51
4b0f1db
fc944d5
4daa0f6
bec2d65
133443f
b048fe9
76a5984
12cc227
14ef983
d41eb27
f8c9542
d5578ad
f8efb01
69aa792
9fd1e28
bd8abb9
799e15d
5c8e61a
eb67958
6e70d0b
b9d40ac
5874d1f
cb7d110
068e85d
5ddcee4
2539c73
1bdb92c
f9b8e16
f725800
1de9b0d
09abedb
b4b6d00
874975f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,346 @@ | ||
| { lib, config, ... }: | ||
| with lib.types; | ||
| let | ||
| # A name containing only "safe" characters that we allow passing to the | ||
| # backends. | ||
| # | ||
| # Note that we often default options of type `safeName` to Nix attribute | ||
| # names. For example, | ||
| # ``` | ||
| # secrets.store."foo bar" = {} | ||
| # ``` | ||
| # will implicitly set `secrets.store."foo bar".name = "foo bar"`. This is | ||
| # bad, because the error will get a confusing error coming from the wrong | ||
| # place. In the future, it might be worth creating a modified version of | ||
| # `attrsOf` that does not have this issue, although the added complexity is | ||
| # not worth it right now. | ||
| safeName = | ||
| of: | ||
| addCheck str ( | ||
| s: | ||
| if lib.strings.match "^[a-zA-Z0-9:_\\.-]+$" s == null then | ||
| throw "Name '${toString s}' is not a valid ${of} name. Currently, only alphanumeric characters, dashes, underscores, and dots are allowed." | ||
| else | ||
| true | ||
| ); | ||
| cfg = config.secrets; | ||
|
|
||
| deferredPackage = | ||
| description: | ||
| lib.mkOption { | ||
| inherit description; | ||
| type = functionTo pathInStore; | ||
| example = { pkgs, ... }: pkgs.writeShellScript "example" "echo 'Hi!'"; | ||
| }; | ||
|
|
||
| nullableDeferredPackage = | ||
| description: | ||
| lib.mkOption { | ||
| inherit description; | ||
| type = nullOr (functionTo pathInStore); | ||
| example = { pkgs, ... }: pkgs.writeShellScript "example" "echo 'Hi!'"; | ||
| default = null; | ||
| }; | ||
|
|
||
| storeBackendModule = submodule ( | ||
| { name, ... }: | ||
| { | ||
| options = { | ||
| name = lib.mkOption { | ||
| description = "The name of the backend."; | ||
| type = str; | ||
| default = name; | ||
| defaultText = "Attribute name of the backend"; | ||
| readOnly = true; | ||
| }; | ||
|
|
||
| get = deferredPackage '' | ||
| Given $1=gen_name and $2=file_name, the script retrieves the | ||
| respective secret to $out. | ||
| ''; | ||
|
|
||
| set = deferredPackage '' | ||
| Given $1=gen_name and $2=file_name, the script retrieves the | ||
| respective secret from $in and stores it in the appropriate location. | ||
| ''; | ||
|
|
||
| delete = nullableDeferredPackage '' | ||
| Given $1=gen_name and $2=file_name, the script deletes the respective | ||
| secret if it does exist. | ||
| ''; | ||
|
|
||
| list = deferredPackage '' | ||
| A script that lists all files managed by this backend. Should output | ||
| space-separated or newline-separated pairs of: secret_name | ||
| file_name. | ||
|
|
||
| If the backend supports multiple hosts, then this command should only | ||
| list the secrets owned by the current host. In particular, files | ||
| included in this command's output will be deleted by the | ||
| collect-garbage command, unless they appear in the user's secret | ||
| configuration. | ||
|
|
||
| This script must not perform side effects. | ||
| ''; | ||
|
|
||
| fixup = nullableDeferredPackage '' | ||
| This script will be run on every invocation of the CLI's "generate" | ||
| command. Given $1=file_list in the same format used by `list`, the | ||
| script performs any necessary updates to the secrets' files (e.g. | ||
| rekeying encrypted secrets). This script can perform side effects, | ||
| but must be idempotent. | ||
| ''; | ||
|
|
||
| deploy.remote = nullableDeferredPackage '' | ||
| Deploys every available file to the given machine. The list of files | ||
| to deploy is provided as $1 in the same format used by `list`. Any | ||
| additional information required by the deploy script can be provided | ||
| by the user through environment variables. | ||
| ''; | ||
|
|
||
| deploy.local = nullableDeferredPackage '' | ||
| Deploys every available file to the machine with system root mounted | ||
| at $1=system_root. The list of files to deploy is provided as $2 in | ||
| the same format used by `list`. This is useful for fresh installs | ||
| from environments live live CDs, where the target system is not yet | ||
| up and running (even if nixos-install has successfully completed). | ||
| ''; | ||
|
|
||
| fileModule = lib.mkOption { | ||
| type = deferredModule; | ||
| internal = true; | ||
| default = { }; | ||
| description = '' | ||
| A module to be imported in every | ||
| secrets.store.<name>.files.<name> submodule. Used by backends to | ||
| define the `path` attribute. The module will have the following | ||
| additional arguments passed to it: | ||
| - `secret`, containing the secret the file belongs to | ||
| - `backend`, containing the backend associated with said secret | ||
| ''; | ||
| }; | ||
| }; | ||
| } | ||
| ); | ||
|
|
||
| fileModule = | ||
| { name, backend, ... }: | ||
| { | ||
| imports = [ backend.fileModule ]; | ||
| options = { | ||
| name = lib.mkOption { | ||
| description = "name of the file"; | ||
| type = safeName "file"; | ||
| default = name; | ||
| defaultText = "Attribute name of the file"; | ||
| readOnly = true; | ||
| }; | ||
|
|
||
| path = lib.mkOption { | ||
| description = "Path to the file; usually set by the backend"; | ||
| type = path; | ||
| }; | ||
|
|
||
| deploy = lib.mkOption { | ||
| description = '' | ||
| Files with this flag will be included in the file list passed to | ||
| the `deploy` script. | ||
| ''; | ||
| type = bool; | ||
| default = true; | ||
| }; | ||
| }; | ||
| }; | ||
|
|
||
| secretModule = submodule ( | ||
| { name, config, ... }: | ||
| let | ||
| backend = cfg.backends.store.${config.backend}; | ||
| in | ||
| { | ||
| options = { | ||
| name = lib.mkOption { | ||
| description = '' | ||
| The name of the secret. This name will be used to refer to the | ||
| the secrets from other generators. | ||
| ''; | ||
| type = safeName "secret"; | ||
| default = name; | ||
| defaultText = "Attribute name of the secret"; | ||
| readOnly = true; | ||
| }; | ||
|
|
||
| backend = lib.mkOption { | ||
| type = str; | ||
| description = "The backend responsible for handling this secret."; | ||
| default = cfg.backends.defaults.store; | ||
| }; | ||
|
|
||
| prompts = lib.mkOption { | ||
| description = '' | ||
| A set of prompts the generator will have at its disposal. | ||
| ''; | ||
| default = { }; | ||
| type = attrsOf promptModule; | ||
| }; | ||
|
|
||
| dependencies = lib.mkOption { | ||
| description = '' | ||
| A list of other secrets this generator should be able to read the | ||
| output(s) of. | ||
| ''; | ||
| type = listOf (safeName "secret"); | ||
| default = [ ]; | ||
| }; | ||
|
|
||
| files = lib.mkOption { | ||
| description = '' | ||
| A set of files to store. The generator 'script' is expected to | ||
| produce exactly these files under $out. | ||
| ''; | ||
| default = { }; | ||
| type = attrsOf (submoduleWith { | ||
| modules = [ fileModule ]; | ||
| specialArgs = { | ||
| inherit backend; | ||
| secret = config; | ||
| }; | ||
| }); | ||
| }; | ||
|
|
||
| generate = nullableDeferredPackage '' | ||
| The script to run to generate the files. The script will be run with | ||
| the following environment variables: | ||
| - $in: The directory containing the output values of all declared | ||
| dependencies | ||
| - $out: The output directory to put the generated files | ||
| - $prompts: The directory containing the prompted values as files | ||
| The script should produce the files specified in the 'files' attribute | ||
| under $out. | ||
| ''; | ||
| }; | ||
| } | ||
| ); | ||
|
|
||
| promptBackendModule = submodule ( | ||
| { name, ... }: | ||
| { | ||
| options = { | ||
| name = lib.mkOption { | ||
| description = "The name of the backend."; | ||
| type = str; | ||
| default = name; | ||
| defaultText = "Attribute name of the backend"; | ||
| readOnly = true; | ||
| }; | ||
|
|
||
| ask = deferredPackage '' | ||
| Given $1=secret_name, $2=prompt_name, $3=prompt_type, | ||
| $4=prompt_label, and optionally $5=prompt_description, the script | ||
| runs the prompt by the user, then saves respective value to $out. | ||
|
|
||
| Do note that the given $2=prompt_name is not meant as a prompt label! | ||
| $4=prompt_label should be used for that purpose. Indeed, $1 and $2 | ||
| are only really useful for non-interactive usecases. | ||
| ''; | ||
| }; | ||
| } | ||
| ); | ||
|
|
||
| promptModule = submodule ( | ||
| { name, ... }: | ||
| { | ||
| options = { | ||
| name = lib.mkOption { | ||
| description = "The prompt's name."; | ||
| type = safeName "prompt"; | ||
| default = name; | ||
| defaultText = "Attribute name of the prompt"; | ||
| readOnly = true; | ||
| }; | ||
|
|
||
| label = lib.mkOption { | ||
| description = "The label to attach to the prompt."; | ||
| type = str; | ||
| default = name; | ||
| }; | ||
|
|
||
| description = lib.mkOption { | ||
| description = '' | ||
| An optional longer description of the prompted value. | ||
| ''; | ||
| type = nullOr str; | ||
| default = null; | ||
| example = "SSH private key"; | ||
| }; | ||
|
|
||
| type = lib.mkOption { | ||
| description = '' | ||
| The input type of the prompt. | ||
| The following types are available: | ||
| - hidden: A hidden text (e.g. password) | ||
| - line: A single line of text | ||
| - multiline: A multiline text | ||
| ''; | ||
| type = enum [ | ||
| "hidden" | ||
| "line" | ||
| "multiline" | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, how would a backend handle this in practice? The idea with Still, if
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. openssh private keys are encoded into multiple lines for example. So if you'd want to paste one for whatever reason, it would need that input mode.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Hmm, I see the point regarding |
||
| ]; | ||
| default = "line"; | ||
| }; | ||
|
|
||
| backend = lib.mkOption { | ||
| type = str; | ||
| description = "The backend responsible for handling this prompt."; | ||
| default = cfg.backends.defaults.prompt; | ||
| }; | ||
| }; | ||
| } | ||
| ); | ||
| in | ||
| { | ||
| options.secrets = { | ||
| store = lib.mkOption { | ||
| description = '' | ||
| A set of secrets that are each expected to store a set of files | ||
| under a directory. Generators can produce files using a script, | ||
| possibly referencing values produced by other generators and user | ||
| input. The secrets can also be manually imported from external files | ||
| using the CLI. | ||
| ''; | ||
| default = { }; | ||
| type = attrsOf secretModule; | ||
| }; | ||
|
|
||
| backends.store = lib.mkOption { | ||
| description = '' | ||
| A set of backends that handle storing and retrieving secret files. | ||
| ''; | ||
| default = { }; | ||
| type = attrsOf storeBackendModule; | ||
| }; | ||
|
|
||
| backends.defaults.store = lib.mkOption { | ||
| description = '' | ||
| The default backend to use for secrets that do not specify one. | ||
| ''; | ||
| type = str; | ||
| }; | ||
|
|
||
| backends.prompt = lib.mkOption { | ||
| description = '' | ||
| A set of backends that handle retrieving user inputs. | ||
| ''; | ||
| default = { }; | ||
| type = attrsOf promptBackendModule; | ||
| }; | ||
|
|
||
| backends.defaults.prompt = lib.mkOption { | ||
| description = '' | ||
| The default backend to use for prompts that do not specify one. | ||
| ''; | ||
| type = str; | ||
| }; | ||
| }; | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1 @@ | ||
| This directory contains a bunch of examples of how one might use the `nixos-secrets` module. These are placed here such that the associated nixos-test(s) can reference the example backends via the `modulesPath` (as suggested by Lassulus). |
Uh oh!
There was an error while loading. Please reload this page.