parent
0eb6953b0d
commit
d74a131529
14 changed files with 259 additions and 67 deletions
88
modules/services/kanidm.nix
Normal file
88
modules/services/kanidm.nix
Normal file
|
|
@ -0,0 +1,88 @@
|
|||
{
|
||||
pkgs,
|
||||
lib,
|
||||
config,
|
||||
...
|
||||
}:
|
||||
let
|
||||
inherit (lib) mkEnableOption mkIf mkOption;
|
||||
inherit (lib.types) str nullOr pathWith;
|
||||
absPath = pathWith {
|
||||
inStore = false;
|
||||
absolute = true;
|
||||
};
|
||||
cfg = config.xyno.services.kanidm;
|
||||
in
|
||||
{
|
||||
options.xyno.services.kanidm.enable = mkEnableOption "enables kanidm";
|
||||
options.xyno.services.kanidm.domain = mkOption {
|
||||
default = "idm.xyno.systems";
|
||||
type = str;
|
||||
};
|
||||
options.xyno.services.kanidm.isReplica = mkEnableOption "replica";
|
||||
options.xyno.services.kanidm.setupTraefik = mkEnableOption "traefik";
|
||||
|
||||
options.xyno.services.kanidm.tls = {
|
||||
keyPem = mkOption {
|
||||
type = nullOr absPath;
|
||||
default = null;
|
||||
description = "autogenerated if unset";
|
||||
};
|
||||
certPem = mkOption {
|
||||
default = "/run/generated/kanidm-tls/cert.pem";
|
||||
type = absPath;
|
||||
};
|
||||
};
|
||||
config = mkIf cfg.enable {
|
||||
services.kanidm = {
|
||||
enableServer = true;
|
||||
enableClient = true;
|
||||
adminPasswordFile = config.sops.secrets."kanidm.password".path;
|
||||
provision = {
|
||||
adminPasswordFile = config.sops.secrets."kanidm.password".path;
|
||||
};
|
||||
serverSettings = {
|
||||
tls_key = if cfg.tls.keyPem != null then cfg.tls.keyPem else "/run/generated/key.pem";
|
||||
tls_chain = cfg.tls.certPem;
|
||||
bindaddress = "127.0.0.3:8443";
|
||||
};
|
||||
};
|
||||
xyno.services.traefik.simpleProxy = mkIf cfg.setupTraefik {
|
||||
host = cfg.domain;
|
||||
internal = "https://127.0.0.3:8443";
|
||||
transport = "kanidm-https";
|
||||
};
|
||||
services.traefik.dynamicConfigOptions.http = mkIf cfg.setupTraefik {
|
||||
serversTransports."kanidm-https" = {
|
||||
serverName = cfg.domain;
|
||||
certificates = [
|
||||
cfg.certPem
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services.generate-kanidm-tls = mkIf (cfg.tls.keyPem == null) {
|
||||
serviceConfig = {
|
||||
User = "root";
|
||||
Group = "kanidm";
|
||||
};
|
||||
wantedBy = [
|
||||
"kanidm.service"
|
||||
"traefik.service"
|
||||
];
|
||||
script = ''
|
||||
mkdir -p /run/generated/kanidm-tls
|
||||
${pkgs.openssl}/bin/openssl req -x509 -newkey ed25519 -noenc -subj "/CN=generated.${cfg.domain}" -addext "subjectAltName=DNS:${cfg.domain}" -keyout /run/generated/key.pem -out /run/generated/cert.pem
|
||||
'';
|
||||
};
|
||||
sops.secrets."kanidm.password" = {
|
||||
sopsFile = ../../instances/${config.networking.hostName}/secrets/kanidm.yaml;
|
||||
};
|
||||
# sops.templates."kanidm.env".content = ''
|
||||
# DESEC_TOKEN=${config.sops.placeholder.desec_token}
|
||||
# DESEC_PROPAGATION_TIMEOUT=1200
|
||||
# '';
|
||||
# sops.templates."kanidm.env".reloadUnits = [ "kanidm.service" ];
|
||||
|
||||
};
|
||||
}
|
||||
|
|
@ -9,21 +9,21 @@ with lib;
|
|||
let
|
||||
cfg = config.xyno.services.monitoring;
|
||||
|
||||
firstInstanceWithPromServer =
|
||||
if cfg.prometheusServer then
|
||||
config.networking.hostName
|
||||
else
|
||||
(builtins.head (
|
||||
attrValues (filterAttrs (n: v: v.config.xyno.services.monitoring.prometheusServer) (otherNodes))
|
||||
)).config.networking.hostName;
|
||||
vmBasicAuthUsername = "xyno-monitoring";
|
||||
# firstInstanceWithPromServer =
|
||||
# if cfg.prometheusServer then
|
||||
# config.networking.hostName
|
||||
# else
|
||||
# (builtins.head (
|
||||
# attrValues (filterAttrs (n: v: v.config.xyno.services.monitoring.prometheusServer) (otherNodes))
|
||||
# )).config.networking.hostName;
|
||||
# vmBasicAuthUsername = "xyno-monitoring";
|
||||
in
|
||||
{
|
||||
options.xyno.services.monitoring.enable =
|
||||
mkEnableOption "enables monitoring (prometheus exporters and stuff)";
|
||||
options.xyno.services.monitoring.remoteWriteUrl = mkOption {
|
||||
type = types.str;
|
||||
default = "http://${firstInstanceWithPromServer}.${config.xyno.services.wireguard.monHostsDomain}:8428/api/v1/write";
|
||||
default = "https://metrics.xyno.systems/api/v1/write";
|
||||
description = "where prometheus metrics should be pushed to";
|
||||
};
|
||||
options.xyno.services.monitoring.prometheusServer = mkOption {
|
||||
|
|
@ -48,8 +48,9 @@ in
|
|||
enabledCollectors = [ "systemd" ];
|
||||
};
|
||||
xyno.services.monitoring.exporters.node = config.services.prometheus.exporters.node.port;
|
||||
# TODO: oauth2 with client per host -> kanidm -> oauth2-proxy -> victoriametrics server
|
||||
services.vmagent = {
|
||||
remoteWrite.url = cfg.remoteWriteUrl;
|
||||
remoteWrite.url = if cfg.prometheusServer then "http://localhost:8428/api/v1/write" else cfg.remoteWriteUrl;
|
||||
remoteWrite.basicAuthUsername = vmBasicAuthUsername;
|
||||
remoteWrite.basicAuthPasswordFile = config.sops.secrets."victoriametrics/basicAuthPassword".path;
|
||||
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ let
|
|||
routers."${router}-robotstxt" = {
|
||||
service = "robotstxt";
|
||||
rule = "Host(`${v.host}`) && Path(`/robots.txt`)";
|
||||
tls.certResolver = "letsencrypt";
|
||||
tls.domains = [
|
||||
{
|
||||
main = certDomain;
|
||||
|
|
@ -30,6 +31,7 @@ let
|
|||
routers.${router} = {
|
||||
inherit service;
|
||||
rule = "Host(`${v.host}`)";
|
||||
tls.certResolver = "letsencrypt";
|
||||
tls.domains = [
|
||||
{
|
||||
main = certDomain;
|
||||
|
|
@ -41,10 +43,11 @@ let
|
|||
loadBalancer.servers = [
|
||||
{ url = v.internal; }
|
||||
];
|
||||
loadBalancer.serverTransport = lib.mkIf (v.transport != null) v.transport;
|
||||
};
|
||||
services.robotstxt = {
|
||||
loadBalancer.servers = [
|
||||
{ url = "http://127.0.0.2"; }
|
||||
{ url = "http://127.0.0.2:8080"; }
|
||||
];
|
||||
};
|
||||
}
|
||||
|
|
@ -77,6 +80,10 @@ in
|
|||
host = lib.mkOption {
|
||||
type = lib.types.str;
|
||||
};
|
||||
transport = lib.mkOption {
|
||||
type = lib.types.nullOr lib.types.anything;
|
||||
default = null;
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
|
@ -86,12 +93,19 @@ in
|
|||
config = lib.mkIf cfg.enable {
|
||||
services.nginx = {
|
||||
enable = lib.mkIf cfg.noBots true;
|
||||
defaultListenAddresses = lib.mkIf cfg.noBots [ "127.0.0.2" ];
|
||||
virtualHosts.localhost.locations."/".root = pkgs.writeTextFile {
|
||||
defaultListen = lib.mkIf cfg.noBots [
|
||||
{
|
||||
addr = "127.0.0.2";
|
||||
port = 8080;
|
||||
}
|
||||
];
|
||||
virtualHosts._.default = true;
|
||||
virtualHosts._.locations."/".root = pkgs.writeTextFile {
|
||||
name = "robots.txt";
|
||||
destination = "/robots.txt";
|
||||
text = ''
|
||||
User-Agent: *
|
||||
Disallow /
|
||||
User-agent: *
|
||||
Disallow: /
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
|
@ -104,7 +118,7 @@ in
|
|||
metrics = lib.mkIf config.xyno.services.monitoring.enable {
|
||||
otlp.http.endpoint = "http://localhost:8429/v1/metrics";
|
||||
};
|
||||
entryponts.web = {
|
||||
entryponits.web = {
|
||||
address = ":80";
|
||||
redirections.entryPoint = {
|
||||
to = "websecure";
|
||||
|
|
@ -112,9 +126,9 @@ in
|
|||
permanent = true;
|
||||
};
|
||||
};
|
||||
entryponts.websecure = {
|
||||
entrypoints.websecure = {
|
||||
address = ":443";
|
||||
tls.certResolver = "letsencrypt";
|
||||
http.tls.certResolver = "letsencrypt";
|
||||
http3 = { };
|
||||
|
||||
};
|
||||
|
|
@ -123,39 +137,40 @@ in
|
|||
email = "ssl@xyno.systems";
|
||||
caServer = "https://acme-v02.api.letsencrypt.org/directory";
|
||||
dnsChallenge = {
|
||||
resolvers = [ "8.8.8.8" "1.1.1.1" ];
|
||||
provider = "desec";
|
||||
};
|
||||
};
|
||||
};
|
||||
dynamicConfigOptions = {
|
||||
http = lib.mkMerge simpleProxyOpts;
|
||||
tls.options.default = {
|
||||
# mozilla modern
|
||||
minVersion = "VersionTLS13";
|
||||
curvePreferences = [
|
||||
"X25519"
|
||||
"CurveP256"
|
||||
"CurveP384"
|
||||
];
|
||||
};
|
||||
tls.options.old = {
|
||||
# mozilla intermediate
|
||||
minVersion = "VersionTLS12";
|
||||
curvePreferences = [
|
||||
"X25519"
|
||||
"CurveP256"
|
||||
"CurveP384"
|
||||
];
|
||||
cipherSuites = [
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
|
||||
"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
|
||||
"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
|
||||
"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
|
||||
"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
|
||||
];
|
||||
# tls.options.default = {
|
||||
# # mozilla modern
|
||||
# minVersion = "VersionTLS13";
|
||||
# curvePreferences = [
|
||||
# "X25519"
|
||||
# "CurveP256"
|
||||
# "CurveP384"
|
||||
# ];
|
||||
# };
|
||||
# tls.options.old = {
|
||||
# # mozilla intermediate
|
||||
# minVersion = "VersionTLS12";
|
||||
# curvePreferences = [
|
||||
# "X25519"
|
||||
# "CurveP256"
|
||||
# "CurveP384"
|
||||
# ];
|
||||
# cipherSuites = [
|
||||
# "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"
|
||||
# "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256"
|
||||
# "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384"
|
||||
# "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384"
|
||||
# "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305"
|
||||
# "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305"
|
||||
# ];
|
||||
|
||||
};
|
||||
# };
|
||||
};
|
||||
};
|
||||
networking.firewall.allowedTCPPorts = [
|
||||
|
|
@ -169,6 +184,7 @@ in
|
|||
sops.templates."traefik.env".content = ''
|
||||
DESEC_TOKEN=${config.sops.placeholder.desec_token}
|
||||
DESEC_PROPAGATION_TIMEOUT=1200
|
||||
LEGO_DISABLE_CNAME_SUPPORT=true
|
||||
'';
|
||||
sops.templates."traefik.env".reloadUnits = [ "traefik.service" ];
|
||||
# services.borgmatic.settings.traefikql_databases = [
|
||||
|
|
|
|||
|
|
@ -21,24 +21,25 @@ in
|
|||
{
|
||||
options.xyno.impermanence = {
|
||||
enable = lib.mkEnableOption "erase all your darlings (they hate you anyways)";
|
||||
files = lib.mkOption { type = lib.types.listOf lib.types.str; };
|
||||
directories = lib.mkOption { type = lib.types.listOf lib.types.str; };
|
||||
files = lib.mkOption { type = lib.types.listOf lib.types.str; default = []; };
|
||||
directories = lib.mkOption { type = lib.types.listOf lib.types.anything; default = [];};
|
||||
user = {
|
||||
files = lib.mkOption { type = lib.types.listOf lib.types.str; };
|
||||
directories = lib.mkOption { type = lib.types.listOf lib.types.str; };
|
||||
files = lib.mkOption { type = lib.types.listOf lib.types.str; default = [];};
|
||||
directories = lib.mkOption { type = lib.types.listOf lib.types.anything; default = [];};
|
||||
};
|
||||
# have a seperate impermanence tree for "cache" files that can just be deleted if wanted
|
||||
cache = {
|
||||
files = lib.mkOption { type = lib.types.listOf lib.types.str; };
|
||||
directories = lib.mkOption { type = lib.types.listOf lib.types.str; };
|
||||
files = lib.mkOption { type = lib.types.listOf lib.types.str; default = [];};
|
||||
directories = lib.mkOption { type = lib.types.listOf lib.types.anything; default = [];};
|
||||
user = {
|
||||
files = lib.mkOption { type = lib.types.listOf lib.types.str; };
|
||||
directories = lib.mkOption { type = lib.types.listOf lib.types.str; };
|
||||
files = lib.mkOption { type = lib.types.listOf lib.types.str; default = [];};
|
||||
directories = lib.mkOption { type = lib.types.listOf lib.types.anything; default = [];};
|
||||
};
|
||||
|
||||
};
|
||||
};
|
||||
config = lib.mkIf cfg.enable {
|
||||
users.mutableUsers = false;
|
||||
xyno.impermanence.files = [
|
||||
"/etc/machine-id" # systemd/zfs unhappy otherwise
|
||||
];
|
||||
|
|
@ -47,6 +48,7 @@ in
|
|||
"/var/lib/systemd/coredump"
|
||||
"/etc/ssh" # host keys
|
||||
"/var/lib/sbctl" # lanzaboote
|
||||
"/var/lib/nixos"
|
||||
|
||||
];
|
||||
xyno.impermanence.user.directories = [
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{lib,...}: with lib;{
|
||||
options.xyno.meta = {
|
||||
sopsKey = mkOption { type = types.text; };
|
||||
sopsKey = mkOption { type = types.str; };
|
||||
};
|
||||
config = {
|
||||
sops.defaultSopsFile = ../../secrets/common.yaml;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue