feat: add RFC 7033 support with new service and package

Python webserver to serve RFC7033 since Authentik does not support it.
This is needed for OICD login in Tailscale
This commit is contained in:
= 2025-02-09 00:27:36 +01:00
parent 8b72b206ce
commit f664873ced
3 changed files with 116 additions and 2 deletions

View file

@ -6,6 +6,10 @@
}: }:
let let
cfg = config.my.services.authentik; cfg = config.my.services.authentik;
# https://github.com/goauthentik/authentik/issues/5440#issuecomment-1682856454
# Needed for Tailscale
rfc-7033 = pkgs.callPackage ../../packages/authentik-rfc7033/default.nix { };
in in
{ {
@ -101,14 +105,48 @@ in
}; };
}; };
networking.firewall.allowedTCPPorts = [ 9000 ]; # Add your package to system packages
environment.systemPackages = [ rfc-7033 ];
# Systemd service configuration
systemd.services.authentik-rfc-7033 = {
description = "Pyhton webserver to implement RFC 7033";
wantedBy = [ "multi-user.target" ];
serviceConfig = {
ExecStart = "${pkgs.python3}/bin/python ${rfc-7033}/bin/rfc-7033.py";
Restart = "on-failure";
User = "nobody"; # Or specify a user
Group = "nogroup";
# Optional: Log output to journalctl
StandardOutput = "journal";
StandardError = "journal";
};
};
# Port 8000 is for RFC 7033
networking.firewall.allowedTCPPorts = [
8000
9000
];
}) })
(lib.mkIf cfg.proxy.enable { (lib.mkIf cfg.proxy.enable {
services.caddy = with cfg.proxy; { services.caddy = with cfg.proxy; {
virtualHosts."${subdomain}.${domain}".extraConfig = '' virtualHosts."${subdomain}.${domain}".extraConfig = ''
# Other reverse proxies go here
handle {
reverse_proxy http://${host}:9000 reverse_proxy http://${host}:9000
}
import cloudflare_${domain}
'';
virtualHosts."${domain}".extraConfig = ''
handle /.well-known/webfinger {
# This should point to the port that the Python script is running on, default is 8000
reverse_proxy http://${host}:8000
}
import cloudflare_${domain} import cloudflare_${domain}
''; '';
}; };

View file

@ -0,0 +1,15 @@
{
pkgs ? import <nixpkgs> { },
}:
pkgs.stdenv.mkDerivation rec {
name = "authentik-rfc7033";
src = ./src;
buildInputs = [ pkgs.python3 ];
installPhase = ''
install -Dm755 rfc-7033.py $out/bin/rfc-7033.py
patchShebangs $out/bin/rfc-7033.py
'';
}

View file

@ -0,0 +1,61 @@
#!/usr/bin/env python3
from http.server import BaseHTTPRequestHandler, HTTPServer
from urllib.parse import urlparse, parse_qs
import json
class WebFingerHandler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path.startswith('/.well-known/webfinger'):
parsed_url = urlparse(self.path)
query_params = parse_qs(parsed_url.query)
if 'resource' in query_params:
resource = query_params['resource'][0]
if resource.startswith('acct:'):
email = resource[5:]
issuer_url = "https://auth.pasetto.me/application/o/tailscale/"
response_data = {
"subject": resource,
"links": [
{
"rel": "http://openid.net/specs/connect/1.0/issuer",
"href": issuer_url
},
{
"rel": "authorization_endpoint",
"href": issuer_url + "oauth2/authorize"
},
{
"rel": "token_endpoint",
"href": issuer_url + "oauth2/token"
},
{
"rel": "userinfo_endpoint",
"href": issuer_url + "userinfo"
},
{
"rel": "jwks_uri",
"href": issuer_url + "jwks"
}
]
}
self.send_response(200)
self.send_header("Content-type", "application/json")
self.end_headers()
self.wfile.write(json.dumps(response_data).encode())
return
self.send_response(404)
self.end_headers()
self.wfile.write(b"Resource not found")
def run_server(server_class=HTTPServer, handler_class=WebFingerHandler, port=8000):
server_address = ('', port)
httpd = server_class(server_address, handler_class)
print(f"Starting WebFinger server on port {port}")
httpd.serve_forever()
if __name__ == '__main__':
run_server()