Zitadel als OIDC Provider für Tailscale verwenden

Anzeigen

Tailscale unterstützt standardmäßig nur die Anmeldung über bestehende SSO-Anbieter wie Google oder GitHub. Einen eigenen Tailscale-Account kann man nicht anlegen.
Wenn du aber lieber deine eigene Lösung nutzen willst, kannst du Zitadel als Identity Provider einrichten. Dazu wird OIDC (OpenID Connect) verwendet.

Das Problem: Zitadel liefert von Haus aus keinen sogenannten Webfinger mit, den Tailscale aber für die Registrierung benötigt.
Zum Glück können wir diesen Webfinger leicht selbst erstellen und über unseren Caddy Reverse Proxy bereitstellen. Das ist eine Erweiterung unser Netbird mit Zitadel als Identity Provider installation.

Für dieses Setup nutzen wir:

Anzeigen
  • Caddy als Reverse Proxy
  • Docker Compose für die Container-Verwaltung
  • Zitadel als Identity Provider

Was ist Webfinger?

Webfinger ist ein Standard, mit dem Metadaten zu einer Identität im Internet abrufbar gemacht werden – maschinenlesbar in Form einer kleinen JSON-Datei.
Man kann sich das wie eine digitale Visitenkarte vorstellen, die einem Dienst (z. B. Tailscale) zeigt: „Für diesen Benutzer ist der Login bei diesem Identity Provider zuständig.“

Ein Beispiel für den benötigten Webfinger:

{
  "subject": "acct:[email protected]",
  "links": [
    {
      "rel": "http://openid.net/specs/connect/1.0/issuer",
      "href": "https://nb.linuxbase.io"
    }
  ]
}

Wichtig: Passe [email protected] und https://nb.linuxbase.io an deine eigene Domain und Subdomain an.

Kurz gesagt

Webfinger ist ein Standard, um Metadaten zu einer Identität im Web bereitzustellen und maschinenlesbar abzurufen.

Der Webfinger ist eine einfache JSON Datei, die quasi die Adresse angibt, bei der sich Authentifiziert werden muss.

Caddy: Webfinger anzeigen

Um den Webfinger nun zu integrieren, müssen wir das Caddyfile, also die Config Datei des Caddy Reverse Proxys bearbeiten und natürlich die Datei selbst anlegen.

Schritt 1: Webfinger-Datei anlegen

Lege in deinem Netbird-Ordner einen Unterordner webfinger an und erstelle dort die Datei webfinger (ohne .json Endung):

cd netbird
mkdir webfinger
vi webfinger

Füge den JSON-Inhalt (siehe oben) ein, speichere die Datei mit ESC:wq.

Schritt 2: Caddyfile anpassen

Jetzt öffnen wir die Konfigurationsdatei von Caddy:

Dann öffnen wir die Caddyfile Datei:

cd ..
vi Caddyfile


Diese Datei sollte ungefähr so ausehen:

{
  debug
        servers :80,:443 {
    protocols h1 h2c h2 h3
  }
}

(security_headers) {
    header * {
        # enable HSTS
        # https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#strict-transport-security-hsts
        # NOTE: Read carefully how this header works before using it.
        # If the HSTS header is misconfigured or if there is a problem with
        # the SSL/TLS certificate being used, legitimate users might be unable
        # to access the website. For example, if the HSTS header is set to a
        # very long duration and the SSL/TLS certificate expires or is revoked,
        # legitimate users might be unable to access the website until
        # the HSTS header duration has expired.
        # The recommended value for the max-age is 2 year (63072000 seconds).
        # But we are using 1 hour (3600 seconds) for testing purposes
        # and ensure that the website is working properly before setting
        # to two years.

        Strict-Transport-Security "max-age=3600; includeSubDomains; preload"

        # disable clients from sniffing the media type
        # https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-content-type-options
        X-Content-Type-Options "nosniff"

        # clickjacking protection
        # https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-frame-options
        X-Frame-Options "SAMEORIGIN"

        # xss protection
        # https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-xss-protection
        X-XSS-Protection "1; mode=block"

        # Remove -Server header, which is an information leak
        # Remove Caddy from Headers
        -Server

        # keep referrer data off of HTTP connections
        # https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#referrer-policy
        Referrer-Policy strict-origin-when-cross-origin
    }
}

