meow
Some checks failed
ci/woodpecker/push/build-cache Pipeline failed

This commit is contained in:
Lucy Hochkamp 2025-11-26 11:11:49 +01:00
parent 0eb6953b0d
commit d74a131529
No known key found for this signature in database
14 changed files with 259 additions and 67 deletions

View 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" ];
};
}

View file

@ -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;

View file

@ -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 = [