diff --git a/flake.lock b/flake.lock index 4366ad2..ed0043b 100644 --- a/flake.lock +++ b/flake.lock @@ -1,5 +1,47 @@ { "nodes": { + "authentik-nix": { + "inputs": { + "authentik-src": "authentik-src", + "flake-compat": "flake-compat", + "flake-parts": "flake-parts", + "flake-utils": "flake-utils", + "napalm": "napalm", + "nixpkgs": "nixpkgs", + "poetry2nix": "poetry2nix", + "systems": "systems" + }, + "locked": { + "lastModified": 1736445563, + "narHash": "sha256-+f1MWPtja+LRlTHJP/i/3yxmnzo2LGtZmxtJJTdAp8o=", + "owner": "nix-community", + "repo": "authentik-nix", + "rev": "bf5a5bf42189ff5f468f0ff26c9296233a97eb6c", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "authentik-nix", + "type": "github" + } + }, + "authentik-src": { + "flake": false, + "locked": { + "lastModified": 1736440980, + "narHash": "sha256-Z3rFFrXrOKaF9NpY/fInsEbzdOWnWqLfEYl7YX9hFEU=", + "owner": "goauthentik", + "repo": "authentik", + "rev": "9d81f0598c7735e2b4616ee865ab896056a67408", + "type": "github" + }, + "original": { + "owner": "goauthentik", + "ref": "version/2024.12.2", + "repo": "authentik", + "type": "github" + } + }, "base16": { "inputs": { "fromYaml": "fromYaml" @@ -90,7 +132,7 @@ }, "firefox-addons": { "inputs": { - "flake-utils": "flake-utils", + "flake-utils": "flake-utils_2", "nixpkgs": [ "nixpkgs" ] @@ -128,6 +170,22 @@ } }, "flake-compat": { + "flake": false, + "locked": { + "lastModified": 1696426674, + "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", + "owner": "edolstra", + "repo": "flake-compat", + "rev": "0f9255e01c2351cc7d116c072cb317785dd33b33", + "type": "github" + }, + "original": { + "owner": "edolstra", + "repo": "flake-compat", + "type": "github" + } + }, + "flake-compat_2": { "flake": false, "locked": { "lastModified": 1733328505, @@ -143,7 +201,7 @@ "type": "github" } }, - "flake-compat_2": { + "flake-compat_3": { "locked": { "lastModified": 1696426674, "narHash": "sha256-kvjfFW7WAETZlt09AgDn1MrtKzP7t90Vf7vypd3OL1U=", @@ -157,7 +215,7 @@ "url": "https://flakehub.com/f/edolstra/flake-compat/1.tar.gz" } }, - "flake-compat_3": { + "flake-compat_4": { "flake": false, "locked": { "lastModified": 1696426674, @@ -174,6 +232,24 @@ } }, "flake-parts": { + "inputs": { + "nixpkgs-lib": "nixpkgs-lib" + }, + "locked": { + "lastModified": 1727826117, + "narHash": "sha256-K5ZLCyfO/Zj9mPFldf3iwS6oZStJcU4tSpiXTMYaaL0=", + "owner": "hercules-ci", + "repo": "flake-parts", + "rev": "3d04084d54bedc3d6b8b736c70ef449225c361b1", + "type": "github" + }, + "original": { + "owner": "hercules-ci", + "repo": "flake-parts", + "type": "github" + } + }, + "flake-parts_2": { "inputs": { "nixpkgs-lib": [ "nixpkgs" @@ -193,7 +269,7 @@ "type": "github" } }, - "flake-parts_2": { + "flake-parts_3": { "inputs": { "nixpkgs-lib": [ "nvim-nix", @@ -216,6 +292,27 @@ } }, "flake-utils": { + "inputs": { + "systems": [ + "authentik-nix", + "systems" + ] + }, + "locked": { + "lastModified": 1726560853, + "narHash": "sha256-X6rJYSESBVr3hBoH0WbKE5KvhPU5bloyZ2L4K60/fPQ=", + "owner": "numtide", + "repo": "flake-utils", + "rev": "c1dfcf08411b08f6b8615f7d8971a2bfa81d5e8a", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "flake-utils", + "type": "github" + } + }, + "flake-utils_2": { "locked": { "lastModified": 1629284811, "narHash": "sha256-JHgasjPR0/J1J3DRm4KxM4zTyAj4IOJY8vIl75v/kPI=", @@ -230,9 +327,9 @@ "type": "github" } }, - "flake-utils_2": { + "flake-utils_3": { "inputs": { - "systems": "systems" + "systems": "systems_2" }, "locked": { "lastModified": 1731533236, @@ -248,7 +345,7 @@ "type": "github" } }, - "flake-utils_3": { + "flake-utils_4": { "inputs": { "systems": [ "stylix", @@ -514,6 +611,32 @@ "type": "github" } }, + "napalm": { + "inputs": { + "flake-utils": [ + "authentik-nix", + "flake-utils" + ], + "nixpkgs": [ + "authentik-nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1725806412, + "narHash": "sha256-lGZjkjds0p924QEhm/r0BhAxbHBJE1xMOldB/HmQH04=", + "owner": "willibutz", + "repo": "napalm", + "rev": "b492440d9e64ae20736d3bec5c7715ffcbde83f5", + "type": "github" + }, + "original": { + "owner": "willibutz", + "ref": "avoid-foldl-stack-overflow", + "repo": "napalm", + "type": "github" + } + }, "nix-darwin": { "inputs": { "nixpkgs": [ @@ -536,6 +659,28 @@ "type": "github" } }, + "nix-github-actions": { + "inputs": { + "nixpkgs": [ + "authentik-nix", + "poetry2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1729742964, + "narHash": "sha256-B4mzTcQ0FZHdpeWcpDYPERtyjJd/NIuaQ9+BV1h+MpA=", + "owner": "nix-community", + "repo": "nix-github-actions", + "rev": "e04df33f62cdcf93d73e9a04142464753a16db67", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "nix-github-actions", + "type": "github" + } + }, "nix-index-database": { "inputs": { "nixpkgs": [ @@ -558,7 +703,7 @@ }, "nixos-wsl": { "inputs": { - "flake-compat": "flake-compat", + "flake-compat": "flake-compat_2", "nixpkgs": [ "nixpkgs" ] @@ -579,6 +724,34 @@ } }, "nixpkgs": { + "locked": { + "lastModified": 1735834308, + "narHash": "sha256-dklw3AXr3OGO4/XT1Tu3Xz9n/we8GctZZ75ZWVqAVhk=", + "owner": "NixOS", + "repo": "nixpkgs", + "rev": "6df24922a1400241dae323af55f30e4318a6ca65", + "type": "github" + }, + "original": { + "owner": "NixOS", + "ref": "nixos-unstable", + "repo": "nixpkgs", + "type": "github" + } + }, + "nixpkgs-lib": { + "locked": { + "lastModified": 1727825735, + "narHash": "sha256-0xHYkMkeLVQAMa7gvkddbPqpxph+hDzdu1XdGPJR+Os=", + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz" + }, + "original": { + "type": "tarball", + "url": "https://github.com/NixOS/nixpkgs/archive/fb192fec7cc7a4c26d51779e9bab07ce6fa5597a.tar.gz" + } + }, + "nixpkgs_2": { "locked": { "lastModified": 1736798957, "narHash": "sha256-qwpCtZhSsSNQtK4xYGzMiyEDhkNzOCz/Vfu4oL2ETsQ=", @@ -597,8 +770,8 @@ "nixvim": { "inputs": { "devshell": "devshell", - "flake-compat": "flake-compat_2", - "flake-parts": "flake-parts_2", + "flake-compat": "flake-compat_3", + "flake-parts": "flake-parts_3", "git-hooks": "git-hooks", "home-manager": "home-manager_2", "nix-darwin": "nix-darwin", @@ -607,7 +780,7 @@ "nixpkgs" ], "nuschtosSearch": "nuschtosSearch", - "treefmt-nix": "treefmt-nix" + "treefmt-nix": "treefmt-nix_2" }, "locked": { "lastModified": 1736964246, @@ -625,7 +798,7 @@ }, "nuschtosSearch": { "inputs": { - "flake-utils": "flake-utils_2", + "flake-utils": "flake-utils_3", "ixx": "ixx", "nixpkgs": [ "nvim-nix", @@ -668,15 +841,47 @@ "type": "github" } }, + "poetry2nix": { + "inputs": { + "flake-utils": [ + "authentik-nix", + "flake-utils" + ], + "nix-github-actions": "nix-github-actions", + "nixpkgs": [ + "authentik-nix", + "nixpkgs" + ], + "systems": [ + "authentik-nix", + "systems" + ], + "treefmt-nix": "treefmt-nix" + }, + "locked": { + "lastModified": 1735164664, + "narHash": "sha256-DaWy+vo3c4TQ93tfLjUgcpPaSoDw4qV4t76Y3Mhu84I=", + "owner": "nix-community", + "repo": "poetry2nix", + "rev": "1fb01e90771f762655be7e0e805516cd7fa4d58e", + "type": "github" + }, + "original": { + "owner": "nix-community", + "repo": "poetry2nix", + "type": "github" + } + }, "root": { "inputs": { + "authentik-nix": "authentik-nix", "firefox-addons": "firefox-addons", - "flake-parts": "flake-parts", + "flake-parts": "flake-parts_2", "hardware": "hardware", "home-manager": "home-manager", "nix-index-database": "nix-index-database", "nixos-wsl": "nixos-wsl", - "nixpkgs": "nixpkgs", + "nixpkgs": "nixpkgs_2", "nvim-nix": "nvim-nix", "sobercookie": "sobercookie", "sops-nix": "sops-nix", @@ -731,15 +936,15 @@ "base16-helix": "base16-helix", "base16-vim": "base16-vim", "firefox-gnome-theme": "firefox-gnome-theme", - "flake-compat": "flake-compat_3", - "flake-utils": "flake-utils_3", + "flake-compat": "flake-compat_4", + "flake-utils": "flake-utils_4", "git-hooks": "git-hooks_2", "gnome-shell": "gnome-shell", "home-manager": "home-manager_3", "nixpkgs": [ "nixpkgs" ], - "systems": "systems_2", + "systems": "systems_3", "tinted-foot": "tinted-foot", "tinted-kitty": "tinted-kitty", "tinted-tmux": "tinted-tmux", @@ -760,6 +965,21 @@ } }, "systems": { + "locked": { + "lastModified": 1689347949, + "narHash": "sha256-12tWmuL2zgBgZkdoB6qXZsgJEH9LR3oUgpaQq2RbI80=", + "owner": "nix-systems", + "repo": "default-linux", + "rev": "31732fcf5e8fea42e59c2488ad31a0e651500f68", + "type": "github" + }, + "original": { + "owner": "nix-systems", + "repo": "default-linux", + "type": "github" + } + }, + "systems_2": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", @@ -774,7 +994,7 @@ "type": "github" } }, - "systems_2": { + "systems_3": { "locked": { "lastModified": 1681028828, "narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=", @@ -856,6 +1076,28 @@ } }, "treefmt-nix": { + "inputs": { + "nixpkgs": [ + "authentik-nix", + "poetry2nix", + "nixpkgs" + ] + }, + "locked": { + "lastModified": 1730120726, + "narHash": "sha256-LqHYIxMrl/1p3/kvm2ir925tZ8DkI0KA10djk8wecSk=", + "owner": "numtide", + "repo": "treefmt-nix", + "rev": "9ef337e492a5555d8e17a51c911ff1f02635be15", + "type": "github" + }, + "original": { + "owner": "numtide", + "repo": "treefmt-nix", + "type": "github" + } + }, + "treefmt-nix_2": { "inputs": { "nixpkgs": [ "nvim-nix", diff --git a/flake.nix b/flake.nix index 537d856..eea9951 100644 --- a/flake.nix +++ b/flake.nix @@ -57,6 +57,8 @@ nixos-wsl.url = "github:nix-community/NixOS-WSL/main"; nixos-wsl.inputs.nixpkgs.follows = "nixpkgs"; + authentik-nix.url = "github:nix-community/authentik-nix"; + # nvfetcher.url = "github:berberman/nvfetcher"; # nvfetcher.inputs.nixpkgs.follows = "nixpkgs"; diff --git a/sys/machines/hopper/lab/default.nix b/sys/machines/hopper/lab/default.nix index 0ff523b..9ea522b 100644 --- a/sys/machines/hopper/lab/default.nix +++ b/sys/machines/hopper/lab/default.nix @@ -19,6 +19,7 @@ in { imports = [ ./samba.nix + inputs.authentik-nix.nixosModules.default ]; ## TODO use kanidm @@ -82,6 +83,7 @@ in { caddyPort slskdUiPort 80 # caddy + 443 # caddy 1900 # jellyfin discovery 7359 # jellyfin discovery # 9001 @@ -116,12 +118,17 @@ in { hostName = "${n}.${domain}:${toString caddyPort}"; } // v) { - jellyfin.extraConfig = "reverse_proxy localhost:8096"; # TODO setup proper auth + jellyfin.extraConfig = '' + reverse_proxy { + header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} + to localhost:8096 + } + ''; kanidm = { useACMEHost = null; - # hostName = "kanidm.xunuwu.xyz:${toString caddyPort}"; extraConfig = '' reverse_proxy https://127.0.0.1:${toString kanidmPort} { + header_up X-Forwarded-For {http.request.header.CF-Connecting-IP} header_up Host {upstream_hostport} header_down Access-Control-Allow-Origin "*" transport http { @@ -148,12 +155,54 @@ in { dash = { useACMEHost = null; hostName = "dash.hopper.xun.host:80"; - extraConfig = "reverse_proxy localhost:${toString config.services.homepage-dashboard.listenPort}"; + extraConfig = '' + # Requests to /oauth2/* are proxied to oauth2-proxy without authentication. + # You can't use `reverse_proxy /oauth2/* oauth2-proxy.internal:4180` here because the reverse_proxy directive has lower precedence than the handle directive. + handle /oauth2/* { + reverse_proxy unix//run/oauth2-proxy/oauth2-proxy.sock { + # oauth2-proxy requires the X-Real-IP and X-Forwarded-{Proto,Host,Uri} headers. + # The reverse_proxy directive automatically sets X-Forwarded-{For,Proto,Host} headers. + header_up X-Real-IP {remote_host} + header_up X-Forwarded-Uri {uri} + } + } + + # Requests to other paths are first processed by oauth2-proxy for authentication. + handle { + forward_auth unix//run/oauth2-proxy/oauth2-proxy.sock { + uri /oauth2/auth + + # oauth2-proxy requires the X-Real-IP and X-Forwarded-{Proto,Host,Uri} headers. + # The forward_auth directive automatically sets the X-Forwarded-{For,Proto,Host,Method,Uri} headers. + header_up X-Real-IP {remote_host} + + # If needed, you can copy headers from the oauth2-proxy response to the request sent to the upstream. + # Make sure to configure the --set-xauthrequest flag to enable this feature. + #copy_headers X-Auth-Request-User X-Auth-Request-Email + + # If oauth2-proxy returns a 401 status, redirect the client to the sign-in page. + @error status 401 + handle_response @error { + redir * /oauth2/sign_in?rd={scheme}://{host}{uri} + } + } + + reverse_proxy localhost:${toString config.services.homepage-dashboard.listenPort} + } + + ''; }; oauth2-proxy = { hostName = "oauth2.${domain}:${toString caddyPort}"; extraConfig = "reverse_proxy unix//run/oauth2-proxy/oauth2-proxy.sock"; }; + navidrome = { + useACMEHost = null; + hostName = "navidrome.hopper.xun.host:80"; + extraConfig = '' + reverse_proxy unix//var/lib/navidrome/navidrome.sock + ''; + }; firefly = { useACMEHost = null; hostName = "firefly.hopper.xun.host:80"; @@ -316,6 +365,26 @@ in { ]; }; + # TODO finish setting up authentik + # services.authentik = { + # enable = true; + # settings = { + # disable_startup_analytics = true; + # error_reporting.enabled = false; + # avatars = "initials"; + # }; + # }; + + # TODO finish setting up navidrome + users.groups.${config.services.navidrome.group}.members = ["caddy"]; # for socket file :) + services.navidrome = { + enable = true; + settings = { + MusicFolder = "/media/library/music"; + Address = "unix:/var/lib/navidrome/navidrome.sock"; + }; + }; + systemd.services.jellyfin.vpnConfinement = { enable = true; vpnNamespace = "wg"; @@ -433,14 +502,14 @@ in { }; users.groups.oauth2-proxy.members = ["caddy"]; - services.oauth2-proxy = let - clientID = "oauth2-proxy"; - in { + services.oauth2-proxy = { enable = true; - inherit clientID; + clientID = "oauth2-proxy"; cookie.expire = "24h"; email.domains = ["*"]; httpAddress = "unix:///run/oauth2-proxy/oauth2-proxy.sock"; + scope = "openid profile email"; + redirectURL = "https://oauth2.${domain}/oauth2/callback"; keyFile = config.sops.secrets.oauth2-proxy.path; @@ -450,10 +519,11 @@ in { provider = "oidc"; - loginURL = "https://${config.services.kanidm.serverSettings.domain}/ui/oauth2"; redeemURL = "https://${config.services.kanidm.serverSettings.domain}/oauth2/token"; - validateURL = "https://${config.services.kanidm.serverSettings.domain}/oauth2/openid/${clientID}/userinfo"; - oidcIssuerUrl = "https://${config.services.kanidm.serverSettings.domain}/oauth2/openid/${clientID}"; + loginURL = "https://${config.services.kanidm.serverSettings.domain}/ui/oauth2"; + oidcIssuerUrl = "https://${config.services.kanidm.serverSettings.domain}/oauth2/openid/oauth2-proxy"; + validateURL = "https://${config.services.kanidm.serverSettings.domain}/oauth2/token/introspect"; + profileURL = "https://${config.services.kanidm.serverSettings.domain}/oauth2/openid/oauth2-proxy/userinfo"; # redeemURL = "https://${config.services.kanidm.serverSettings.domain}/oauth2/token"; # loginURL = "https://${config.services.kanidm.serverSettings.domain}/ui/oauth2"; @@ -521,6 +591,7 @@ in { preferShortUsername = true; scopeMaps."oauth2-proxy.access" = [ "openid" + "profile" "email" ]; claimMaps.groups = {