9d58489903
Some identity providers (auth0 for example) do not allow to set the groups claims and administrators must use custom claims names and add them in the id token. This commit adds the following configuration options: - `oidc.groups_claim` to set the groups claim name - `oidc.email_claim` to set the email claim name All claims default to the previous values for backwards compatibility. The groups claim can now also accept `[]string` or `string` as some providers might return only a string response instead of array.
177 lines
6.1 KiB
Markdown
177 lines
6.1 KiB
Markdown
# Configuring Headscale to use OIDC authentication
|
||
|
||
In order to authenticate users through a centralized solution one must enable the OIDC integration.
|
||
|
||
Known limitations:
|
||
|
||
- No dynamic ACL support
|
||
- OIDC groups cannot be used in ACLs
|
||
|
||
## Basic configuration
|
||
|
||
In your `config.yaml`, customize this to your liking:
|
||
|
||
```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"
|
||
# If provided, the name of a custom OIDC claim for specifying user groups.
|
||
# The claim value is expected to be a string or array of strings.
|
||
groups_claim: groups
|
||
# The OIDC claim to use as the email.
|
||
email_claim: email
|
||
|
||
# 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
|
||
|
||
# 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
|
||
|
||
# If `strip_email_domain` is set to `true`, the domain part of the username email address will be removed.
|
||
# This will transform `first-name.last-name@example.com` to the user `first-name.last-name`
|
||
# If `strip_email_domain` is set to `false` the domain part will NOT be removed resulting to the following
|
||
# user: `first-name.last-name.example.com`
|
||
strip_email_domain: true
|
||
```
|
||
|
||
## Azure AD example
|
||
|
||
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:
|
||
|
||
```hcl
|
||
resource "azuread_application" "headscale" {
|
||
display_name = "Headscale"
|
||
|
||
sign_in_audience = "AzureADMyOrg"
|
||
fallback_public_client_enabled = false
|
||
|
||
required_resource_access {
|
||
// Microsoft Graph
|
||
resource_app_id = "00000003-0000-0000-c000-000000000000"
|
||
|
||
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"]
|
||
|
||
implicit_grant {
|
||
access_token_issuance_enabled = false
|
||
id_token_issuance_enabled = true
|
||
}
|
||
}
|
||
|
||
group_membership_claims = ["SecurityGroup"]
|
||
optional_claims {
|
||
# Expose group memberships
|
||
id_token {
|
||
name = "groups"
|
||
}
|
||
}
|
||
}
|
||
|
||
resource "azuread_application_password" "headscale-application-secret" {
|
||
display_name = "Headscale Server"
|
||
application_object_id = azuread_application.headscale.object_id
|
||
}
|
||
|
||
resource "azuread_service_principal" "headscale" {
|
||
application_id = azuread_application.headscale.application_id
|
||
}
|
||
|
||
resource "azuread_service_principal_password" "headscale" {
|
||
service_principal_id = azuread_service_principal.headscale.id
|
||
end_date_relative = "44640h"
|
||
}
|
||
|
||
output "headscale_client_id" {
|
||
value = azuread_application.headscale.application_id
|
||
}
|
||
|
||
output "headscale_client_secret" {
|
||
value = azuread_application_password.headscale-application-secret.value
|
||
}
|
||
```
|
||
|
||
And in your Headscale `config.yaml`:
|
||
|
||
```yaml
|
||
oidc:
|
||
issuer: "https://login.microsoftonline.com/<tenant-UUID>/v2.0"
|
||
client_id: "<client-id-from-terraform>"
|
||
client_secret: "<client-secret-from-terraform>"
|
||
|
||
# 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
|
||
```
|
||
|
||
## Google OAuth Example
|
||
|
||
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).
|
||
3. On the left hand menu, go to `APIs and services` -> `Credentials`
|
||
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.
|
||
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
|
||
oidc:
|
||
issuer: "https://accounts.google.com"
|
||
client_id: ""
|
||
client_secret: ""
|
||
scope: ["openid", "profile", "email"]
|
||
```
|
||
|
||
You can also use `allowed_domains` and `allowed_users` to restrict the users who can authenticate.
|