260 lines
7.8 KiB
Nix
260 lines
7.8 KiB
Nix
{ config, lib, pkgs, ... }@toplevel:
|
|
|
|
with lib;
|
|
let
|
|
cfg = config.services.authentikContainer;
|
|
|
|
hostname = config.instance.hostname;
|
|
|
|
domainName = config.fudo.hosts."${hostname}".domain;
|
|
|
|
hostSecrets = config.fudo.secrets.host-secrets."${hostname}";
|
|
|
|
mkEnvFile = envVars:
|
|
let
|
|
envLines =
|
|
mapAttrsToList (var: val: ''${var}="${toString val}"'') envVars;
|
|
in pkgs.writeText "envFile" (concatStringsSep "\n" envLines);
|
|
|
|
mkUserMap = uid: "${toString uid}:${toString uid}";
|
|
|
|
postgresPasswdFile =
|
|
pkgs.lib.passwd.stablerandom-passwd-file "authentik-postgresql-passwd"
|
|
config.instance.build-seed;
|
|
|
|
authentikSecretKeyFile =
|
|
pkgs.lib.passwd.stablerandom-passwd-file "authentik-secret-key"
|
|
config.instance.build-seed;
|
|
|
|
in {
|
|
options.services.authentikContainer = with types; {
|
|
enable = mkEnableOption "Enable Authentik running in an Arion container.";
|
|
|
|
state-directory = mkOption {
|
|
type = str;
|
|
description = "Directory at which to store server state data.";
|
|
};
|
|
|
|
images = {
|
|
authentik = mkOption { type = str; };
|
|
postgres = mkOption { type = str; };
|
|
redis = mkOption { type = str; };
|
|
};
|
|
|
|
ports = {
|
|
http = mkOption {
|
|
type = port;
|
|
default = 5030;
|
|
};
|
|
https = mkOption {
|
|
type = port;
|
|
default = 5031;
|
|
};
|
|
};
|
|
|
|
smtp = {
|
|
host = mkOption {
|
|
type = str;
|
|
default = "smtp.${domainName}";
|
|
};
|
|
port = mkOption {
|
|
type = port;
|
|
default = 587;
|
|
};
|
|
user = mkOption {
|
|
type = str;
|
|
default = "authentik";
|
|
};
|
|
password-file = mkOption { type = str; };
|
|
from-address = mkOption {
|
|
type = str;
|
|
default =
|
|
"Fudo Authentication <${toplevel.config.services.authentikContainer.smtp.user}@${domainName}>";
|
|
};
|
|
};
|
|
|
|
extraCerts = mkOption {
|
|
type = attrsOf str;
|
|
description = "Map of certificate name to certificate location.";
|
|
default = { };
|
|
};
|
|
|
|
uids = {
|
|
authentik = mkOption {
|
|
type = int;
|
|
default = 721;
|
|
};
|
|
postgres = mkOption {
|
|
type = int;
|
|
default = 722;
|
|
};
|
|
redis = mkOption {
|
|
type = int;
|
|
default = 723;
|
|
};
|
|
};
|
|
};
|
|
|
|
config = mkIf cfg.enable {
|
|
systemd = {
|
|
tmpfiles.rules = [
|
|
"d ${cfg.state-directory}/postgres 0700 authentik-postgres root - -"
|
|
"d ${cfg.state-directory}/redis 0700 authentik-redis root - -"
|
|
"d ${cfg.state-directory}/media 0700 authentik root - -"
|
|
"d ${cfg.state-directory}/templates 0700 authentik root - -"
|
|
"d ${cfg.state-directory}/certs 0700 authentik root - -"
|
|
];
|
|
services = {
|
|
authentik-cert-copy = {
|
|
wantedBy = [ "arion-authentik.service" ];
|
|
before = [ "arion-authentik.service" ];
|
|
script = let
|
|
mkCopyCommand = name: src:
|
|
let target = "${cfg.state-directory}/certs/${name}";
|
|
in ''
|
|
cp -v "${src}" "${target}"
|
|
chown authentik:root "${target}"
|
|
'';
|
|
in concatStringsSep "\n"
|
|
(mapAttrsToList mkCopyCommand cfg.extraCerts);
|
|
};
|
|
arion-authentik = {
|
|
after = [ "network-online.target" "podman.service" ];
|
|
requires = [ "network-online.target" "podman.service" ];
|
|
serviceConfig = {
|
|
Restart = "on-failure";
|
|
RestartSec = 120;
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
users = {
|
|
users = {
|
|
authentik = {
|
|
isSystemUser = true;
|
|
group = "authentik";
|
|
uid = cfg.uids.authentik;
|
|
};
|
|
authentik-postgres = {
|
|
isSystemUser = true;
|
|
group = "authentik";
|
|
uid = cfg.uids.postgres;
|
|
};
|
|
authentik-redis = {
|
|
isSystemUser = true;
|
|
group = "authentik";
|
|
uid = cfg.uids.redis;
|
|
};
|
|
};
|
|
groups.authentik.members =
|
|
[ "authentik" "authentik-postgres" "authentik-redis" ];
|
|
};
|
|
|
|
fudo.secrets.host-secrets."${hostname}" = {
|
|
authentikEnv = {
|
|
source-file = mkEnvFile {
|
|
AUTHENTIK_REDIS__HOST = "redis";
|
|
|
|
AUTHENTIK_POSTGRESQL__HOST = "postgres";
|
|
AUTHENTIK_POSTGRESQL__NAME = "authentik";
|
|
AUTHENTIK_POSTGRESQL__USER = "authentik";
|
|
AUTHENTIK_POSTGRESQL__PASSWORD = readFile postgresPasswdFile;
|
|
|
|
AUTHENTIK_SECRET_KEY = readFile authentikSecretKeyFile;
|
|
|
|
AUTHENTIK_DEFAULT_USER_CHANGE_USERNAME = toString false;
|
|
|
|
AUTHENTIK_EMAIL__HOST = cfg.smtp.host;
|
|
AUTHENTIK_EMAIL__PORT = toString cfg.smtp.port;
|
|
AUTHENTIK_EMAIL__USERNAME = cfg.smtp.user;
|
|
AUTHENTIK_EMAIL__PASSWORD =
|
|
removeSuffix "\n" (readFile cfg.smtp.password-file);
|
|
AUTHENTIK_EMAIL__USE_SSL =
|
|
optionalString (cfg.smtp.port == 465) "TRUE";
|
|
AUTHENTIK_EMAIL__USE_TLS =
|
|
optionalString (cfg.smtp.port == 25 || cfg.smtp.port == 587) "TRUE";
|
|
AUTHENTIK_EMAIL__TIMEOUT = 10;
|
|
AUTHENTIK_EMAIL__FROM = cfg.smtp.from-address;
|
|
};
|
|
target-file = "/run/authentik/authentik.env";
|
|
};
|
|
authentikPostgresEnv = {
|
|
source-file = mkEnvFile {
|
|
POSTGRES_DB = "authentik";
|
|
POSTGRES_USER = "authentik";
|
|
POSTGRES_PASSWORD = readFile postgresPasswdFile;
|
|
};
|
|
target-file = "/run/authentik/postgres.env";
|
|
};
|
|
};
|
|
|
|
virtualisation.arion.projects.authentik.settings = let
|
|
image = { ... }: {
|
|
project.name = "authentik";
|
|
services = {
|
|
postgres.service = {
|
|
image = cfg.images.postgres;
|
|
restart = "always";
|
|
command = "-c 'max_connections=300'";
|
|
volumes =
|
|
[ "${cfg.state-directory}/postgres:/var/lib/postgresql/data" ];
|
|
healthcheck = {
|
|
test = [ "CMD" "pg_isready" "-U" "authentik" "-d" "authentik" ];
|
|
start_period = "20s";
|
|
interval = "30s";
|
|
retries = 5;
|
|
timeout = "3s";
|
|
};
|
|
user = mkUserMap cfg.uids.postgres;
|
|
env_file = [ hostSecrets.authentikPostgresEnv.target-file ];
|
|
};
|
|
redis.service = {
|
|
image = cfg.images.redis;
|
|
restart = "always";
|
|
command = "--save 60 1 --loglevel warning";
|
|
volumes = [ "${cfg.state-directory}/redis:/data" ];
|
|
healthcheck = {
|
|
test = [ "CMD" "redis-cli" "ping" ];
|
|
start_period = "20s";
|
|
interval = "30s";
|
|
retries = 5;
|
|
timeout = "3s";
|
|
};
|
|
user = mkUserMap cfg.uids.redis;
|
|
};
|
|
server.service = {
|
|
image = cfg.images.authentik;
|
|
restart = "always";
|
|
command = "server";
|
|
env_file = [ hostSecrets.authentikEnv.target-file ];
|
|
volumes = [
|
|
"${cfg.state-directory}/media:/media"
|
|
"${cfg.state-directory}/templates:/templates"
|
|
];
|
|
user = mkUserMap cfg.uids.authentik;
|
|
ports = [
|
|
"${toString cfg.ports.http}:9000"
|
|
"${toString cfg.ports.https}:9443"
|
|
];
|
|
depends_on = [ "postgres" "redis" ];
|
|
};
|
|
worker.service = {
|
|
image = cfg.images.authentik;
|
|
restart = "always";
|
|
command = "worker";
|
|
env_file = [ hostSecrets.authentikEnv.target-file ];
|
|
volumes = [
|
|
"${cfg.state-directory}/media:/media"
|
|
"${cfg.state-directory}/certs:/certs"
|
|
"${cfg.state-directory}/templates:/templates"
|
|
];
|
|
user = mkUserMap cfg.uids.authentik;
|
|
depends_on = [ "postgres" "redis" ];
|
|
};
|
|
};
|
|
};
|
|
in { imports = [ image ]; };
|
|
};
|
|
}
|