mirror of
https://github.com/juanfont/headscale.git
synced 2025-07-19 13:38:57 -04:00
Refactor OpenID Connect documentation
Restructure and rewrite the OpenID Connect documentation. Start from the most minimal configuration and describe what needs to be done both in Headscale and the identity provider. Describe additional features such as PKCE and authorization filters in a generic manner with examples. Document how Headscale populates its user profile and how it relates to OIDC claims. This is a revised version from the table in the changelog. Document the validation rules for fields and extend known limitations. Sort the provider specific section alphabetically and add a section for Authelia, Authentik, Kanidm and Keycloak. Also simplify and rename Azure to Entra ID. Update the description for the oidc section in the example configuration. Give a short explanation of each configuration setting. All documentend features were tested with Headscale 0.26 (using a fresh database each time) using the following identity providers: * Authelia * Authentik * Kanidm * Keycloak Fixes: #2295
This commit is contained in:
parent
efc6974017
commit
d461db3abd
@ -1,4 +1,5 @@
|
||||
.github/workflows/test-integration-v2*
|
||||
docs/about/features.md
|
||||
docs/ref/configuration.md
|
||||
docs/ref/oidc.md
|
||||
docs/ref/remote-cli.md
|
||||
|
@ -14,6 +14,8 @@
|
||||
[#2614](https://github.com/juanfont/headscale/pull/2614)
|
||||
- Support client verify for DERP
|
||||
[#2046](https://github.com/juanfont/headscale/pull/2046)
|
||||
- Refactor OpenID Connect documentation
|
||||
[#2625](https://github.com/juanfont/headscale/pull/2625)
|
||||
|
||||
## 0.26.1 (2025-06-06)
|
||||
|
||||
|
@ -322,51 +322,60 @@ dns:
|
||||
# Note: for production you will want to set this to something like:
|
||||
unix_socket: /var/run/headscale/headscale.sock
|
||||
unix_socket_permission: "0770"
|
||||
#
|
||||
# headscale supports experimental OpenID connect support,
|
||||
# it is still being tested and might have some bugs, please
|
||||
# help us test it.
|
||||
|
||||
# OpenID Connect
|
||||
# oidc:
|
||||
# # Block startup until the identity provider is available and healthy.
|
||||
# only_start_if_oidc_is_available: true
|
||||
#
|
||||
# # OpenID Connect Issuer URL from the identity provider
|
||||
# issuer: "https://your-oidc.issuer.com/path"
|
||||
#
|
||||
# # Client ID from the identity provider
|
||||
# client_id: "your-oidc-client-id"
|
||||
#
|
||||
# # Client secret generated by the identity provider
|
||||
# # Note: client_secret and client_secret_path are mutually exclusive.
|
||||
# client_secret: "your-oidc-client-secret"
|
||||
# # Alternatively, set `client_secret_path` to read the secret from the file.
|
||||
# # It resolves environment variables, making integration to systemd's
|
||||
# # `LoadCredential` straightforward:
|
||||
# client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret"
|
||||
# # client_secret and client_secret_path are mutually exclusive.
|
||||
#
|
||||
# # The amount of time from a node is authenticated with OpenID until it
|
||||
# # expires and needs to reauthenticate.
|
||||
# # The amount of time a node is authenticated with OpenID until it expires
|
||||
# # and needs to reauthenticate.
|
||||
# # Setting the value to "0" will mean no expiry.
|
||||
# expiry: 180d
|
||||
#
|
||||
# # Use the expiry from the token received from OpenID when the user logged
|
||||
# # in, this will typically lead to frequent need to reauthenticate and should
|
||||
# # only been enabled if you know what you are doing.
|
||||
# # in. This will typically lead to frequent need to reauthenticate and should
|
||||
# # only be enabled if you know what you are doing.
|
||||
# # Note: enabling this will cause `oidc.expiry` to be ignored.
|
||||
# use_expiry_from_token: false
|
||||
#
|
||||
# # Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query
|
||||
# # parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email".
|
||||
# # The OIDC scopes to use, defaults to "openid", "profile" and "email".
|
||||
# # Custom scopes can be configured as needed, be sure to always include the
|
||||
# # required "openid" scope.
|
||||
# scope: ["openid", "profile", "email"]
|
||||
#
|
||||
# scope: ["openid", "profile", "email", "custom"]
|
||||
# # Provide custom key/value pairs which get sent to the identity provider's
|
||||
# # authorization endpoint.
|
||||
# extra_params:
|
||||
# domain_hint: example.com
|
||||
#
|
||||
# # List allowed principal domains and/or users. If an authenticated user's domain is not in this list, the
|
||||
# # authentication request will be rejected.
|
||||
#
|
||||
# # Only accept users whose email domain is part of the allowed_domains list.
|
||||
# allowed_domains:
|
||||
# - example.com
|
||||
# # Note: Groups from keycloak have a leading '/'
|
||||
# allowed_groups:
|
||||
# - /headscale
|
||||
#
|
||||
# # Only accept users whose email address is part of the allowed_users list.
|
||||
# allowed_users:
|
||||
# - alice@example.com
|
||||
#
|
||||
# # Only accept users which are members of at least one group in the
|
||||
# # allowed_groups list.
|
||||
# allowed_groups:
|
||||
# - /headscale
|
||||
#
|
||||
# # Optional: PKCE (Proof Key for Code Exchange) configuration
|
||||
# # PKCE adds an additional layer of security to the OAuth 2.0 authorization code flow
|
||||
# # by preventing authorization code interception attacks
|
||||
@ -374,6 +383,7 @@ unix_socket_permission: "0770"
|
||||
# pkce:
|
||||
# # Enable or disable PKCE support (default: false)
|
||||
# enabled: false
|
||||
#
|
||||
# # PKCE method to use:
|
||||
# # - plain: Use plain code verifier
|
||||
# # - S256: Use SHA256 hashed code verifier (default, recommended)
|
||||
|
@ -28,10 +28,9 @@ provides on overview of Headscale's feature and compatibility with the Tailscale
|
||||
routers](../ref/routes.md#automatically-approve-routes-of-a-subnet-router) and [exit
|
||||
nodes](../ref/routes.md#automatically-approve-an-exit-node-with-auto-approvers)
|
||||
- [x] [Tailscale SSH](https://tailscale.com/kb/1193/tailscale-ssh)
|
||||
* [ ] Node registration using Single-Sign-On (OpenID Connect) ([GitHub label "OIDC"](https://github.com/juanfont/headscale/labels/OIDC))
|
||||
* [x] [Node registration using Single-Sign-On (OpenID Connect)](../ref/oidc.md) ([GitHub label "OIDC"](https://github.com/juanfont/headscale/labels/OIDC))
|
||||
- [x] Basic registration
|
||||
- [x] Update user profile from identity provider
|
||||
- [ ] Dynamic ACL support
|
||||
- [ ] OIDC groups cannot be used in ACLs
|
||||
- [ ] [Funnel](https://tailscale.com/kb/1223/funnel) ([#1040](https://github.com/juanfont/headscale/issues/1040))
|
||||
- [ ] [Serve](https://tailscale.com/kb/1312/serve) ([#1234](https://github.com/juanfont/headscale/issues/1921))
|
||||
|
448
docs/ref/oidc.md
448
docs/ref/oidc.md
@ -1,162 +1,272 @@
|
||||
# Configuring headscale to use OIDC authentication
|
||||
# OpenID Connect
|
||||
|
||||
In order to authenticate users through a centralized solution one must enable the OIDC integration.
|
||||
Headscale supports authentication via external identity providers using OpenID Connect (OIDC). It features:
|
||||
|
||||
Known limitations:
|
||||
- Autoconfiguration via OpenID Connect Discovery Protocol
|
||||
- [Proof Key for Code Exchange (PKCE) code verification](#enable-pkce-recommended)
|
||||
- [Authorization based on a user's domain, email address or group membership](#authorize-users-with-filters)
|
||||
- Synchronization of [standard OIDC claims](#supported-oidc-claims)
|
||||
|
||||
- No dynamic ACL support
|
||||
- OIDC groups cannot be used in ACLs
|
||||
Please see [limitations](#limitations) for known issues and limitations.
|
||||
|
||||
## Basic configuration
|
||||
## Configuration
|
||||
|
||||
In your `config.yaml`, customize this to your liking:
|
||||
OpenID requires configuration in Headscale and your identity provider:
|
||||
|
||||
```yaml title="config.yaml"
|
||||
oidc:
|
||||
# Block further startup until the OIDC provider is healthy and available
|
||||
only_start_if_oidc_is_available: true
|
||||
# Specified by your OIDC provider
|
||||
issuer: "https://your-oidc.issuer.com/path"
|
||||
# Specified/generated by your OIDC provider
|
||||
client_id: "your-oidc-client-id"
|
||||
client_secret: "your-oidc-client-secret"
|
||||
# alternatively, set `client_secret_path` to read the secret from the file.
|
||||
# It resolves environment variables, making integration to systemd's
|
||||
# `LoadCredential` straightforward:
|
||||
#client_secret_path: "${CREDENTIALS_DIRECTORY}/oidc_client_secret"
|
||||
# as third option, it's also possible to load the oidc secret from environment variables
|
||||
# set HEADSCALE_OIDC_CLIENT_SECRET to the required value
|
||||
- Headscale: The `oidc` section of the Headscale [configuration](configuration.md) contains all available configuration
|
||||
options along with a description and their default values.
|
||||
- Identity provider: Please refer to the official documentation of your identity provider for specific instructions.
|
||||
Additionally, there might be some useful hints in the [Identity provider specific
|
||||
configuration](#identity-provider-specific-configuration) section below.
|
||||
|
||||
# Customize the scopes used in the OIDC flow, defaults to "openid", "profile" and "email" and add custom query
|
||||
# parameters to the Authorize Endpoint request. Scopes default to "openid", "profile" and "email".
|
||||
scope: ["openid", "profile", "email", "custom"]
|
||||
# Optional: Passed on to the browser login request – used to tweak behaviour for the OIDC provider
|
||||
extra_params:
|
||||
domain_hint: example.com
|
||||
### Basic configuration
|
||||
|
||||
# Optional: List allowed principal domains and/or users. If an authenticated user's domain is not in this list,
|
||||
# the authentication request will be rejected.
|
||||
allowed_domains:
|
||||
- example.com
|
||||
# Optional. Note that groups from Keycloak have a leading '/'.
|
||||
allowed_groups:
|
||||
- /headscale
|
||||
# Optional.
|
||||
allowed_users:
|
||||
- alice@example.com
|
||||
A basic configuration connects Headscale to an identity provider and typically requires:
|
||||
|
||||
# Optional: PKCE (Proof Key for Code Exchange) configuration
|
||||
# PKCE adds an additional layer of security to the OAuth 2.0 authorization code flow
|
||||
# by preventing authorization code interception attacks
|
||||
# See https://datatracker.ietf.org/doc/html/rfc7636
|
||||
pkce:
|
||||
# Enable or disable PKCE support (default: false)
|
||||
enabled: false
|
||||
# PKCE method to use:
|
||||
# - plain: Use plain code verifier
|
||||
# - S256: Use SHA256 hashed code verifier (default, recommended)
|
||||
method: S256
|
||||
```
|
||||
- OpenID Connect Issuer URL from the identity provider. Headscale uses the OpenID Connect Discovery Protocol 1.0 to
|
||||
automatically obtain OpenID configuration parameters (example: `https://sso.example.com`).
|
||||
- Client ID from the identity provider (example: `headscale`).
|
||||
- Client secret generated by the identity provider (example: `generated-secret`).
|
||||
- Redirect URI for your identity provider (example: `https://headscale.example.com/oidc/callback`).
|
||||
|
||||
## Azure AD example
|
||||
=== "Headscale"
|
||||
|
||||
In order to integrate headscale with Azure Active Directory, we'll need to provision an App Registration with the correct scopes and redirect URI. Here with Terraform:
|
||||
```yaml
|
||||
oidc:
|
||||
issuer: "https://sso.example.com"
|
||||
client_id: "headscale"
|
||||
client_secret: "generated-secret"
|
||||
```
|
||||
|
||||
```hcl title="terraform.hcl"
|
||||
resource "azuread_application" "headscale" {
|
||||
display_name = "Headscale"
|
||||
=== "Identity provider"
|
||||
|
||||
sign_in_audience = "AzureADMyOrg"
|
||||
fallback_public_client_enabled = false
|
||||
* Create a new confidential client (`Client ID`, `Client secret`)
|
||||
* Add Headscale's OIDC callback URL as valid redirect URL: `https://headscale.example.com/oidc/callback`
|
||||
* Configure additional parameters to improve user experience such as: name, description, logo, …
|
||||
|
||||
required_resource_access {
|
||||
// Microsoft Graph
|
||||
resource_app_id = "00000003-0000-0000-c000-000000000000"
|
||||
### Enable PKCE (recommended)
|
||||
|
||||
resource_access {
|
||||
// scope: profile
|
||||
id = "14dad69e-099b-42c9-810b-d002981feec1"
|
||||
type = "Scope"
|
||||
}
|
||||
resource_access {
|
||||
// scope: openid
|
||||
id = "37f7f235-527c-4136-accd-4a02d197296e"
|
||||
type = "Scope"
|
||||
}
|
||||
resource_access {
|
||||
// scope: email
|
||||
id = "64a6cdd6-aab1-4aaf-94b8-3cc8405e90d0"
|
||||
type = "Scope"
|
||||
}
|
||||
}
|
||||
web {
|
||||
# Points at your running headscale instance
|
||||
redirect_uris = ["https://headscale.example.com/oidc/callback"]
|
||||
Proof Key for Code Exchange (PKCE) adds an additional layer of security to the OAuth 2.0 authorization code flow by
|
||||
preventing authorization code interception attacks, see: <https://datatracker.ietf.org/doc/html/rfc7636>. PKCE is
|
||||
recommended and needs to be configured for Headscale and the identity provider alike:
|
||||
|
||||
implicit_grant {
|
||||
access_token_issuance_enabled = false
|
||||
id_token_issuance_enabled = true
|
||||
}
|
||||
}
|
||||
=== "Headscale"
|
||||
|
||||
group_membership_claims = ["SecurityGroup"]
|
||||
optional_claims {
|
||||
# Expose group memberships
|
||||
id_token {
|
||||
name = "groups"
|
||||
}
|
||||
}
|
||||
}
|
||||
```yaml hl_lines="5-6"
|
||||
oidc:
|
||||
issuer: "https://sso.example.com"
|
||||
client_id: "headscale"
|
||||
client_secret: "generated-secret"
|
||||
pkce:
|
||||
enabled: true
|
||||
```
|
||||
|
||||
resource "azuread_application_password" "headscale-application-secret" {
|
||||
display_name = "Headscale Server"
|
||||
application_object_id = azuread_application.headscale.object_id
|
||||
}
|
||||
=== "Identity provider"
|
||||
|
||||
resource "azuread_service_principal" "headscale" {
|
||||
application_id = azuread_application.headscale.application_id
|
||||
}
|
||||
* Enable PKCE for the headscale client
|
||||
* Set the PKCE challenge method to "S256"
|
||||
|
||||
resource "azuread_service_principal_password" "headscale" {
|
||||
service_principal_id = azuread_service_principal.headscale.id
|
||||
end_date_relative = "44640h"
|
||||
}
|
||||
### Authorize users with filters
|
||||
|
||||
output "headscale_client_id" {
|
||||
value = azuread_application.headscale.application_id
|
||||
}
|
||||
Headscale allows to filter for allowed users based on their domain, email address or group membership. These filters can
|
||||
be helpful to apply additional restrictions and control which users are allowed to join. Filters are disabled by
|
||||
default, users are allowed to join once the authentication with the identity provider succeeds. In case multiple filters
|
||||
are configured, a user needs to pass all of them.
|
||||
|
||||
output "headscale_client_secret" {
|
||||
value = azuread_application_password.headscale-application-secret.value
|
||||
}
|
||||
```
|
||||
=== "Allowed domains"
|
||||
|
||||
And in your headscale `config.yaml`:
|
||||
* Check the email domain of each authenticating user against the list of allowed domains and only authorize users
|
||||
whose email domain matches `example.com`.
|
||||
* Access allowed: `alice@example.com`
|
||||
* Access denied: `bob@example.net`
|
||||
|
||||
```yaml title="config.yaml"
|
||||
oidc:
|
||||
issuer: "https://login.microsoftonline.com/<tenant-UUID>/v2.0"
|
||||
client_id: "<client-id-from-terraform>"
|
||||
client_secret: "<client-secret-from-terraform>"
|
||||
```yaml hl_lines="5-6"
|
||||
oidc:
|
||||
issuer: "https://sso.example.com"
|
||||
client_id: "headscale"
|
||||
client_secret: "generated-secret"
|
||||
allowed_domains:
|
||||
- "example.com"
|
||||
```
|
||||
|
||||
# Optional: add "groups"
|
||||
scope: ["openid", "profile", "email"]
|
||||
extra_params:
|
||||
# Use your own domain, associated with Azure AD
|
||||
domain_hint: example.com
|
||||
# Optional: Force the Azure AD account picker
|
||||
prompt: select_account
|
||||
```
|
||||
=== "Allowed users/emails"
|
||||
|
||||
## Google OAuth Example
|
||||
* Check the email address of each authenticating user against the list of allowed email addresses and only authorize
|
||||
users whose email is part of the `allowed_users` list.
|
||||
* Access allowed: `alice@example.com`, `bob@example.net`
|
||||
* Access denied: `mallory@example.net`
|
||||
|
||||
In order to integrate headscale with Google, you'll need to have a [Google Cloud Console](https://console.cloud.google.com) account.
|
||||
```yaml hl_lines="5-7"
|
||||
oidc:
|
||||
issuer: "https://sso.example.com"
|
||||
client_id: "headscale"
|
||||
client_secret: "generated-secret"
|
||||
allowed_users:
|
||||
- "alice@example.com"
|
||||
- "bob@example.net"
|
||||
```
|
||||
|
||||
Google OAuth has a [verification process](https://support.google.com/cloud/answer/9110914?hl=en) if you need to have users authenticate who are outside of your domain. If you only need to authenticate users from your domain name (ie `@example.com`), you don't need to go through the verification process.
|
||||
=== "Allowed groups"
|
||||
|
||||
However if you don't have a domain, or need to add users outside of your domain, you can manually add emails via Google Console.
|
||||
* Use the OIDC `groups` claim of each authenticating user to get their group membership and only authorize users
|
||||
which are members in at least one of the referenced groups.
|
||||
* Access allowed: users in the `headscale_users` group
|
||||
* Access denied: users without groups, users with other groups
|
||||
|
||||
### Steps
|
||||
```yaml hl_lines="5-7"
|
||||
oidc:
|
||||
issuer: "https://sso.example.com"
|
||||
client_id: "headscale"
|
||||
client_secret: "generated-secret"
|
||||
scope: ["openid", "profile", "email", "groups"]
|
||||
allowed_groups:
|
||||
- "headscale_users"
|
||||
```
|
||||
|
||||
### Customize node expiration
|
||||
|
||||
The node expiration is the amount of time a node is authenticated with OpenID Connect until it expires and needs to
|
||||
reauthenticate. The default node expiration is 180 days. This can either be customized or set to the expiration from the
|
||||
Access Token.
|
||||
|
||||
=== "Customize node expiration"
|
||||
|
||||
```yaml hl_lines="5"
|
||||
oidc:
|
||||
issuer: "https://sso.example.com"
|
||||
client_id: "headscale"
|
||||
client_secret: "generated-secret"
|
||||
expiry: 30d # Use 0 to disable node expiration
|
||||
```
|
||||
|
||||
=== "Use expiration from Access Token"
|
||||
|
||||
Please keep in mind that the Access Token is typically a short-lived token that expires within a few minutes. You
|
||||
will have to configure token expiration in your identity provider to avoid frequent reauthentication.
|
||||
|
||||
|
||||
```yaml hl_lines="5"
|
||||
oidc:
|
||||
issuer: "https://sso.example.com"
|
||||
client_id: "headscale"
|
||||
client_secret: "generated-secret"
|
||||
use_expiry_from_token: true
|
||||
```
|
||||
|
||||
!!! tip "Expire a node and force re-authentication"
|
||||
|
||||
A node can be expired immediately via:
|
||||
```console
|
||||
headscale node expire -i <NODE_ID>
|
||||
```
|
||||
|
||||
### Reference a user in the policy
|
||||
|
||||
You may refer to users in the Headscale policy via:
|
||||
|
||||
- Email address
|
||||
- Username
|
||||
- Provider identifier (only available in the database or from your identity provider)
|
||||
|
||||
!!! note "A user identifier in the policy must contain a single `@`"
|
||||
|
||||
The Headscale policy requires a single `@` to reference a user. If the username or provider identifier doesn't
|
||||
already contain a single `@`, it needs to be appended at the end. For example: the username `ssmith` has to be
|
||||
written as `ssmith@` to be correctly identified as user within the policy.
|
||||
|
||||
!!! warning "Email address or username might be updated by users"
|
||||
|
||||
Many identity providers allow users to update their own profile. Depending on the identity provider and its
|
||||
configuration, the values for username or email address might change over time. This might have unexpected
|
||||
consequences for Headscale where a policy might no longer work or a user might obtain more access by hijacking an
|
||||
existing username or email address.
|
||||
|
||||
## Supported OIDC claims
|
||||
|
||||
Headscale uses [the standard OIDC claims](https://openid.net/specs/openid-connect-core-1_0.html#StandardClaims) to
|
||||
populate and update its local user profile on each login. OIDC claims are read from the ID Token or from the UserInfo
|
||||
endpoint.
|
||||
|
||||
| Headscale profile | OIDC claim | Notes / examples |
|
||||
| ------------------- | -------------------- | ------------------------------------------------------------------------------------------------- |
|
||||
| email address | `email` | Only used when `email_verified: true` |
|
||||
| display name | `name` | eg: `Sam Smith` |
|
||||
| username | `preferred_username` | Depends on identity provider, eg: `ssmith`, `ssmith@idp.example.com`, `\\example.com\ssmith` |
|
||||
| profile picture | `picture` | URL to a profile picture or avatar |
|
||||
| provider identifier | `iss`, `sub` | A stable and unique identifier for a user, typically a combination of `iss` and `sub` OIDC claims |
|
||||
| | `groups` | [Only used to filter for allowed groups](#authorize-users-with-filters) |
|
||||
|
||||
## Limitations
|
||||
|
||||
- Support for OpenID Connect aims to be generic and vendor independent. It offers only limited support for quirks of
|
||||
specific identity providers.
|
||||
- OIDC groups cannot be used in ACLs.
|
||||
- The username provided by the identity provider needs to adhere to this pattern:
|
||||
- The username must be at least two characters long.
|
||||
- It must only contain letters, digits, hyphens, dots, underscores, and up to a single `@`.
|
||||
- The username must start with a letter.
|
||||
- A user's email address is only synchronized to the local user profile when the identity provider marks the email
|
||||
address as verified (`email_verified: true`).
|
||||
|
||||
Please see the [GitHub label "OIDC"](https://github.com/juanfont/headscale/labels/OIDC) for OIDC related issues.
|
||||
|
||||
## Identity provider specific configuration
|
||||
|
||||
!!! warning "Third-party software and services"
|
||||
|
||||
This section of the documentation is specific for third-party software and services. We recommend users read the
|
||||
third-party documentation on how to configure and integrate an OIDC client. Please see the [Configuration
|
||||
section](#configuration) for a description of Headscale's OIDC related configuration settings.
|
||||
|
||||
Any identity provider with OpenID Connect support should "just work" with Headscale. The following identity providers
|
||||
are known to work:
|
||||
|
||||
- [Authelia](#authelia)
|
||||
- [Authentik](#authentik)
|
||||
- [Kanidm](#kanidm)
|
||||
- [Keycloak](#keycloak)
|
||||
|
||||
### Authelia
|
||||
|
||||
Authelia is fully supported by Headscale.
|
||||
|
||||
#### Additional configuration to authorize users based on filters
|
||||
|
||||
Authelia (4.39.0 or newer) no longer provides standard OIDC claims such as `email` or `groups` via the ID Token. The
|
||||
OIDC `email` and `groups` claims are used to [authorize users with filters](#authorize-users-with-filters). This extra
|
||||
configuration step is **only** needed if you need to authorize access based on one of the following user properties:
|
||||
|
||||
- domain
|
||||
- email address
|
||||
- group membership
|
||||
|
||||
Please follow the instructions from Authelia's documentation on how to [Restore Functionality Prior to Claims
|
||||
Parameter](https://www.authelia.com/integration/openid-connect/openid-connect-1.0-claims/#restore-functionality-prior-to-claims-parameter).
|
||||
|
||||
### Authentik
|
||||
|
||||
- Authentik is fully supported by Headscale.
|
||||
- [Headscale does not JSON Web Encryption](https://github.com/juanfont/headscale/issues/2446). Leave the field
|
||||
`Encryption Key` in the providers section unset.
|
||||
|
||||
### Google OAuth
|
||||
|
||||
!!! warning "No username due to missing preferred_username"
|
||||
|
||||
Google OAuth does not send the `preferred_username` claim when the scope `profile` is requested. The username in
|
||||
Headscale will be blank/not set.
|
||||
|
||||
In order to integrate Headscale with Google, you'll need to have a [Google Cloud
|
||||
Console](https://console.cloud.google.com) account.
|
||||
|
||||
Google OAuth has a [verification process](https://support.google.com/cloud/answer/9110914?hl=en) if you need to have
|
||||
users authenticate who are outside of your domain. If you only need to authenticate users from your domain name (ie
|
||||
`@example.com`), you don't need to go through the verification process.
|
||||
|
||||
However if you don't have a domain, or need to add users outside of your domain, you can manually add emails via Google
|
||||
Console.
|
||||
|
||||
#### Steps
|
||||
|
||||
1. Go to [Google Console](https://console.cloud.google.com) and login or create an account if you don't have one.
|
||||
2. Create a project (if you don't already have one).
|
||||
@ -164,58 +274,44 @@ However if you don't have a domain, or need to add users outside of your domain,
|
||||
4. Click `Create Credentials` -> `OAuth client ID`
|
||||
5. Under `Application Type`, choose `Web Application`
|
||||
6. For `Name`, enter whatever you like
|
||||
7. Under `Authorised redirect URIs`, use `https://example.com/oidc/callback`, replacing example.com with your headscale URL.
|
||||
7. Under `Authorised redirect URIs`, add Headscale's OIDC callback URL: `https://headscale.example.com/oidc/callback`
|
||||
8. Click `Save` at the bottom of the form
|
||||
9. Take note of the `Client ID` and `Client secret`, you can also download it for reference if you need it.
|
||||
10. Edit your headscale config, under `oidc`, filling in your `client_id` and `client_secret`:
|
||||
```yaml title="config.yaml"
|
||||
oidc:
|
||||
issuer: "https://accounts.google.com"
|
||||
client_id: ""
|
||||
client_secret: ""
|
||||
scope: ["openid", "profile", "email"]
|
||||
```
|
||||
10. [Configure Headscale following the "Basic configuration" steps](#basic-configuration). The issuer URL for Google
|
||||
OAuth is: `https://accounts.google.com`.
|
||||
|
||||
You can also use `allowed_domains` and `allowed_users` to restrict the users who can authenticate.
|
||||
### Kanidm
|
||||
|
||||
## Authelia
|
||||
- Kanidm is fully supported by Headscale.
|
||||
- Groups for the [allowed groups filter](#authorize-users-with-filters) need to be specified with their full SPN, for
|
||||
example: `headscale_users@sso.example.com`.
|
||||
|
||||
Authelia since v4.39.0, has removed most claims from the `ID Token`, they are still available when application queries [UserInfo Endpoint](https://openid.net/specs/openid-connect-core-1_0.html#UserInfo).
|
||||
### Keycloak
|
||||
|
||||
Following config restores sending 'default' claims in the `ID Token`
|
||||
Keycloak is fully supported by Headscale.
|
||||
|
||||
For more information please read: [Authelia restore functionality prior to claims parameter](https://www.authelia.com/integration/openid-connect/openid-connect-1.0-claims/#restore-functionality-prior-to-claims-parameter)
|
||||
#### Additional configuration to use the allowed groups filter
|
||||
|
||||
```yaml
|
||||
identity_providers:
|
||||
oidc:
|
||||
claims_policies:
|
||||
default:
|
||||
id_token:
|
||||
[
|
||||
"groups",
|
||||
"email",
|
||||
"email_verified",
|
||||
"alt_emails",
|
||||
"preferred_username",
|
||||
"name",
|
||||
]
|
||||
clients:
|
||||
- client_id: "headscale"
|
||||
client_name: "headscale"
|
||||
client_secret: ""
|
||||
public: false
|
||||
claims_policy: "default"
|
||||
authorization_policy: "two_factor"
|
||||
require_pkce: true
|
||||
pkce_challenge_method: "S256"
|
||||
redirect_uris:
|
||||
- "https://headscale.example.com/oidc/callback"
|
||||
scopes:
|
||||
- "openid"
|
||||
- "profile"
|
||||
- "groups"
|
||||
- "email"
|
||||
userinfo_signed_response_alg: "none"
|
||||
token_endpoint_auth_method: "client_secret_basic"
|
||||
```
|
||||
Keycloak has no built-in client scope for the OIDC `groups` claim. This extra configuration step is **only** needed if
|
||||
you need to [authorize access based on group membership](#authorize-users-with-filters).
|
||||
|
||||
- Create a new client scope `groups` for OpenID Connect:
|
||||
- Configure a `Group Membership` mapper with name `groups` and the token claim name `groups`.
|
||||
- Enable the mapper for the ID Token, Access Token and UserInfo endpoint.
|
||||
- Configure the new client scope for your Headscale client:
|
||||
- Edit the Headscale client.
|
||||
- Search for the client scope `group`.
|
||||
- Add it with assigned type `Default`.
|
||||
- [Configure the allowed groups in Headscale](#authorize-users-with-filters). Keep in mind that groups in Keycloak start
|
||||
with a leading `/`.
|
||||
|
||||
### Microsoft Entra ID
|
||||
|
||||
In order to integrate Headscale with Microsoft Entra ID, you'll need to provision an App Registration with the correct
|
||||
scopes and redirect URI.
|
||||
|
||||
[Configure Headscale following the "Basic configuration" steps](#basic-configuration). The issuer URL for Microsoft
|
||||
Entra ID is: `https://login.microsoftonline.com/<tenant-UUID>/v2.0`. The following `extra_params` might be useful:
|
||||
|
||||
- `domain_hint: example.com` to use your own domain
|
||||
- `prompt: select_account` to force an account picker during login
|
||||
|
@ -176,7 +176,7 @@ nav:
|
||||
- Windows: usage/connect/windows.md
|
||||
- Reference:
|
||||
- Configuration: ref/configuration.md
|
||||
- OIDC authentication: ref/oidc.md
|
||||
- OpenID Connect: ref/oidc.md
|
||||
- Routes: ref/routes.md
|
||||
- TLS: ref/tls.md
|
||||
- ACLs: ref/acls.md
|
||||
|
Loading…
x
Reference in New Issue
Block a user