module: prohibit store-paths for environmentFile

The store is world-readable, so secrets shouldn't end up there in the
first place. On top, `types.path` has the following behavior:

* `toString foo` returns the absolute path
* `${foo}` copies the path silently into the store and returns the
  store-path.

This happens without any real feedback, so this can be caused by an
innocent looking change.

To address this problem, `pathsWith` was introduced into <nixpkgs/lib>
which allows absolute paths represented as string, but rejects things
pointing to the store and path literals which may be copied later on.
This commit is contained in:
Maximilian Bosch 2025-04-08 12:52:35 +02:00
parent b4916a86d4
commit e9bde1ace0
No known key found for this signature in database
3 changed files with 28 additions and 16 deletions

View file

@ -44,6 +44,11 @@ let
;
settingsFormat = pkgs.formats.yaml { };
pathToSecret = types.pathWith {
inStore = false;
absolute = true;
};
in
{
options.services = {
@ -81,7 +86,7 @@ in
};
environmentFile = mkOption {
type = types.nullOr types.path;
type = types.nullOr pathToSecret;
default = null;
example = "/run/secrets/authentik/authentik-env";
description = ''
@ -105,7 +110,7 @@ in
enable = mkEnableOption "authentik LDAP outpost";
environmentFile = mkOption {
type = types.nullOr types.path;
type = types.nullOr pathToSecret;
default = null;
example = "/run/secrets/authentik-ldap/authentik-ldap-env";
description = ''
@ -128,7 +133,7 @@ in
enable = mkEnableOption "authentik RADIUS outpost";
environmentFile = mkOption {
type = types.nullOr types.path;
type = types.nullOr pathToSecret;
default = null;
example = "/run/secrets/authentik-radius/authentik-radius-env";
description = ''

View file

@ -3,12 +3,6 @@
authentik-version,
nixosModules,
}:
let
# use a root-owned EnvironmentFile in production instead (services.authentik.environmentFile)
authentik-env = pkgs.writeText "authentik-test-secret-env" ''
AUTHENTIK_SECRET_KEY=thissecretwillbeinthenixstore
'';
in
pkgs.nixosTest {
name = "authentik";
nodes = {
@ -23,9 +17,18 @@ pkgs.nixosTest {
"${pkgs.path}/nixos/tests/common/x11.nix"
];
# Keep in mind that the secret still ends up in the store and is world-readable because the
# systemd-tmpfiles config lands in the store.
# This is just a trick to not pass a store-path (which is prohibited) to `environmentFile`
# without having to integrate secret managers like agenix or sops-nix into the test.
# Don't do this in production.
systemd.tmpfiles.rules = [
"f /etc/authentik.env 0700 root root - AUTHENTIK_SECRET_KEY=notastorepath"
];
services.authentik = {
enable = true;
environmentFile = authentik-env;
environmentFile = "/etc/authentik.env";
nginx = {
enable = true;
host = "localhost";

View file

@ -18,11 +18,6 @@
*/
let
# use a root-owned EnvironmentFile in production instead (services.authentik.environmentFile)
authentik-env = pkgs.writeText "authentik-test-secret-env" ''
AUTHENTIK_SECRET_KEY=thissecretwillbeinthenixstore
'';
customWelcome = "Welcome to custom authentik";
# creates a new scope using python 3.12 for mkPoetryEnv
@ -61,9 +56,18 @@ pkgs.nixosTest {
"${pkgs.path}/nixos/tests/common/x11.nix"
];
# Keep in mind that the secret still ends up in the store and is world-readable because the
# systemd-tmpfiles config lands in the store.
# This is just a trick to not pass a store-path (which is prohibited) to `environmentFile`
# without having to integrate secret managers like agenix or sops-nix into the test.
# Don't do this in production.
systemd.tmpfiles.rules = [
"f /etc/authentik.env 0700 root root - AUTHENTIK_SECRET_KEY=notastorepath"
];
services.authentik = {
enable = true;
environmentFile = authentik-env;
environmentFile = "/etc/authentik.env";
nginx = {
enable = true;
host = "localhost";