:80, nb.linxubase.io:443 {
    import security_headers
    # relay
    reverse_proxy /relay* relay:80
    # Signal
    reverse_proxy /signalexchange.SignalExchange/* h2c://signal:10000
    # Management
    reverse_proxy /api/* management:80
    reverse_proxy /management.ManagementService/* h2c://management:80
    # Zitadel
    reverse_proxy /zitadel.admin.v1.AdminService/* h2c://zitadel:8080
    reverse_proxy /admin/v1/* h2c://zitadel:8080
    reverse_proxy /zitadel.auth.v1.AuthService/* h2c://zitadel:8080
    reverse_proxy /auth/v1/* h2c://zitadel:8080
    reverse_proxy /zitadel.management.v1.ManagementService/* h2c://zitadel:8080
    reverse_proxy /management/v1/* h2c://zitadel:8080
    reverse_proxy /zitadel.system.v1.SystemService/* h2c://zitadel:8080
    reverse_proxy /system/v1/* h2c://zitadel:8080
    reverse_proxy /assets/v1/* h2c://zitadel:8080
    reverse_proxy /ui/* h2c://zitadel:8080
    reverse_proxy /oidc/v1/* h2c://zitadel:8080
    reverse_proxy /saml/v2/* h2c://zitadel:8080
    reverse_proxy /oauth/v2/* h2c://zitadel:8080
    reverse_proxy /.well-known/openid-configuration h2c://zitadel:8080
    reverse_proxy /openapi/* h2c://zitadel:8080
    reverse_proxy /debug/* h2c://zitadel:8080
    reverse_proxy /device/* h2c://zitadel:8080
    reverse_proxy /device h2c://zitadel:8080
    reverse_proxy /zitadel.user.v2.UserService/* h2c://zitadel:8080
    # Dashboard
    reverse_proxy /* dashboard:80
}

Füge unter folgendem Block:

:80, nb.linxuxbase.io:443 {
    import security_headers

diesen Abschnitt hinzu:

    handle_path /.well-known/webfinger {
        root * /etc/caddy/webfinger
        try_files /webfinger
        file_server
}

Das ganze sieht dann so aus:

{
  debug
        servers :80,:443 {
    protocols h1 h2c h2 h3
  }
}

(security_headers) {
    header * {
        # enable HSTS
        # https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#strict-transport-security-hsts
        # NOTE: Read carefully how this header works before using it.
        # If the HSTS header is misconfigured or if there is a problem with
        # the SSL/TLS certificate being used, legitimate users might be unable
        # to access the website. For example, if the HSTS header is set to a
        # very long duration and the SSL/TLS certificate expires or is revoked,
        # legitimate users might be unable to access the website until
        # the HSTS header duration has expired.
        # The recommended value for the max-age is 2 year (63072000 seconds).
        # But we are using 1 hour (3600 seconds) for testing purposes
        # and ensure that the website is working properly before setting
        # to two years.

        Strict-Transport-Security "max-age=3600; includeSubDomains; preload"

        # disable clients from sniffing the media type
        # https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-content-type-options
        X-Content-Type-Options "nosniff"

        # clickjacking protection
        # https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-frame-options
        X-Frame-Options "SAMEORIGIN"

        # xss protection
        # https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#x-xss-protection
        X-XSS-Protection "1; mode=block"

        # Remove -Server header, which is an information leak
        # Remove Caddy from Headers
        -Server

        # keep referrer data off of HTTP connections
        # https://cheatsheetseries.owasp.org/cheatsheets/HTTP_Headers_Cheat_Sheet.html#referrer-policy
        Referrer-Policy strict-origin-when-cross-origin
    }
}

:80, nb.linxuxbase.io:443 {
    import security_headers
    handle_path /.well-known/webfinger {
        root * /etc/caddy/webfinger
        try_files /webfinger
        file_server
}
    # relay
    reverse_proxy /relay* relay:80
    # Signal
    reverse_proxy /signalexchange.SignalExchange/* h2c://signal:10000
    # Management
    reverse_proxy /api/* management:80
    reverse_proxy /management.ManagementService/* h2c://management:80
    # Zitadel
    reverse_proxy /zitadel.admin.v1.AdminService/* h2c://zitadel:8080
    reverse_proxy /admin/v1/* h2c://zitadel:8080
    reverse_proxy /zitadel.auth.v1.AuthService/* h2c://zitadel:8080
    reverse_proxy /auth/v1/* h2c://zitadel:8080
    reverse_proxy /zitadel.management.v1.ManagementService/* h2c://zitadel:8080
    reverse_proxy /management/v1/* h2c://zitadel:8080
    reverse_proxy /zitadel.system.v1.SystemService/* h2c://zitadel:8080
    reverse_proxy /system/v1/* h2c://zitadel:8080
    reverse_proxy /assets/v1/* h2c://zitadel:8080
    reverse_proxy /ui/* h2c://zitadel:8080
    reverse_proxy /oidc/v1/* h2c://zitadel:8080
    reverse_proxy /saml/v2/* h2c://zitadel:8080
    reverse_proxy /oauth/v2/* h2c://zitadel:8080
    reverse_proxy /.well-known/openid-configuration h2c://zitadel:8080
    reverse_proxy /openapi/* h2c://zitadel:8080
    reverse_proxy /debug/* h2c://zitadel:8080
    reverse_proxy /device/* h2c://zitadel:8080
    reverse_proxy /device h2c://zitadel:8080
    reverse_proxy /zitadel.user.v2.UserService/* h2c://zitadel:8080
    # Dashboard
    reverse_proxy /* dashboard:80
}

Damit wird die Webfinger-Datei unter https://deinedomain.de/.well-known/webfinger bereitgestellt.
Das Argument try_files /webfinger ist wichtig, damit nur die Datei ausgeliefert wird. Andere Pfade unter .well-known/ (z. B. für OIDC) werden weiterhin von Zitadel genutzt.

Schritt 3: Caddy neu starten

Damit die Änderungen aktiv werden, musst du den Caddy-Container neu starten.
Liste zuerst die laufenden Container:

docker ps

root@app-a0001:~/netbird# docker ps
CONTAINER ID   IMAGE                             COMMAND                  CREATED      STATUS                PORTS                                                                                                                             NAMES
1fa0ae6125d8   ghcr.io/zitadel/zitadel:v2.64.1   "/app/zitadel start-…"   2 days ago   Up 2 days                                                                                                                                               netbird-zitadel-1
1af48ac03c8b   netbirdio/relay:latest            "/go/bin/netbird-rel…"   2 days ago   Up 2 days                                                                                                                                               netbird-relay-1
e18d05216c4b   caddy                             "caddy run --config …"   2 days ago   Up 2 days             0.0.0.0:80->80/tcp, [::]:80->80/tcp, 0.0.0.0:443->443/tcp, [::]:443->443/tcp, 0.0.0.0:443->443/udp, [::]:443->443/udp, 2019/tcp   netbird-caddy-1
a03d44931c0f   netbirdio/management:latest       "/go/bin/netbird-mgm…"   2 days ago   Up 2 days                                                                                                                                               netbird-management-1
f3c0d42b0903   netbirdio/dashboard:latest        "/usr/bin/supervisor…"   2 days ago   Up 2 days             80/tcp, 443/tcp                                                                                                                   netbird-dashboard-1
00a087562f13   coturn/coturn                     "docker-entrypoint.s…"   2 days ago   Up 2 days                                                                                                                                               netbird-coturn-1
4f4209763133   postgres:16-alpine                "docker-entrypoint.s…"   2 days ago   Up 2 days (healthy)   5432/tcp                                                                                                                          netbird-zdb-1
584ec1ffced4   netbirdio/signal:latest           "/go/bin/netbird-sig…"   2 days ago   Up 2 days                                                                                                                                               netbird-signal-1

Suche die Container-ID von Caddy (z. B. e18d05216c4b) und starte ihn neu:

docker compose restart e18d05216c4b

Hinweis: Der Befehl muss im Verzeichnis mit deiner docker-compose.yml ausgeführt werden.

Nach wenigen Sekunden sollte die Datei erreichbar sein:

https://deinedomain.de/.well-known/webfinger

Schritt 4: Tailscale mit Zitadel verbinden

Nun können wir Tailscale mit Zitadel verwenden.
Gehe dazu auf die Tailscale-Seite → „Get Started“ → „Sign up with OIDC“.

Trage hier deinen Benutzer in der Form ein:

[email protected]

In meinem Fall ist es der Admin User:

[email protected]

Damit authentifiziert sich Tailscale über deinen Zitadel-Server.

Zusammenfassung

  1. Webfinger-Datei erstellt
  2. Caddy konfiguriert
  3. Caddy-Container neu gestartet
  4. Tailscale mit Zitadel als OIDC Provider verbunden

Jetzt kannst du Tailscale mit deiner eigenen Zitadel-Installation nutzen, ganz ohne Google- oder GitHub-Account.

Anzeigen

Kommentar verfassen

Deine E-Mail-Adresse wird nicht veröffentlicht. Erforderliche Felder sind mit * markiert

Nach oben scrollen