495 lines
15 KiB
Nix
495 lines
15 KiB
Nix
{
|
|
specialArgs,
|
|
hostBridge,
|
|
hostAddress,
|
|
localAddress,
|
|
httpPort,
|
|
httpsPort,
|
|
forgejoSshPort,
|
|
autoStart ? false,
|
|
}:
|
|
let
|
|
domain = "www.stefanjunker.de";
|
|
in
|
|
{
|
|
inherit specialArgs;
|
|
config =
|
|
{
|
|
config,
|
|
pkgs,
|
|
lib,
|
|
repoFlake,
|
|
nodeFlake,
|
|
system,
|
|
...
|
|
}:
|
|
let
|
|
nixpkgs-kanidm =
|
|
# nodeFlake.inputs.nixpkgs-kanidm
|
|
nodeFlake.inputs.nixpkgs-unstable
|
|
;
|
|
in
|
|
{
|
|
system.stateVersion = "22.05"; # Did you read the comment?
|
|
|
|
disabledModules = [
|
|
"services/misc/forgejo.nix"
|
|
"services/security/kanidm.nix"
|
|
];
|
|
|
|
imports = [
|
|
"${nodeFlake.inputs.nixpkgs-unstable}/nixos/modules/services/misc/forgejo.nix"
|
|
"${nixpkgs-kanidm}/nixos/modules/services/security/kanidm.nix"
|
|
|
|
../profiles/containers/configuration.nix
|
|
|
|
repoFlake.inputs.sops-nix.nixosModules.sops
|
|
];
|
|
|
|
sops.defaultSopsFile = ./webserver_secrets.yaml;
|
|
|
|
networking.firewall.allowedTCPPorts = [
|
|
httpPort
|
|
httpsPort
|
|
forgejoSshPort
|
|
];
|
|
|
|
sops.age.sshKeyPaths = [ "/etc/ssh/ssh_host_ed25519_key" ];
|
|
sops.secrets.hedgedoc_environment_file = {
|
|
sopsFile = ./webserver_secrets.yaml;
|
|
owner = config.users.users.hedgedoc.name;
|
|
};
|
|
|
|
services.caddy = {
|
|
enable = true;
|
|
logFormat = ''
|
|
level ERROR
|
|
'';
|
|
virtualHosts."${domain}" = {
|
|
extraConfig = ''
|
|
redir /hedgedoc* https://hedgedoc.${domain}
|
|
|
|
file_server /*/* {
|
|
browse
|
|
root /var/www/stefanjunker.de/htdocs/caddy
|
|
pass_thru
|
|
}
|
|
|
|
# respond "Hi"
|
|
# respond (not /*/*) "Hi"
|
|
'';
|
|
};
|
|
|
|
virtualHosts."hedgedoc.${domain}" = {
|
|
extraConfig = ''
|
|
reverse_proxy http://[::1]:3000
|
|
'';
|
|
};
|
|
|
|
virtualHosts."authelia.${domain}" = {
|
|
extraConfig = ''
|
|
reverse_proxy http://127.0.0.1:${builtins.toString config.services.authelia.instances.default.settings.server.port}
|
|
'';
|
|
};
|
|
|
|
virtualHosts."lldap.${domain}" = {
|
|
extraConfig = ''
|
|
reverse_proxy http://127.0.0.1:${builtins.toString config.services.lldap.settings.http_port}
|
|
'';
|
|
};
|
|
|
|
virtualHosts."forgejo.${domain}" = {
|
|
extraConfig = ''
|
|
reverse_proxy http://127.0.0.1:${builtins.toString config.services.forgejo.settings.server.HTTP_PORT}
|
|
'';
|
|
};
|
|
|
|
virtualHosts."kanidm.${domain}" = {
|
|
extraConfig = ''
|
|
reverse_proxy https://${builtins.toString config.services.kanidm.serverSettings.bindaddress} {
|
|
transport http {
|
|
tls_server_name ${config.services.kanidm.serverSettings.domain}
|
|
}
|
|
}
|
|
'';
|
|
};
|
|
};
|
|
|
|
services.hedgedoc = {
|
|
enable = true;
|
|
settings = {
|
|
domain = "hedgedoc.${domain}";
|
|
urlPath = "";
|
|
protocolUseSSL = true;
|
|
db = {
|
|
dialect = "sqlite";
|
|
storage = "/var/lib/hedgedoc/db.hedgedoc.sqlite";
|
|
};
|
|
|
|
allowAnonymous = false;
|
|
allowAnonymousEdits = false;
|
|
allowGravatar = false;
|
|
allowFreeURL = false;
|
|
defaultPermission = "private";
|
|
|
|
allowEmailRegister = false;
|
|
email = false;
|
|
|
|
ldap = {
|
|
url = "ldap://127.0.0.1:${builtins.toString config.services.lldap.settings.ldap_port}";
|
|
bindDn = "uid=admin,ou=people,dc=stefanjunker,dc=de";
|
|
# these are set via the `environmentFile`
|
|
# bindCredentials = "$LDAP_ADMIN_PASSWORD";
|
|
searchBase = "ou=people,dc=stefanjunker,dc=de";
|
|
searchFilter = "(&(memberOf=cn=hedgedoc,ou=groups,dc=stefanjunker,dc=de)(uid={{username}}))";
|
|
useridField = "uid";
|
|
};
|
|
|
|
oauth2 =
|
|
let
|
|
originURL = config.services.kanidm.serverSettings.origin;
|
|
in
|
|
{
|
|
providerName = "kanidm (${originURL})";
|
|
|
|
authorizationURL = "${originURL}/ui/oauth2";
|
|
tokenURL = "${originURL}/oauth2/token";
|
|
userProfileURL = "${originURL}/oauth2/openid/hedgedoc/userinfo";
|
|
|
|
scope = "openid email profile";
|
|
# rolesClaim = "roles";
|
|
# accessRole = "role/hedgedoc";
|
|
|
|
userProfileUsernameAttr = "name";
|
|
userProfileDisplayNameAttr = "displayname";
|
|
userProfileEmailAttr = "email";
|
|
|
|
clientID = "hedgedoc";
|
|
# set via the `environmentFile`
|
|
# clientSecret = "$CMD_OAUTH2_CLIENT_SECRET";
|
|
};
|
|
|
|
uploadsPath = "/var/lib/hedgedoc/uploads";
|
|
};
|
|
|
|
environmentFile = config.sops.secrets.hedgedoc_environment_file.path;
|
|
};
|
|
|
|
services.jitsi-meet = {
|
|
enable = false;
|
|
hostName = "meet.${domain}";
|
|
config = {
|
|
prejoinPageEnabled = true;
|
|
};
|
|
caddy.enable = true;
|
|
nginx.enable = false;
|
|
};
|
|
|
|
sops.secrets.authelia_storageEncryptionKey = {
|
|
sopsFile = ./webserver_secrets.yaml;
|
|
owner = config.users.users.authelia-default.name;
|
|
};
|
|
|
|
sops.secrets.authelia_jwtSecret = {
|
|
sopsFile = ./webserver_secrets.yaml;
|
|
owner = config.users.users.authelia-default.name;
|
|
};
|
|
|
|
services.authelia.instances.default =
|
|
let
|
|
baseDir = "/var/lib/authelia-default";
|
|
in
|
|
{
|
|
enable = true;
|
|
secrets.storageEncryptionKeyFile = config.sops.secrets.authelia_storageEncryptionKey.path;
|
|
secrets.jwtSecretFile = config.sops.secrets.authelia_jwtSecret.path;
|
|
settings = {
|
|
theme = "auto";
|
|
default_2fa_method = "totp";
|
|
log.level = "debug";
|
|
|
|
server = {
|
|
disable_healthcheck = true;
|
|
host = "127.0.0.1";
|
|
port = 9091;
|
|
# path = "authelia";
|
|
};
|
|
|
|
storage = {
|
|
local.path = "${baseDir}/authelia.sqlite";
|
|
};
|
|
|
|
authentication_backend = {
|
|
file.path = "${baseDir}/first_factor.yaml";
|
|
file.search.email = true;
|
|
file.search.case_insensitive = false;
|
|
};
|
|
|
|
access_control = {
|
|
default_policy = "one_factor";
|
|
};
|
|
|
|
session.domain = "stefanjunker.de";
|
|
|
|
notifier = {
|
|
disable_startup_check = true;
|
|
filesystem.filename = "${baseDir}/notification.txt";
|
|
};
|
|
};
|
|
};
|
|
|
|
users.groups.lldap = { };
|
|
users.users.lldap = {
|
|
isSystemUser = true;
|
|
group = "lldap";
|
|
};
|
|
|
|
sops.secrets.lldap_jwtSecret = {
|
|
sopsFile = ./webserver_secrets.yaml;
|
|
owner = config.users.users.lldap.name;
|
|
};
|
|
|
|
sops.secrets.lldap_adminPassword = {
|
|
sopsFile = ./webserver_secrets.yaml;
|
|
owner = config.users.users.lldap.name;
|
|
};
|
|
|
|
sops.secrets.lldap_environmentFile = {
|
|
sopsFile = ./webserver_secrets.yaml;
|
|
owner = config.users.users.lldap.name;
|
|
};
|
|
|
|
services.lldap = {
|
|
enable = true;
|
|
environment = {
|
|
LLDAP_JWT_SECRET_FILE = config.sops.secrets.lldap_jwtSecret.path;
|
|
LLDAP_LDAP_USER_PASS_FILE = config.sops.secrets.lldap_adminPassword.path;
|
|
};
|
|
environmentFile = config.sops.secrets.lldap_environmentFile.path;
|
|
|
|
settings = {
|
|
verbose = true;
|
|
|
|
ldap_base_dn = "dc=stefanjunker,dc=de";
|
|
http_url = "https://lldap.${domain}";
|
|
|
|
## Options to configure SMTP parameters, to send password reset emails.
|
|
## To set these options from environment variables, use the following format
|
|
## (example with "password"): LLDAP_SMTP_OPTIONS__PASSWORD
|
|
smtp_options = {
|
|
## Whether to enabled password reset via email, from LLDAP.
|
|
enable_password_reset = true;
|
|
|
|
# port = 465;
|
|
## How the connection is encrypted, either "NONE" (no encryption), "TLS" or "STARTTLS".
|
|
# smtp_encryption = "TLS";
|
|
};
|
|
|
|
# database_url = "sqlite:///var/lib/lldap/users.db?mode=rwc";
|
|
};
|
|
};
|
|
|
|
sops.secrets.FORGEJO_JWT_SECRET = { };
|
|
sops.secrets.FORGEJO_INTERNAL_TOKEN = { };
|
|
sops.secrets.FORGEJO_SECRET_KEY = { };
|
|
|
|
services.forgejo = {
|
|
enable = true;
|
|
package = nodeFlake.inputs.nixpkgs-unstable.legacyPackages.${pkgs.system}.forgejo;
|
|
settings = {
|
|
service.DISABLE_REGISTRATION = true;
|
|
server.HTTP_ADDR = "127.0.0.1";
|
|
server.START_SSH_SERVER = true;
|
|
server.SSH_PORT = forgejoSshPort;
|
|
server.ROOT_URL = "https://forgejo.${domain}";
|
|
server.HTTP_PORT = 3001;
|
|
|
|
# TODO: how do i get a 3072 length SSH key with the yubikey?
|
|
"ssh.minimum_key_sizes".RSA = 2048;
|
|
};
|
|
secrets = {
|
|
oauth2.JWT_SECRET = lib.mkForce config.sops.secrets.FORGEJO_JWT_SECRET.path;
|
|
security.INTERNAL_TOKEN = lib.mkForce config.sops.secrets.FORGEJO_INTERNAL_TOKEN.path;
|
|
security.SECRET_KEY = lib.mkForce config.sops.secrets.FORGEJO_SECRET_KEY.path;
|
|
};
|
|
};
|
|
|
|
systemd.services.lldap.serviceConfig.User = config.users.users.lldap.name;
|
|
systemd.services.lldap.serviceConfig.Group = config.users.groups.lldap.name;
|
|
systemd.services.lldap.serviceConfig.DynamicUser = lib.mkForce false;
|
|
|
|
# combine a path watcher with a service that transfers the certs by caddy to kanidm
|
|
# TODO: had an issue where the certificate in kanidm was expired, despite caddy having a refreshed certificate
|
|
systemd.paths.kanidm-tls-watch = {
|
|
enable = true;
|
|
requiredBy = [ "kanidm.service" ];
|
|
pathConfig = {
|
|
PathChanged = [
|
|
"${config.services.caddy.dataDir}/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/${config.services.kanidm.serverSettings.domain}/${config.services.kanidm.serverSettings.domain}.key"
|
|
"${config.services.caddy.dataDir}/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/${config.services.kanidm.serverSettings.domain}/${config.services.kanidm.serverSettings.domain}.crt"
|
|
];
|
|
Unit = "kanidm-tls-update.service";
|
|
};
|
|
};
|
|
systemd.services.kanidm-tls-update =
|
|
let
|
|
dbDir = builtins.dirOf config.services.kanidm.serverSettings.db_path;
|
|
in
|
|
{
|
|
enable = true;
|
|
requiredBy = [ "kanidm.service" ];
|
|
unitConfig = {
|
|
# ConditionPathExists = [
|
|
# "${config.services.caddy.dataDir}/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/${config.services.kanidm.serverSettings.domain}/${config.services.kanidm.serverSettings.domain}.key"
|
|
# "${config.services.caddy.dataDir}/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/${config.services.kanidm.serverSettings.domain}/${config.services.kanidm.serverSettings.domain}.crt"
|
|
# ];
|
|
};
|
|
serviceConfig.Type = "oneshot";
|
|
script =
|
|
let
|
|
tlsDir = builtins.dirOf config.services.kanidm.serverSettings.tls_key;
|
|
in
|
|
''
|
|
set -xe
|
|
|
|
cat "${config.services.caddy.dataDir}/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/${config.services.kanidm.serverSettings.domain}/${config.services.kanidm.serverSettings.domain}.key" > tls.key
|
|
cat "${config.services.caddy.dataDir}/.local/share/caddy/certificates/acme-v02.api.letsencrypt.org-directory/${config.services.kanidm.serverSettings.domain}/${config.services.kanidm.serverSettings.domain}.crt" > tls.chain
|
|
|
|
chown ${config.systemd.services.kanidm.serviceConfig.User}:${config.systemd.services.kanidm.serviceConfig.Group} tls.{key,chain}
|
|
chmod 400 tls.{key,chain}
|
|
|
|
# create the kanidm directory in case it's missing
|
|
if [[ ! -d ${tlsDir} ]]; then
|
|
mkdir -p ${tlsDir}
|
|
chown -R ${config.systemd.services.kanidm.serviceConfig.User}:${config.systemd.services.kanidm.serviceConfig.Group} ${tlsDir}
|
|
chmod 700 ${tlsDir}
|
|
fi
|
|
|
|
mv tls.key ${config.services.kanidm.serverSettings.tls_key}
|
|
mv tls.chain ${config.services.kanidm.serverSettings.tls_chain}
|
|
|
|
if [[ ! -d ${dbDir} ]]; then
|
|
mkdir -p ${dbDir}
|
|
chown -R ${config.systemd.services.kanidm.serviceConfig.User}:${config.systemd.services.kanidm.serviceConfig.Group} ${dbDir}
|
|
chmod 700 ${dbDir}
|
|
fi
|
|
'';
|
|
};
|
|
|
|
systemd.services.kanidm.serviceConfig =
|
|
let
|
|
dbDir = builtins.dirOf config.services.kanidm.serverSettings.db_path;
|
|
in
|
|
# stateDir = "/var/lib/${config.systemd.services.kanidm.serviceConfig.StateDirectory}";
|
|
{
|
|
# ExecStartPre = ''
|
|
# mkdir -p ${dbDir}
|
|
# '';
|
|
BindPaths = [
|
|
dbDir
|
|
# stateDir
|
|
];
|
|
};
|
|
|
|
services.kanidm =
|
|
let
|
|
dataDir = "/var/lib/kanidm";
|
|
in
|
|
{
|
|
package = nixpkgs-kanidm.legacyPackages.${pkgs.system}.kanidm;
|
|
|
|
enablePam = false;
|
|
enableClient = false;
|
|
|
|
enableServer = true;
|
|
serverSettings = {
|
|
role = "WriteReplica";
|
|
log_level = "debug";
|
|
|
|
domain = "kanidm.${domain}";
|
|
origin = "https://kanidm.${domain}";
|
|
|
|
|
|
bindaddress = "127.0.0.1:8444";
|
|
|
|
# don't expose ldap
|
|
# ldapbindaddress = "[::1]:6636";
|
|
|
|
tls_key = "${dataDir}/tls/tls.key";
|
|
tls_chain = "${dataDir}/tls/tls.chain";
|
|
|
|
online_backup = {
|
|
schedule = "00 06 * * *";
|
|
};
|
|
};
|
|
};
|
|
};
|
|
|
|
inherit autoStart;
|
|
|
|
bindMounts = {
|
|
# FIXME/REMINDER: this is used so that the container can decrypt the secrets that are deployed to the host
|
|
"/etc/ssh/ssh_host_ed25519_key".isReadOnly = true;
|
|
"/etc/ssh/ssh_host_ed25519_key.pub".isReadOnly = true;
|
|
|
|
"/var/www" = {
|
|
hostPath = "/var/lib/container-volumes/webserver/var-www";
|
|
isReadOnly = false;
|
|
};
|
|
|
|
"/var/lib/mysql" = {
|
|
hostPath = "/var/lib/container-volumes/webserver/var-lib-mysql";
|
|
isReadOnly = false;
|
|
};
|
|
|
|
"/var/lib/hedgedoc" = {
|
|
hostPath = "/var/lib/container-volumes/webserver/var-lib-hedgedoc";
|
|
isReadOnly = false;
|
|
};
|
|
|
|
"/var/lib/authelia-default" = {
|
|
hostPath = "/var/lib/container-volumes/webserver/var-lib-authelia-default";
|
|
isReadOnly = false;
|
|
};
|
|
|
|
"/var/lib/lldap" = {
|
|
hostPath = "/var/lib/container-volumes/webserver/var-lib-lldap";
|
|
isReadOnly = false;
|
|
};
|
|
|
|
"/var/lib/forgejo" = {
|
|
hostPath = "/var/lib/container-volumes/webserver/var-lib-forgejo";
|
|
isReadOnly = false;
|
|
};
|
|
|
|
"/var/lib/kanidm" = {
|
|
hostPath = "/var/lib/container-volumes/webserver/var-lib-kanidm";
|
|
isReadOnly = false;
|
|
};
|
|
};
|
|
|
|
privateNetwork = true;
|
|
forwardPorts = [
|
|
{
|
|
# http
|
|
containerPort = 80;
|
|
hostPort = httpPort;
|
|
protocol = "tcp";
|
|
}
|
|
{
|
|
# https
|
|
containerPort = 443;
|
|
hostPort = httpsPort;
|
|
protocol = "tcp";
|
|
}
|
|
|
|
{
|
|
# forgejo ssh
|
|
containerPort = forgejoSshPort;
|
|
hostPort = forgejoSshPort;
|
|
protocol = "tcp";
|
|
}
|
|
];
|
|
|
|
inherit hostBridge hostAddress localAddress;
|
|
}
|