nixos/gitlab: Store secrets in files rather than the store#31358
nixos/gitlab: Store secrets in files rather than the store#31358srhb wants to merge 1 commit intoNixOS:masterfrom
Conversation
|
This at least needs an entry in the release-notes, also cc @fpletz |
There was a problem hiding this comment.
What about other escape codes, should they exist in the string? I don't really know if they will, but it's really not obvious, at least to me. To be fair I'm not really sure what the JWS key is :)
There was a problem hiding this comment.
The JWS key is actually the only one that's reasonably safe to assume doesn't contain a comma ( :( ), because it's base64 encoded...
There was a problem hiding this comment.
Should probably be quoted to prevent whitespace in the password from breaking.
There was a problem hiding this comment.
Actually never mind, this seems to be fine.
There was a problem hiding this comment.
This quoting is needed for databasePassword to tolerate whitespace: DBPASSWORD=$(cat "${cfg.databasePassword}"). The "outer" quoting is unneeded, as mentioned, although it looks a bit scary :-)
There was a problem hiding this comment.
Although while putting spaces in passwords is a sensible thing to do IMHO, anyone who's putting a space in the path to their password should reevaluate their life choices. Again IMHO ;)
There was a problem hiding this comment.
This at least can be trivially fixed, and I'll do so. Thanks!
There was a problem hiding this comment.
All these substitutions will break if any of the keys/passwords contain a comma, right? Perhaps use ${VAR//,/\\,/} rather than $VAR in each case.
There was a problem hiding this comment.
If this seems like an acceptable fix to the substitution issue, I'll do it. I feel like the entire sed approach is wrong, but I don't know of any other reasonable alternatives. :/
There was a problem hiding this comment.
This would break with a password containing a quote, right? Similarly to before, I'd suggest ${DBPASSWORD//'/\\'/}… Although I'm guessing that would still go wrong in other ways 😢 (I wouldn't be surprised if postgres interprets other escape sequences too.) Oh, the joys of substituting text into other languages.
There was a problem hiding this comment.
Also, shouldn't bash refrain from variable substitutions in single quotes anyway?
There was a problem hiding this comment.
Uh, yes. I must have been fooled by the peer authentication.
There was a problem hiding this comment.
Oh, no, this is fine.
$ foo=test; echo "This is fine: '$foo'"
This is fine: 'test'
There was a problem hiding this comment.
Hm, weird. Without the outer quotes:
foo=test; echo This is fine: '$foo'
This is fine: $foo
There was a problem hiding this comment.
Ah, I guess that has the same problem that @dhess pointed out.
There was a problem hiding this comment.
Yes, because it would appear in ps, just for echo rather than psql. You could also remove the -, since psql won't care about the leading whitespace AFAIK.
There was a problem hiding this comment.
Another alternative is psql postgres <<< "CREATE ROLE ${cfg.databaseUsername} WITH LOGIN NOCREATEDB NOCREATEROLE ENCRYPTED PASSWORD '$DBPASSWORD'"
There was a problem hiding this comment.
aren't paths copied into the nix store as well? I stumbled upon this in #29298
There was a problem hiding this comment.
As far as I understand, neither the value of type str or path is copied directly to the store. The problem is that the secretsYml file was. Instead, that file (which is still copied to the store) is merely a template which we copy out substitute into at runtime from files whose path are specified here.
There was a problem hiding this comment.
Actually, I suppose the configuration is stored, but it doesn't matter, since the path, not the contents is what's made world-readable. At best you can now see where the secret is stored, but it should still be secure (if permissions are correct.)
There was a problem hiding this comment.
@srhb good work on making NixOS more secure! With regards to password options having type path see this comment by @domenkozar: #24288 (comment).
|
@lheckemann pointed out that bash is pretty good at substitutions, so let's try that instead. >_> The only outstanding issue is really the createrole where single quotes will cause issues. |
There was a problem hiding this comment.
Does this really prevent store path being created? I think you should do:
nix-repl> "${toString ./timeout.txt}"
"/home/ielectric/timeout.txt"
instead of
nix-repl> "${./timeout.txt}"
"/nix/store/qvggx3asvcz26r9wpclpy67f0k5zryg6-timeout.txt"
There was a problem hiding this comment.
See https://stackoverflow.com/a/43850372/133235 as a reference
There was a problem hiding this comment.
I'm sorry, I don't understand exactly where you think it's going wrong. Can you point me at the exact spot? Here's an example of the rendered preStart-script:
cat > /var/gitlab/state/config/secrets.yml << EOF
production:
secret_key_base: $(cat "/run/keys/secret")
otp_key_base: $(cat "/run/keys/otp")
db_key_base: $(cat "/run/keys/db")
jws_private_key: $(/nix/store/dc4f9mfgbwb0wygwk7qw5b0s0mv7kcml-jq-1.5/bin/jq -Rs . "/run/keys/jws")
EOF
There was a problem hiding this comment.
This is with services.gitlab.secrets.db set to "/run/keys/db" and so on.
There was a problem hiding this comment.
The problem is, someone can specify it as /run/keys/db instead of "/run/keys/db" and it would get copied to the store if you don't call toString first.
There was a problem hiding this comment.
Good point! That's actually a fair argument against using path at all...
There was a problem hiding this comment.
0ba5f49 incorporates your suggestion, thank you. :)
There was a problem hiding this comment.
We could come up with a type like nonStorePath meaning it would validate the value is not in store but is a path.
There was a problem hiding this comment.
I think that would actually be pretty handy!
There was a problem hiding this comment.
@domenkozar Do you still want nonStorePath for this PR?
|
I have one other request for this patch (and thank you for the work!) -- can you add It's rare for a NixOS service to do this, but there is precedent: c.f., |
|
@dhess Like so? |
|
Perfect, thank you! |
|
I believe this looks good after I've fix the merge conflicts. @domenkozar Are you satisfied with the changes? |
a9f9e26 to
2c79f06
Compare
|
Bump? Would be nice to have this merged. |
|
Can we get this merged? :) |
|
@srhb @domenkozar What has to be done to get this (rebased) and merged? It looks pretty good. Is the lack of a |
|
I no longer use gitlab, so I'm not in a position to test, but I can do a blind rebase and someone else can take over from there. |
2c79f06 to
f2fb706
Compare
|
|
||
| secrets.secret = mkOption { | ||
| type = types.str; | ||
| type = types.path; |
There was a problem hiding this comment.
One thing I don't like is how this breaks everybody's config with a mediocre error message (type mismatch). Alternatives are:
- Introduce
{secret,db,...}Fileoptions for path based passwords. I don't like this because it introduces more options. - Introduce a type
types.changed types.str types.pathfor such situations, maybe eventypes.changed "<reason, and remedy>" types.str types.path. I quite like this one.
I don't consider this a blocker for this PR though.
There was a problem hiding this comment.
@infinisil, in nextcloud you have the adminPass and adminPassFile options next to each other. I think that's quite an ok solution.
There was a problem hiding this comment.
As per infinisil's suggestion
| type = types.path; | |
| type = types.changed "The secret is now stored in a file, rather than plain text, to avoid it being world-visible." types.str types.path; |
|
Could you make this work with either a file or the previous in-store-secrets to not break gitlab for anyone currently using it? |
What currently breaks? |
|
I'd like to work on this as I want to host my own gitlab instance, but I'm not very good at nix still. One other problem with having the secret in the config is that you can't upload your config anywhere without "cleaning" it first. It would be great if there was a |
|
This has been implemented |
Motivation for this change
The current gitlab module stores all secrets in the store, rendering them world readable. This PR converts databasePassword and secrets.* to
types.pathand ensures that preStart substitutes them into place. The NixOS test has also been altered to write dummy secrets to the store (but it still times out in qemu, which I've not been able to fix.)There are some things I would like to improve:
types.pathsolely, which could conceivably fail.Things done
build-use-sandboxinnix.confon non-NixOS)nix-shell -p nox --run "nox-review wip"./result/bin/)