aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLibravatar Alexander Foremny <aforemny@posteo.de>2024-02-23 08:07:11 +0100
committerLibravatar Alexander Foremny <aforemny@posteo.de>2024-02-26 04:36:24 +0100
commit597ec76b7cb1527b1df215548a8f50bddccd8606 (patch)
tree9ea88686f3b15689e222a1d286a6726f6ce59ace
parentd2873fe0f6a117d7157c2a6f204a864f9edeb668 (diff)
apps/authelia: init
-rw-r--r--apps/authelia/appspec.nix33
-rw-r--r--apps/authelia/integration.nix15
-rw-r--r--apps/authelia/module.nix61
-rw-r--r--apps/authelia/secrets.nix5
-rw-r--r--apps/cgit/appspec.nix8
-rw-r--r--apps/static-users/appspec.nix17
-rw-r--r--apps/static-users/capabilities.nix22
-rw-r--r--apps/static-users/secrets.nix7
-rw-r--r--configs/default.nix3
-rw-r--r--modules/fysiweb-capabilities/default.nix17
-rw-r--r--modules/fysiweb-host-modules/default.nix14
-rw-r--r--modules/fysiweb-secrets/default.nix27
m---------secrets0
-rw-r--r--shell.nix1
-rw-r--r--systems/system1/configuration.nix6
15 files changed, 217 insertions, 19 deletions
diff --git a/apps/authelia/appspec.nix b/apps/authelia/appspec.nix
new file mode 100644
index 0000000..60e2695
--- /dev/null
+++ b/apps/authelia/appspec.nix
@@ -0,0 +1,33 @@
+{ appConfig, lib, ... }: {
+ name = "authelia";
+ endOfLife = null;
+ options = {
+ domain = lib.mkOption {
+ type = lib.types.str;
+ };
+ users = lib.mkOption {
+ type = lib.types.attrsOf (lib.types.submodule {
+ options.username = lib.mkOption {
+ type = lib.types.nullOr lib.types.str;
+ default = null;
+ };
+ options.passwordFile = lib.mkOption {
+ type = lib.types.nullOr lib.types.str;
+ default = null;
+ };
+ });
+ };
+ jwtSecret = lib.mkOption {
+ type = lib.types.str;
+ default = "system-secrets/${appConfig.appId}/jwtSecret";
+ };
+ storageEncryptionKey = lib.mkOption {
+ type = lib.types.str;
+ default = "system-secrets/${appConfig.appId}/storageEncryptionKey";
+ };
+ sessionSecret = lib.mkOption {
+ type = lib.types.str;
+ default = "system-secrets/${appConfig.appId}/sessionSecret";
+ };
+ };
+}
diff --git a/apps/authelia/integration.nix b/apps/authelia/integration.nix
new file mode 100644
index 0000000..a7b71a6
--- /dev/null
+++ b/apps/authelia/integration.nix
@@ -0,0 +1,15 @@
+{ appConfig, lib, ... }: lib.mkMerge [
+ {
+ port = 9091;
+ }
+ {
+ container.extraFlags = [
+ "--load-credential jwtSecret:/etc/nixos/${appConfig.jwtSecret}"
+ "--load-credential sessionSecret:/etc/nixos/${appConfig.sessionSecret}"
+ "--load-credential storageEncryptionKey:/etc/nixos/${appConfig.storageEncryptionKey}"
+ ] ++ (lib.mapAttrsToList
+ (username: args:
+ "--load-credential ${args.username}.password:/etc/nixos/${args.passwordFile}")
+ appConfig.users);
+ }
+]
diff --git a/apps/authelia/module.nix b/apps/authelia/module.nix
new file mode 100644
index 0000000..fa4d35d
--- /dev/null
+++ b/apps/authelia/module.nix
@@ -0,0 +1,61 @@
+{ appConfig, lib, pkgs, ... }: lib.mkMerge [
+ # authelia
+ {
+ services.authelia.instances.default.enable = true;
+ services.authelia.instances.default.settings.access_control.default_policy = "one_factor";
+ services.authelia.instances.default.settings.log.format = "text";
+ services.authelia.instances.default.settings.log.level = "info";
+ services.authelia.instances.default.settings.notifier.filesystem.filename = "/var/lib/authelia-default/notifier.txt";
+ services.authelia.instances.default.settings.server.host = "0.0.0.0";
+ services.authelia.instances.default.settings.server.port = 9091;
+ services.authelia.instances.default.settings.session.domain = appConfig.domain;
+ services.authelia.instances.default.settings.storage.local.path = "/var/lib/authelia-default/storage.sqlite3";
+ }
+ # configure secrets
+ {
+ services.authelia.instances.default.secrets.manual = true;
+ systemd.services.authelia-default.environment.AUTHELIA_JWT_SECRET_FILE = "%d/jwtSecret";
+ systemd.services.authelia-default.environment.AUTHELIA_SESSION_SECRET_FILE = "%d/sessionSecret";
+ systemd.services.authelia-default.environment.AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE = "%d/storageEncryptionKey";
+ systemd.services.authelia-default.serviceConfig.LoadCredential = [
+ "jwtSecret:jwtSecret"
+ "sessionSecret:sessionSecret"
+ "storageEncryptionKey:storageEncryptionKey"
+ ];
+ }
+ # configure users
+ {
+ services.authelia.instances.default.settings.authentication_backend.file.path = "/var/lib/authelia-default/users.yaml";
+ services.authelia.instances.default.settings.authentication_backend.file.watch = true;
+
+ systemd.services.authelia-default-users.before = [ "authelia-default.service" ];
+ systemd.services.authelia-default-users.environment.CREDENTIALS_DIRECTORY = "%d";
+ systemd.services.authelia-default-users.serviceConfig.Group = "authelia-default";
+ systemd.services.authelia-default-users.serviceConfig.LoadCredential = lib.mapAttrsToList (username: attrs: "${username}:${username}.password") appConfig.users;
+ systemd.services.authelia-default-users.serviceConfig.User = "authelia-default";
+ systemd.services.authelia-default-users.wantedBy = [ "authelia-default.service" ];
+
+ # TODO password is used on command line
+ #
+ # @topic apps/authelia
+ systemd.services.authelia-default-users.script = "${pkgs.writers.writeDashBin "script" ''
+ set -efu
+ umask 0177
+ PATH=${lib.makeBinPath [ pkgs.authelia pkgs.coreutils pkgs.jq pkgs.json2yaml ]}
+ users=$(
+ echo ${lib.escapeShellArg (lib.generators.toJSON {} (lib.attrValues appConfig.users))} | jq -c .[] | while read -r account; do
+ username=$(echo "$account" | jq -r .username)
+ passwordFile=$(echo "$account" | jq -r .passwordFile)
+ hashedPassword=$(authelia crypto hash generate argon2 --password "$(cat "$CREDENTIALS_DIRECTORY"/"$username")" | cut -d' ' -f2-)
+ jq -cn \
+ --arg username "$username" \
+ --arg password "$hashedPassword" \
+ '{ key: $username, value: { displayname: $username, $password } }'
+ done |
+ jq -s from_entries
+ )
+ jq -cn --argjson users "$users" '{ $users }' |
+ json2yaml > /var/lib/authelia-default/users.yaml
+ ''}/bin/script";
+ }
+]
diff --git a/apps/authelia/secrets.nix b/apps/authelia/secrets.nix
new file mode 100644
index 0000000..1ad5f1a
--- /dev/null
+++ b/apps/authelia/secrets.nix
@@ -0,0 +1,5 @@
+{ appConfig, ... }: [
+ { type = "random-string"; path = appConfig.jwtSecret; }
+ { type = "random-string"; path = appConfig.sessionSecret; }
+ { type = "random-string"; path = appConfig.storageEncryptionKey; }
+]
diff --git a/apps/cgit/appspec.nix b/apps/cgit/appspec.nix
index 243f477..a7744d5 100644
--- a/apps/cgit/appspec.nix
+++ b/apps/cgit/appspec.nix
@@ -25,12 +25,12 @@
default = { };
};
users = lib.mkOption {
- type = lib.types.nullOr (lib.types.attrsOf (lib.types.submodule {
+ type = lib.types.attrsOf (lib.types.submodule {
options.publicKeyFile = lib.mkOption {
- type = lib.types.str;
+ type = lib.types.nullOr lib.types.str;
};
- }));
- default = null;
+ });
+ default = { };
};
};
}
diff --git a/apps/static-users/appspec.nix b/apps/static-users/appspec.nix
index 6ab5c7d..cb55ea7 100644
--- a/apps/static-users/appspec.nix
+++ b/apps/static-users/appspec.nix
@@ -1,12 +1,21 @@
-{ lib, ... }: {
+{ appConfig, lib, ... }: {
description = "static-users";
endOfLife = null;
options.users = lib.mkOption {
- type = lib.types.attrsOf (lib.types.submodule {
+ type = lib.types.attrsOf (lib.types.submodule ({ name, ... }: {
+ options.passwordFile = lib.mkOption {
+ type = lib.types.nullOr lib.types.str;
+ default = "system-secrets/${appConfig.appId}/${appConfig.users.${name}.username}.password";
+ };
options.publicKeyFile = lib.mkOption {
- type = lib.types.path;
+ type = lib.types.nullOr lib.types.path;
+ default = null;
+ };
+ options.username = lib.mkOption {
+ type = lib.types.str;
+ default = name;
};
- });
+ }));
default = { };
};
}
diff --git a/apps/static-users/capabilities.nix b/apps/static-users/capabilities.nix
index de8d1f0..1861888 100644
--- a/apps/static-users/capabilities.nix
+++ b/apps/static-users/capabilities.nix
@@ -1,8 +1,14 @@
-{ appConfig, lib, ... }:
-lib.concatMapAttrs
- (name: attrs: lib.optionalAttrs (attrs ? publicKeyFile) {
- ${name} = {
- inherit (attrs) publicKeyFile;
- };
- })
- appConfig.users
+{ appConfig, config, lib, ... }:
+{
+ password-credentials = lib.concatMapAttrs
+ (name: attrs: lib.optionalAttrs (attrs.passwordFile != null) {
+ ${name} = { inherit (attrs) username passwordFile; };
+ })
+ # TODO appConfig should come from config to have been fully evaluated
+ config.fysiweb-apps.${appConfig.owner}.${appConfig.appName}.${appConfig.appInstanceName}.users;
+ ssh-credentials = lib.concatMapAttrs
+ (name: attrs: lib.optionalAttrs (attrs.publicKeyFile != null) {
+ ${name} = { inherit (attrs) publicKeyFile; };
+ })
+ appConfig.users;
+}
diff --git a/apps/static-users/secrets.nix b/apps/static-users/secrets.nix
new file mode 100644
index 0000000..ef6f35f
--- /dev/null
+++ b/apps/static-users/secrets.nix
@@ -0,0 +1,7 @@
+{ appConfig, lib, ... }:
+lib.mapAttrsToList
+ (username: _: {
+ type = "random-string";
+ path = "system-secrets/${appConfig.appId}/${username}.password";
+ })
+ appConfig.users
diff --git a/configs/default.nix b/configs/default.nix
index c15bd1e..812f365 100644
--- a/configs/default.nix
+++ b/configs/default.nix
@@ -11,8 +11,11 @@
security.acme.acceptTerms = true;
# TODO why do defaults not suffice here?
+
#security.acme.certs.defaults.email = "aforemny@posteo.de";
#security.acme.certs.defaults.webroot = "/var/lib/acme/acme-challenge";
+ security.acme.certs."auth.nomath.org".email = "aforemny@posteo.de";
+ security.acme.certs."auth.nomath.org".webroot = "/var/lib/acme/acme-challenge";
security.acme.certs."code.nomath.org".email = "aforemny@posteo.de";
security.acme.certs."code.nomath.org".webroot = "/var/lib/acme/acme-challenge";
security.acme.certs."nomath.org".email = "aforemny@posteo.de";
diff --git a/modules/fysiweb-capabilities/default.nix b/modules/fysiweb-capabilities/default.nix
index cbb57eb..bf1937b 100644
--- a/modules/fysiweb-capabilities/default.nix
+++ b/modules/fysiweb-capabilities/default.nix
@@ -3,6 +3,17 @@ let
allApps = lib.concatMap lib.attrValues (lib.concatMap lib.attrValues (lib.attrValues config.fysiweb-apps));
in
{
+ options.fysiweb.capabilities.password-credentials = lib.mkOption {
+ type = lib.types.attrsOf (lib.types.attrsOf (lib.types.submodule {
+ options.username = lib.mkOption {
+ type = lib.types.str;
+ };
+ options.passwordFile = lib.mkOption {
+ type = lib.types.str;
+ };
+ }));
+ default = { };
+ };
options.fysiweb.capabilities.ssh-credentials = lib.mkOption {
type = lib.types.attrsOf (lib.types.attrsOf (lib.types.submodule {
options.publicKeyFile = lib.mkOption {
@@ -12,12 +23,12 @@ in
default = { };
};
config = {
- fysiweb.capabilities.ssh-credentials = lib.listToAttrs (lib.concatMap
+ fysiweb.capabilities = lib.attrsets.mergeAttrsList (lib.concatMap
(appConfig:
let path = (toString ../../apps) + "/${appConfig.appName}/capabilities.nix"; in
lib.optionals (lib.pathIsRegularFile path) [
- (lib.nameValuePair appConfig.appId
- (import path { inherit appConfig lib; }))
+ (lib.mapAttrs (_: value: { ${appConfig.appId} = value; })
+ (import path { inherit appConfig config lib; }))
])
allApps);
};
diff --git a/modules/fysiweb-host-modules/default.nix b/modules/fysiweb-host-modules/default.nix
new file mode 100644
index 0000000..d38ba9f
--- /dev/null
+++ b/modules/fysiweb-host-modules/default.nix
@@ -0,0 +1,14 @@
+{ config, lib, ... }:
+let
+ allApps = lib.concatMap lib.attrValues (lib.concatMap lib.attrValues (lib.attrValues config.fysiweb-apps));
+in
+{
+ config = lib.mkMerge (map
+ (appConfig:
+ let path = (toString ../../apps) + "/${appConfig.appName}/host-module.nix"; in
+ lib.optionalAttr (lib.pathIsRegularFile path) { }
+ #(import path { })
+ )
+ #allApps);
+ [ ]);
+}
diff --git a/modules/fysiweb-secrets/default.nix b/modules/fysiweb-secrets/default.nix
new file mode 100644
index 0000000..e494dde
--- /dev/null
+++ b/modules/fysiweb-secrets/default.nix
@@ -0,0 +1,27 @@
+{ config, lib, ... }:
+let
+ allApps = lib.concatMap lib.attrValues (lib.concatMap lib.attrValues (lib.attrValues config.fysiweb-apps));
+in
+{
+ options.fysiweb.secrets = lib.mkOption {
+ type = lib.types.listOf (lib.types.submodule {
+ options = {
+ type = lib.mkOption {
+ type = lib.types.enum [ "random-string" ];
+ };
+ path = lib.mkOption {
+ type = lib.types.str;
+ };
+ };
+ });
+ default = [ ];
+ };
+ config = {
+ fysiweb.secrets = lib.concatMap
+ (appConfig:
+ let path = (toString ../../apps) + "/${appConfig.appName}/secrets.nix"; in
+ lib.optionals (lib.pathIsRegularFile path)
+ (import path { inherit appConfig lib; }))
+ allApps;
+ };
+}
diff --git a/secrets b/secrets
-Subproject 3609101b200901c55227a453ee36bbdfde9a708
+Subproject 1efddacabaf31e5fcb0db4f2797224dc6a9e976
diff --git a/shell.nix b/shell.nix
index 645ccad..b6016b9 100644
--- a/shell.nix
+++ b/shell.nix
@@ -17,6 +17,7 @@
let inherit (pkgs) lib; in
pkgs.mkShell {
buildInputs = [
+ pkgs.authelia
pkgs.fysiweb-cli
pkgs.git
pkgs.niv
diff --git a/systems/system1/configuration.nix b/systems/system1/configuration.nix
index dc9422d..7f42b1a 100644
--- a/systems/system1/configuration.nix
+++ b/systems/system1/configuration.nix
@@ -8,6 +8,7 @@
# TODO auto-load modules
../../modules/abuilder
../../modules/fysiweb-capabilities
+ ../../modules/fysiweb-secrets
];
config = lib.mkMerge [
@@ -19,6 +20,11 @@
fysiweb-apps.public.static-users.public.users.aforemny.publicKeyFile = toString ../../public + "/aforemny.id_rsa.pub";
fysiweb-apps.public.static-users.public.users.kirchner.publicKeyFile = toString ../../public + "/kirchner.id_rsa.pub";
}
+ # enable authelia
+ {
+ fysiweb-apps.public.authelia.public.domain = "auth.nomath.org";
+ fysiweb-apps.public.authelia.public.users = config.fysiweb.capabilities.password-credentials.public-static-users-public;
+ }
# enable static website "nomath.org"
{
fysiweb-apps.public.static-website."nomath-org".domain = "nomath.org";