Compare commits
No commits in common. "d97a085af50b913110a516aca886763eab393702" and "4c6bc314763e11e4107ebe627b1908d606c4b3c8" have entirely different histories.
d97a085af5
...
4c6bc31476
12 changed files with 161 additions and 541 deletions
50
flake.lock
generated
50
flake.lock
generated
|
|
@ -30,11 +30,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1774779250,
|
||||
"narHash": "sha256-n7zH1dk+mcUt59i5FDSF3q6G398NzKVt/E/lM2DZY8A=",
|
||||
"lastModified": 1772058043,
|
||||
"narHash": "sha256-m1cmQgb6tBcHkndKZ8BSsw6PRNJMG89FZwoYVOuKi34=",
|
||||
"owner": "AdnanHodzic",
|
||||
"repo": "auto-cpufreq",
|
||||
"rev": "a620b9971963730978a0e5fc9d92bf613218d21e",
|
||||
"rev": "5d600d710bb2aa331e1a4370e08476bcdea1cab5",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -50,11 +50,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1776613567,
|
||||
"narHash": "sha256-gC9Cp5ibBmGD5awCA9z7xy6MW6iJufhazTYJOiGlCUI=",
|
||||
"lastModified": 1773889306,
|
||||
"narHash": "sha256-PAqwnsBSI9SVC2QugvQ3xeYCB0otOwCacB1ueQj2tgw=",
|
||||
"owner": "nix-community",
|
||||
"repo": "disko",
|
||||
"rev": "32f4236bfc141ae930b5ba2fb604f561fed5219d",
|
||||
"rev": "5ad85c82cc52264f4beddc934ba57f3789f28347",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -144,11 +144,11 @@
|
|||
]
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1775425411,
|
||||
"narHash": "sha256-KY6HsebJHEe5nHOWP7ur09mb0drGxYSzE3rQxy62rJo=",
|
||||
"lastModified": 1774559029,
|
||||
"narHash": "sha256-deix7yg3j6AhjMPnFDCmWB3f83LsajaaULP5HH2j34k=",
|
||||
"owner": "nix-community",
|
||||
"repo": "home-manager",
|
||||
"rev": "0d02ec1d0a05f88ef9e74b516842900c41f0f2fe",
|
||||
"rev": "a0bb0d11514f92b639514220114ac8063c72d0a3",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -181,11 +181,11 @@
|
|||
},
|
||||
"nixos-hardware": {
|
||||
"locked": {
|
||||
"lastModified": 1776983936,
|
||||
"narHash": "sha256-ZOQyNqSvJ8UdrrqU1p7vaFcdL53idK+LOM8oRWEWh6o=",
|
||||
"lastModified": 1774465523,
|
||||
"narHash": "sha256-4v7HPm63Q90nNn4fgkgKsjW1AH2Klw7XzPtHJr562nM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixos-hardware",
|
||||
"rev": "2096f3f411ce46e88a79ae4eafcfc9df8ed41c61",
|
||||
"rev": "de895be946ad1d8aafa0bb6dfc7e7e0e9e466a29",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -197,11 +197,11 @@
|
|||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1776734388,
|
||||
"narHash": "sha256-vl3dkhlE5gzsItuHoEMVe+DlonsK+0836LIRDnm6MXQ=",
|
||||
"lastModified": 1774388614,
|
||||
"narHash": "sha256-tFwzTI0DdDzovdE9+Ras6CUss0yn8P9XV4Ja6RjA+nU=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "10e7ad5bbcb421fe07e3a4ad53a634b0cd57ffac",
|
||||
"rev": "1073dad219cb244572b74da2b20c7fe39cb3fa9e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -261,11 +261,11 @@
|
|||
},
|
||||
"nixpkgs-unstable": {
|
||||
"locked": {
|
||||
"lastModified": 1776877367,
|
||||
"narHash": "sha256-EHq1/OX139R1RvBzOJ0aMRT3xnWyqtHBRUBuO1gFzjI=",
|
||||
"lastModified": 1774386573,
|
||||
"narHash": "sha256-4hAV26quOxdC6iyG7kYaZcM3VOskcPUrdCQd/nx8obc=",
|
||||
"owner": "nixos",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "0726a0ecb6d4e08f6adced58726b95db924cef57",
|
||||
"rev": "46db2e09e1d3f113a13c0d7b81e2f221c63b8ce9",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -307,11 +307,11 @@
|
|||
"utils": "utils"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1775228763,
|
||||
"narHash": "sha256-8fKOEOouCaPZLBTdWPS+uU0bxsPp1OmfloDNoNSiu8w=",
|
||||
"lastModified": 1769870714,
|
||||
"narHash": "sha256-wjwCj70iiFXoAasQto+3jTaA4wCMOAs/rdX+nsmtBrQ=",
|
||||
"owner": "SaumonNet",
|
||||
"repo": "proxmox-nixos",
|
||||
"rev": "e803cb839e5e5207fa37d92bc6ac7290f4dba633",
|
||||
"rev": "c1f79f104930347a0b84abbca0d42884063a8c09",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
@ -338,11 +338,11 @@
|
|||
"secrets": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1777076192,
|
||||
"narHash": "sha256-N7n2OPN2IRWwL73Cr6mc5nNhucHmMeFas9hQ/NF0bFg=",
|
||||
"lastModified": 1774571252,
|
||||
"narHash": "sha256-NU/vfItTMSjaRTXe0UDzbWR8UnhkBUFU47OpqEpxKb4=",
|
||||
"ref": "refs/heads/main",
|
||||
"rev": "34ff1c4b0460a2e103a8fec183f53f274dc123ed",
|
||||
"revCount": 32,
|
||||
"rev": "7965907ae885d77acb3c4ecc11cee096a12af868",
|
||||
"revCount": 25,
|
||||
"type": "git",
|
||||
"url": "ssh://git@git.jfreudenberger.de/JuliusFreudenberger/nix-private.git"
|
||||
},
|
||||
|
|
|
|||
18
flake.nix
18
flake.nix
|
|
@ -167,24 +167,6 @@
|
|||
];
|
||||
};
|
||||
|
||||
srv03 = nixpkgs.lib.nixosSystem rec {
|
||||
system = "x86_64-linux";
|
||||
|
||||
specialArgs = {
|
||||
inherit inputs outputs;
|
||||
pkgs-unstable = import nixpkgs-unstable {
|
||||
inherit system;
|
||||
config.allowUnfree = true;
|
||||
};
|
||||
};
|
||||
|
||||
modules = [
|
||||
disko.nixosModules.disko
|
||||
agenix.nixosModules.default
|
||||
./hosts/srv03
|
||||
];
|
||||
};
|
||||
|
||||
};
|
||||
|
||||
homeConfigurations = {
|
||||
|
|
|
|||
|
|
@ -1,91 +0,0 @@
|
|||
{ inputs, outputs, config, lib, pkgs, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[
|
||||
./secrets.nix
|
||||
|
||||
../../modules/disko/legacy-full-ext4-swap.nix
|
||||
|
||||
../../users/julius/nixos-server.nix
|
||||
../../modules/nix.nix
|
||||
../../modules/locale.nix
|
||||
../../modules/server-cli.nix
|
||||
../../modules/sshd.nix
|
||||
../../modules/qemu-guest.nix
|
||||
../../modules/docker.nix
|
||||
../../modules/traefik.nix
|
||||
../../modules/pocket-id.nix
|
||||
../../modules/auto-upgrade.nix
|
||||
"${inputs.secrets}/modules/opkssh.nix"
|
||||
# Include the results of the hardware scan.
|
||||
./hardware-configuration.nix
|
||||
];
|
||||
|
||||
#services.openssh.openFirewall = false;
|
||||
|
||||
services = {
|
||||
traefik-docker = {
|
||||
enable = true;
|
||||
dashboardUrl = "traefik.netbird.jfreudenberger.de";
|
||||
dnsChallengeProvider = "inwx";
|
||||
dnsSecrets = [
|
||||
config.age.secrets.inwx
|
||||
];
|
||||
};
|
||||
|
||||
pocket-id-docker.enable = true;
|
||||
pocket-id = {
|
||||
settings = {
|
||||
APP_URL = "https://login.jfreudenberger.de";
|
||||
TRUST_PROXY = true;
|
||||
};
|
||||
environmentFile = config.age.secrets.pocket-id.path;
|
||||
};
|
||||
};
|
||||
|
||||
systemd.network = {
|
||||
enable = true;
|
||||
networks."10-wan" = {
|
||||
matchConfig.Name = "enp1s0";
|
||||
networkConfig.DHCP = "no";
|
||||
address = [
|
||||
"46.224.47.24/32"
|
||||
"2a01:4f8:c013:bf68::1/64"
|
||||
];
|
||||
routes = [
|
||||
{ Gateway = "172.31.1.1"; GatewayOnLink = true; }
|
||||
{ Gateway = "fe80::1"; GatewayOnLink = true; }
|
||||
];
|
||||
dns = [ "9.9.9.9" ];
|
||||
};
|
||||
};
|
||||
|
||||
boot = {
|
||||
tmp.cleanOnBoot = true;
|
||||
growPartition = true;
|
||||
kernelParams = [ "console=ttyS0" ];
|
||||
loader = {
|
||||
grub.enable = true;
|
||||
};
|
||||
};
|
||||
|
||||
# Disable classic networking configuration
|
||||
networking.useDHCP = lib.mkForce false;
|
||||
|
||||
networking.hostName = "srv03"; # Define your hostname.
|
||||
|
||||
# This option defines the first version of NixOS you have installed on this particular machine,
|
||||
# and is used to maintain compatibility with application data (e.g. databases) created on older NixOS versions.
|
||||
# Most users should NEVER change this value after the initial install, for any reason,
|
||||
# even if you've upgraded your system to a new NixOS release.
|
||||
# This value does NOT affect the Nixpkgs version your packages and OS are pulled from,
|
||||
# so changing it will NOT upgrade your system - see https://nixos.org/manual/nixos/stable/#sec-upgrading for how
|
||||
# to actually do that.
|
||||
# This value being lower than the current NixOS release does NOT mean your system is
|
||||
# out of date, out of support, or vulnerable.
|
||||
# Do NOT change this value unless you have manually inspected all the changes it would make to your configuration,
|
||||
# and migrated your data accordingly.
|
||||
# For more information, see `man configuration.nix` or https://nixos.org/manual/nixos/stable/options#opt-system.stateVersion .
|
||||
system.stateVersion = "25.05"; # Did you read the comment?
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
# Do not modify this file! It was generated by ‘nixos-generate-config’
|
||||
# and may be overwritten by future invocations. Please make changes
|
||||
# to /etc/nixos/configuration.nix instead.
|
||||
{ config, lib, pkgs, modulesPath, ... }:
|
||||
|
||||
{
|
||||
imports =
|
||||
[ (modulesPath + "/profiles/qemu-guest.nix")
|
||||
];
|
||||
|
||||
boot.initrd.availableKernelModules = [ "ahci" "xhci_pci" "virtio_pci" "virtio_scsi" "sd_mod" "sr_mod" ];
|
||||
boot.initrd.kernelModules = [ ];
|
||||
boot.kernelModules = [ "kvm-intel" ];
|
||||
boot.extraModulePackages = [ ];
|
||||
|
||||
# Enables DHCP on each ethernet and wireless interface. In case of scripted networking
|
||||
# (the default) this is the recommended approach. When using systemd-networkd it's
|
||||
# still possible to use this option, but it's recommended to use it in conjunction
|
||||
# with explicit per-interface declarations with `networking.interfaces.<interface>.useDHCP`.
|
||||
networking.useDHCP = lib.mkDefault true;
|
||||
# networking.interfaces.enp1s0.useDHCP = lib.mkDefault true;
|
||||
|
||||
nixpkgs.hostPlatform = lib.mkDefault "x86_64-linux";
|
||||
}
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
{ inputs, ... }:
|
||||
{
|
||||
age.secrets = {
|
||||
inwx.file = "${inputs.secrets}/secrets/dns-management/inwx";
|
||||
pocket-id.file = "${inputs.secrets}/secrets/srv03/pocket-id";
|
||||
};
|
||||
}
|
||||
|
|
@ -7,7 +7,6 @@
|
|||
remmina
|
||||
|
||||
teleport_17.client
|
||||
opkssh
|
||||
];
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,45 +0,0 @@
|
|||
{
|
||||
disko.devices = {
|
||||
disk = {
|
||||
sda = {
|
||||
type = "disk";
|
||||
device = "/dev/sda";
|
||||
content = {
|
||||
type = "gpt";
|
||||
partitions = {
|
||||
MBR = {
|
||||
type = "EF02"; # for grub MBR
|
||||
size = "1M";
|
||||
priority = 1; # Needs to be first partition
|
||||
};
|
||||
ESP = {
|
||||
size = "1G";
|
||||
type = "EF00";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "vfat";
|
||||
mountpoint = "/boot";
|
||||
};
|
||||
};
|
||||
root = {
|
||||
end = "-1G";
|
||||
content = {
|
||||
type = "filesystem";
|
||||
format = "ext4";
|
||||
mountpoint = "/";
|
||||
};
|
||||
};
|
||||
encryptedSwap = {
|
||||
size = "100%";
|
||||
content = {
|
||||
type = "swap";
|
||||
randomEncryption = true;
|
||||
priority = 100;
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
}
|
||||
|
|
@ -38,7 +38,7 @@ in {
|
|||
};
|
||||
extraOptions = [
|
||||
''--mount=type=volume,source=dockhand-data,target=/app/data,volume-driver=local''
|
||||
''--group-add=${config.ids.gids.docker}''
|
||||
''--group-add=131'' # docker group
|
||||
];
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
...
|
||||
}: {
|
||||
|
||||
boot.kernelPackages = pkgs.linuxKernel.packages.linux_zen;
|
||||
boot.kernelPackages = pkgs.linuxPackages_latest;
|
||||
|
||||
services.logind.settings.Login = {
|
||||
HandleLidSwitch= "suspend-then-hibernate";
|
||||
|
|
|
|||
|
|
@ -1,58 +0,0 @@
|
|||
{
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
|
||||
cfg = config.services.pocket-id-docker;
|
||||
pocketidCfg = config.services.pocket-id;
|
||||
version = "2.6.2";
|
||||
|
||||
in {
|
||||
|
||||
options.services.pocket-id-docker = {
|
||||
enable = lib.mkEnableOption "Pocket ID server hosted as OCI container";
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
virtualisation.oci-containers.containers = {
|
||||
pocket-id = {
|
||||
image = "ghcr.io/pocket-id/pocket-id:v${version}";
|
||||
autoStart = true;
|
||||
networks = [
|
||||
"webproxy"
|
||||
];
|
||||
environment = {
|
||||
APP_URL = pocketidCfg.settings.APP_URL;
|
||||
TRUST_PROXY = lib.boolToString pocketidCfg.settings.TRUST_PROXY;
|
||||
ANALYTICS_DISABLED = lib.boolToString pocketidCfg.settings.ANALYTICS_DISABLED;
|
||||
};
|
||||
environmentFiles = [ pocketidCfg.environmentFile ];
|
||||
extraOptions = [
|
||||
''--mount=type=volume,source=data,target=/app/data,volume-driver=local''
|
||||
"--health-cmd=/app/pocket-id healthcheck"
|
||||
"--health-interval=1m30s"
|
||||
"--health-timeout=5s"
|
||||
"--health-retries=2"
|
||||
"--health-start-period=10s"
|
||||
];
|
||||
labels = {
|
||||
"traefik.enable" = "true";
|
||||
"traefik.http.routers.pocket-id.rule" = "Host(`${lib.removePrefix "https://" pocketidCfg.settings.APP_URL}`)";
|
||||
"traefik.http.routers.pocket-id.entrypoints" = "websecure";
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services."docker-pocket-id" = {
|
||||
after = [
|
||||
"docker-traefik.service"
|
||||
];
|
||||
requires = [
|
||||
"docker-traefik.service"
|
||||
];
|
||||
};
|
||||
|
||||
};
|
||||
}
|
||||
|
|
@ -1,221 +0,0 @@
|
|||
{
|
||||
pkgs,
|
||||
config,
|
||||
lib,
|
||||
...
|
||||
}:
|
||||
let
|
||||
|
||||
cfg = config.services.traefik-docker;
|
||||
|
||||
mapOidcClientNameToEnv = stringToReplace: lib.replaceString "-" "_" (lib.toUpper stringToReplace);
|
||||
|
||||
traefik-mtls-config = (pkgs.formats.yaml { }).generate "traefik-mtls-config" {
|
||||
tls.options.default.clientAuth = {
|
||||
caFiles = "caFiles/root_ca.crt";
|
||||
clientAuthType = "VerifyClientCertIfGiven";
|
||||
};
|
||||
};
|
||||
|
||||
in {
|
||||
|
||||
options.services.traefik-docker = {
|
||||
enable = lib.mkEnableOption "traefik web server hosted as OCI container";
|
||||
dashboardUrl = lib.mkOption {
|
||||
description = "External URL the traefik dashboard will be reachable from, without protocol";
|
||||
type = lib.types.str;
|
||||
};
|
||||
dnsSecrets = lib.mkOption {
|
||||
description = "Secrets for DNS providers.";
|
||||
type = lib.types.listOf lib.types.anything;
|
||||
};
|
||||
mTLSCaCertSecret = lib.mkOption {
|
||||
description = "Agenix secret containing the CA file to verify client certificates against.";
|
||||
};
|
||||
oidcAuthProviderUrl = lib.mkOption {
|
||||
description = "Provider URL of OIDC auth provider.";
|
||||
type = lib.types.str;
|
||||
};
|
||||
oidcClients = lib.mkOption {
|
||||
example = ''
|
||||
immich = {
|
||||
scopes = [
|
||||
"openid"
|
||||
"email"
|
||||
"profile"
|
||||
];
|
||||
enableBypassUsingClientCertificate = true;
|
||||
usePkce = true;
|
||||
};
|
||||
'';
|
||||
description = "Attribute set of OIDC clients with their configurations.";
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
secret = lib.mkOption {
|
||||
description = ''Agenix secret containing the following needed environment variables in dotenv notation:
|
||||
- <clientName>_OIDC_AUTH_SECRET
|
||||
- <clientName>_OIDC_AUTH_PROVIDER_CLIENT_ID
|
||||
- <clientName>_OIDC_CLIENT_SECRET
|
||||
'';
|
||||
};
|
||||
scopes = lib.mkOption {
|
||||
default = [ "openid" ];
|
||||
example = [ "openid" "email" "profile" "groups" ];
|
||||
description = "OIDC scopes to request from auth provider.";
|
||||
type = lib.types.listOf lib.types.str;
|
||||
};
|
||||
usePkce = lib.mkOption {
|
||||
default = true;
|
||||
description = "Whether to enable PKCE for this provider.";
|
||||
type = lib.types.bool;
|
||||
};
|
||||
enableBypassUsingClientCertificate = lib.mkOption {
|
||||
default = false;
|
||||
description = "Whether to allow bypassing OIDC protection when a verified client certificate is presented.";
|
||||
type = lib.types.bool;
|
||||
};
|
||||
useClaimsFromUserInfo = lib.mkOption {
|
||||
default = false;
|
||||
description = "When enabled, an additional request to the provider's userinfo_endpoint is made to validate the token and to retrieve additional claims. The userinfo claims are merged directly into the token claims, with userinfo values overriding token values for non-security-critical claims.";
|
||||
type = lib.types.bool;
|
||||
};
|
||||
headers = lib.mkOption {
|
||||
default = [];
|
||||
description = "Headers to be added to the upstream request. Templating is possible. Documentation can be found here: https://traefik-oidc-auth.sevensolutions.cc/docs/getting-started/middleware-configuration";
|
||||
type = lib.types.listOf (lib.types.submodule {
|
||||
options = {
|
||||
Name = lib.mkOption {
|
||||
description = "The name of the header which should be added to the upstream request.";
|
||||
type = lib.types.str;
|
||||
};
|
||||
Value = lib.mkOption {
|
||||
description = "The value of the header, which can use Go-Templates.";
|
||||
type = lib.types.str;
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
virtualisation.oci-containers.containers = {
|
||||
traefik = {
|
||||
image = "traefik:v3.6.6";
|
||||
cmd = [
|
||||
"--providers.docker=true"
|
||||
"--providers.docker.exposedByDefault=false"
|
||||
"--providers.docker.network=traefik"
|
||||
"--providers.file.directory=/dynamic-config"
|
||||
"--log.level=INFO"
|
||||
"--api=true"
|
||||
"--ping=true"
|
||||
"--entrypoints.web.address=:80"
|
||||
"--entrypoints.websecure.address=:443"
|
||||
"--entrypoints.websecure.transport.respondingTimeouts.readTimeout=600s"
|
||||
"--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=600s"
|
||||
"--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=600s"
|
||||
"--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
||||
"--entrypoints.websecure.asDefault=true"
|
||||
"--entrypoints.websecure.http.middlewares=strip-mtls-headers@docker,pass-tls-client-cert@docker"
|
||||
"--entrypoints.websecure.http.tls.certresolver=letsencrypt"
|
||||
"--certificatesresolvers.letsencrypt.acme.storage=/certs/acme.json"
|
||||
"--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
|
||||
"--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=netcup"
|
||||
"--experimental.plugins.traefik-oidc-auth.modulename=github.com/sevensolutions/traefik-oidc-auth"
|
||||
"--experimental.plugins.traefik-oidc-auth.version=v0.17.0"
|
||||
];
|
||||
autoStart = true;
|
||||
ports = [
|
||||
"80:80"
|
||||
"443:443"
|
||||
];
|
||||
networks = [
|
||||
"traefik"
|
||||
];
|
||||
environment = {
|
||||
OIDC_AUTH_PROVIDER_URL = cfg.oidcAuthProviderUrl;
|
||||
};
|
||||
environmentFiles = lib.forEach cfg.dnsSecrets (secret: secret.path) ++ (lib.mapAttrsToList (oidcClientName: oidcClientConfig: oidcClientConfig.secret.path) cfg.oidcClients);
|
||||
labels = {
|
||||
"traefik.enable" = "true";
|
||||
"traefik.http.routers.dashboard.rule" = "Host(`${cfg.dashboardUrl}`)";
|
||||
"traefik.http.routers.dashboard.service" = "dashboard@internal";
|
||||
"traefik.http.routers.dashboard.middlewares" = "traefik-dashboard-oidc-auth@file";
|
||||
"traefik.http.routers.api.rule" = "Host(`${cfg.dashboardUrl}`) && (PathPrefix(`/api`) || PathPrefix(`/oidc/callback`))";
|
||||
"traefik.http.routers.api.service" = "api@internal";
|
||||
"traefik.http.routers.api.middlewares" = "traefik-dashboard-oidc-auth@file";
|
||||
"traefik.http.middlewares.strip-mtls-headers.headers.customrequestheaders.X-Forwarded-Tls-Client-Cert" = "";
|
||||
"traefik.http.middlewares.pass-tls-client-cert.passtlsclientcert.pem" = "true";
|
||||
};
|
||||
volumes = let
|
||||
oidc-config = lib.mapAttrs' (
|
||||
oidcClientName: oidcClientConfig:
|
||||
lib.nameValuePair "${oidcClientName}-oidc-auth" {
|
||||
plugin.traefik-oidc-auth = {
|
||||
LogLevel = "INFO";
|
||||
Secret = ''{{ env "${mapOidcClientNameToEnv oidcClientName}_OIDC_AUTH_SECRET" }}'';
|
||||
Provider = {
|
||||
Url = ''{{ env "OIDC_AUTH_PROVIDER_URL" }}'';
|
||||
ClientId = ''{{ env "${mapOidcClientNameToEnv oidcClientName}_OIDC_AUTH_PROVIDER_CLIENT_ID" }}'';
|
||||
ClientSecret = ''{{ env "${mapOidcClientNameToEnv oidcClientName}_OIDC_AUTH_PROVIDER_CLIENT_SECRET" }}'';
|
||||
UsePkce = oidcClientConfig.usePkce;
|
||||
UseClaimsFromUserInfo = oidcClientConfig.useClaimsFromUserInfo;
|
||||
};
|
||||
Scopes = oidcClientConfig.scopes;
|
||||
LoginUrl = ''{{ env "OIDC_AUTH_PROVIDER_URL" }}'';
|
||||
} // (lib.attrsets.optionalAttrs oidcClientConfig.enableBypassUsingClientCertificate {
|
||||
BypassAuthenticationRule = "HeaderRegexp(`X-Forwarded-Tls-Client-Cert`, `.+`)";
|
||||
}) // (lib.attrsets.optionalAttrs ((lib.length oidcClientConfig.headers) > 0) {
|
||||
Headers = oidcClientConfig.headers;
|
||||
});
|
||||
}
|
||||
) cfg.oidcClients;
|
||||
traefik-oidc-authentication-config = (pkgs.formats.yaml {}).generate "traefik-oidc-auth" {
|
||||
http.middlewares = oidc-config;
|
||||
};
|
||||
in [
|
||||
"/var/run/docker.sock:/var/run/docker.sock"
|
||||
"${traefik-oidc-authentication-config}:/dynamic-config/traefik-oidc-auth.yaml:ro"
|
||||
"${traefik-mtls-config}:/dynamic-config/traefik-mtls.yaml:ro"
|
||||
"${cfg.mTLSCaCertSecret.path}:/caFiles/root_ca.crt:ro"
|
||||
];
|
||||
extraOptions = [
|
||||
''--mount=type=volume,source=certs,target=/certs,volume-driver=local''
|
||||
"--add-host=host.docker.internal:host-gateway"
|
||||
"--health-cmd=wget --spider --quiet http://localhost:8080/ping"
|
||||
"--health-interval=10s"
|
||||
"--health-timeout=5s"
|
||||
"--health-retries=3"
|
||||
"--health-start-period=5s"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services."docker-traefik" = {
|
||||
after = [
|
||||
"docker-network-traefik.service"
|
||||
];
|
||||
requires = [
|
||||
"docker-network-traefik.service"
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services."docker-network-traefik" = {
|
||||
path = [ pkgs.docker ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
};
|
||||
script = ''
|
||||
docker network inspect traefik || docker network create traefik --ipv4 --ipv6 --subnet=172.18.0.0/16 --gateway=172.18.0.1
|
||||
'';
|
||||
};
|
||||
|
||||
networking.firewall.extraCommands = "iptables -t nat -I PREROUTING -s 172.18.0.0/16 -d 172.18.0.0/16 -j MASQUERADE";
|
||||
|
||||
};
|
||||
}
|
||||
|
|
@ -7,7 +7,15 @@
|
|||
let
|
||||
|
||||
cfg = config.services.traefik-docker;
|
||||
version = "3.6.14";
|
||||
|
||||
mapOidcClientNameToEnv = stringToReplace: lib.replaceString "-" "_" (lib.toUpper stringToReplace);
|
||||
|
||||
traefik-mtls-config = (pkgs.formats.yaml { }).generate "traefik-mtls-config" {
|
||||
tls.options.default.clientAuth = {
|
||||
caFiles = "caFiles/root_ca.crt";
|
||||
clientAuthType = "VerifyClientCertIfGiven";
|
||||
};
|
||||
};
|
||||
|
||||
in {
|
||||
|
||||
|
|
@ -21,40 +29,105 @@ in {
|
|||
description = "Secrets for DNS providers.";
|
||||
type = lib.types.listOf lib.types.anything;
|
||||
};
|
||||
dnsChallengeProvider = lib.mkOption {
|
||||
description = "Name of provider for DNS challenge.";
|
||||
mTLSCaCertSecret = lib.mkOption {
|
||||
description = "Agenix secret containing the CA file to verify client certificates against.";
|
||||
};
|
||||
oidcAuthProviderUrl = lib.mkOption {
|
||||
description = "Provider URL of OIDC auth provider.";
|
||||
type = lib.types.str;
|
||||
};
|
||||
oidcClients = lib.mkOption {
|
||||
example = ''
|
||||
immich = {
|
||||
scopes = [
|
||||
"openid"
|
||||
"email"
|
||||
"profile"
|
||||
];
|
||||
enableBypassUsingClientCertificate = true;
|
||||
usePkce = true;
|
||||
};
|
||||
'';
|
||||
description = "Attribute set of OIDC clients with their configurations.";
|
||||
type = lib.types.attrsOf (
|
||||
lib.types.submodule {
|
||||
options = {
|
||||
secret = lib.mkOption {
|
||||
description = ''Agenix secret containing the following needed environment variables in dotenv notation:
|
||||
- <clientName>_OIDC_AUTH_SECRET
|
||||
- <clientName>_OIDC_AUTH_PROVIDER_CLIENT_ID
|
||||
- <clientName>_OIDC_CLIENT_SECRET
|
||||
'';
|
||||
};
|
||||
scopes = lib.mkOption {
|
||||
default = [ "openid" ];
|
||||
example = [ "openid" "email" "profile" "groups" ];
|
||||
description = "OIDC scopes to request from auth provider.";
|
||||
type = lib.types.listOf lib.types.str;
|
||||
};
|
||||
usePkce = lib.mkOption {
|
||||
default = true;
|
||||
description = "Whether to enable PKCE for this provider.";
|
||||
type = lib.types.bool;
|
||||
};
|
||||
enableBypassUsingClientCertificate = lib.mkOption {
|
||||
default = false;
|
||||
description = "Whether to allow bypassing OIDC protection when a verified client certificate is presented.";
|
||||
type = lib.types.bool;
|
||||
};
|
||||
useClaimsFromUserInfo = lib.mkOption {
|
||||
default = false;
|
||||
description = "When enabled, an additional request to the provider's userinfo_endpoint is made to validate the token and to retrieve additional claims. The userinfo claims are merged directly into the token claims, with userinfo values overriding token values for non-security-critical claims.";
|
||||
type = lib.types.bool;
|
||||
};
|
||||
headers = lib.mkOption {
|
||||
default = [];
|
||||
description = "Headers to be added to the upstream request. Templating is possible. Documentation can be found here: https://traefik-oidc-auth.sevensolutions.cc/docs/getting-started/middleware-configuration";
|
||||
type = lib.types.listOf (lib.types.submodule {
|
||||
options = {
|
||||
Name = lib.mkOption {
|
||||
description = "The name of the header which should be added to the upstream request.";
|
||||
type = lib.types.str;
|
||||
};
|
||||
Value = lib.mkOption {
|
||||
description = "The value of the header, which can use Go-Templates.";
|
||||
type = lib.types.str;
|
||||
};
|
||||
};
|
||||
});
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
|
||||
config = lib.mkIf cfg.enable {
|
||||
virtualisation.oci-containers.containers = {
|
||||
traefik = {
|
||||
image = "traefik:v${version}";
|
||||
image = "traefik:v3.6.6";
|
||||
cmd = [
|
||||
"--providers.docker=true"
|
||||
"--providers.docker.endpoint=http://docker-socket-proxy:2375"
|
||||
"--providers.docker.exposedByDefault=false"
|
||||
"--providers.docker.network=webproxy"
|
||||
"--providers.docker.network=traefik"
|
||||
"--providers.file.directory=/dynamic-config"
|
||||
"--log.level=INFO"
|
||||
"--api=true"
|
||||
"--ping=true"
|
||||
"--entrypoints.web.address=:80"
|
||||
"--entrypoints.websecure.address=:443"
|
||||
"--entrypoints.websecure.transport.respondingTimeouts.readTimeout=0"
|
||||
"--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=0"
|
||||
"--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=0"
|
||||
"--serverstransport.forwardingtimeouts.responseheadertimeout=0s"
|
||||
"--serverstransport.forwardingtimeouts.idleconntimeout=0s"
|
||||
"--entrypoints.websecure.transport.respondingTimeouts.readTimeout=600s"
|
||||
"--entrypoints.websecure.transport.respondingTimeouts.idleTimeout=600s"
|
||||
"--entrypoints.websecure.transport.respondingTimeouts.writeTimeout=600s"
|
||||
"--entrypoints.web.http.redirections.entrypoint.to=websecure"
|
||||
"--entrypoints.websecure.asDefault=true"
|
||||
"--entrypoints.websecure.http.middlewares=strip-mtls-headers@docker,pass-tls-client-cert@docker"
|
||||
"--entrypoints.websecure.http.tls.certresolver=letsencrypt"
|
||||
"--certificatesresolvers.letsencrypt.acme.email=contact@jfreudenberger.de"
|
||||
"--certificatesresolvers.letsencrypt.acme.storage=/certs/acme.json"
|
||||
"--certificatesresolvers.letsencrypt.acme.dnschallenge=true"
|
||||
"--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=${cfg.dnsChallengeProvider}"
|
||||
"--providers.file.filename=/dynamic-config/providers.yaml"
|
||||
"--certificatesresolvers.letsencrypt.acme.dnschallenge.provider=netcup"
|
||||
"--experimental.plugins.traefik-oidc-auth.modulename=github.com/sevensolutions/traefik-oidc-auth"
|
||||
"--experimental.plugins.traefik-oidc-auth.version=v0.17.0"
|
||||
];
|
||||
autoStart = true;
|
||||
ports = [
|
||||
|
|
@ -62,17 +135,54 @@ in {
|
|||
"443:443"
|
||||
];
|
||||
networks = [
|
||||
"webproxy"
|
||||
"docker-socket"
|
||||
"traefik"
|
||||
];
|
||||
environmentFiles = lib.forEach cfg.dnsSecrets (secret: secret.path);
|
||||
environment = {
|
||||
OIDC_AUTH_PROVIDER_URL = cfg.oidcAuthProviderUrl;
|
||||
};
|
||||
environmentFiles = lib.forEach cfg.dnsSecrets (secret: secret.path) ++ (lib.mapAttrsToList (oidcClientName: oidcClientConfig: oidcClientConfig.secret.path) cfg.oidcClients);
|
||||
labels = {
|
||||
"traefik.enable" = "true";
|
||||
"traefik.http.routers.dashboard.rule" = "Host(`${cfg.dashboardUrl}`)";
|
||||
"traefik.http.routers.dashboard.service" = "dashboard@internal";
|
||||
"traefik.http.routers.dashboard.middlewares" = "traefik-dashboard-oidc-auth@file";
|
||||
"traefik.http.routers.api.rule" = "Host(`${cfg.dashboardUrl}`) && (PathPrefix(`/api`) || PathPrefix(`/oidc/callback`))";
|
||||
"traefik.http.routers.api.service" = "api@internal";
|
||||
"traefik.http.routers.api.middlewares" = "traefik-dashboard-oidc-auth@file";
|
||||
"traefik.http.middlewares.strip-mtls-headers.headers.customrequestheaders.X-Forwarded-Tls-Client-Cert" = "";
|
||||
"traefik.http.middlewares.pass-tls-client-cert.passtlsclientcert.pem" = "true";
|
||||
};
|
||||
volumes = let
|
||||
traefik-providers-config = (pkgs.formats.yaml {}).generate "traefik-providers-config" {
|
||||
tcp.serversTransports.pp-v2.proxyProtocol.version = 2;
|
||||
oidc-config = lib.mapAttrs' (
|
||||
oidcClientName: oidcClientConfig:
|
||||
lib.nameValuePair "${oidcClientName}-oidc-auth" {
|
||||
plugin.traefik-oidc-auth = {
|
||||
LogLevel = "INFO";
|
||||
Secret = ''{{ env "${mapOidcClientNameToEnv oidcClientName}_OIDC_AUTH_SECRET" }}'';
|
||||
Provider = {
|
||||
Url = ''{{ env "OIDC_AUTH_PROVIDER_URL" }}'';
|
||||
ClientId = ''{{ env "${mapOidcClientNameToEnv oidcClientName}_OIDC_AUTH_PROVIDER_CLIENT_ID" }}'';
|
||||
ClientSecret = ''{{ env "${mapOidcClientNameToEnv oidcClientName}_OIDC_AUTH_PROVIDER_CLIENT_SECRET" }}'';
|
||||
UsePkce = oidcClientConfig.usePkce;
|
||||
UseClaimsFromUserInfo = oidcClientConfig.useClaimsFromUserInfo;
|
||||
};
|
||||
Scopes = oidcClientConfig.scopes;
|
||||
LoginUrl = ''{{ env "OIDC_AUTH_PROVIDER_URL" }}'';
|
||||
} // (lib.attrsets.optionalAttrs oidcClientConfig.enableBypassUsingClientCertificate {
|
||||
BypassAuthenticationRule = "HeaderRegexp(`X-Forwarded-Tls-Client-Cert`, `.+`)";
|
||||
}) // (lib.attrsets.optionalAttrs ((lib.length oidcClientConfig.headers) > 0) {
|
||||
Headers = oidcClientConfig.headers;
|
||||
});
|
||||
}
|
||||
) cfg.oidcClients;
|
||||
traefik-oidc-authentication-config = (pkgs.formats.yaml {}).generate "traefik-oidc-auth" {
|
||||
http.middlewares = oidc-config;
|
||||
};
|
||||
in [
|
||||
"/var/run/docker.sock:/var/run/docker.sock"
|
||||
"${traefik-providers-config}:/dynamic-config/providers.yaml:ro"
|
||||
"${traefik-oidc-authentication-config}:/dynamic-config/traefik-oidc-auth.yaml:ro"
|
||||
"${traefik-mtls-config}:/dynamic-config/traefik-mtls.yaml:ro"
|
||||
"${cfg.mTLSCaCertSecret.path}:/caFiles/root_ca.crt:ro"
|
||||
];
|
||||
extraOptions = [
|
||||
''--mount=type=volume,source=certs,target=/certs,volume-driver=local''
|
||||
|
|
@ -84,49 +194,24 @@ in {
|
|||
"--health-start-period=5s"
|
||||
];
|
||||
};
|
||||
docker-socket-proxy = {
|
||||
image = "tecnativa/docker-socket-proxy:v0.4.2";
|
||||
autoStart = true;
|
||||
networks = [
|
||||
"docker-socket"
|
||||
];
|
||||
environment = {
|
||||
CONTAINERS = "1";
|
||||
};
|
||||
volumes = [
|
||||
"/var/run/docker.sock:/var/run/docker.sock:ro"
|
||||
];
|
||||
};
|
||||
};
|
||||
|
||||
systemd.services."docker-traefik" = {
|
||||
after = [
|
||||
"docker-network-webproxy.service"
|
||||
"docker-network-docker-socket.service"
|
||||
"docker-network-traefik.service"
|
||||
];
|
||||
requires = [
|
||||
"docker-network-webproxy.service"
|
||||
"docker-network-docker-socket.service"
|
||||
"docker-network-traefik.service"
|
||||
];
|
||||
};
|
||||
|
||||
systemd.services."docker-network-webproxy" = {
|
||||
systemd.services."docker-network-traefik" = {
|
||||
path = [ pkgs.docker ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
};
|
||||
script = ''
|
||||
docker network inspect webproxy || docker network create webproxy --ipv4 --ipv6 --subnet=172.18.0.0/16 --gateway=172.18.0.1
|
||||
'';
|
||||
};
|
||||
|
||||
systemd.services."docker-network-docker-socket" = {
|
||||
path = [ pkgs.docker ];
|
||||
serviceConfig = {
|
||||
Type = "oneshot";
|
||||
};
|
||||
script = ''
|
||||
docker network inspect docker-socket || docker network create docker-socket --ipv4 --ipv6 --subnet=172.19.0.0/16 --gateway=172.19.0.1
|
||||
docker network inspect traefik || docker network create traefik --ipv4 --ipv6 --subnet=172.18.0.0/16 --gateway=172.18.0.1
|
||||
'';
|
||||
};
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue