headscale/docs/ref/oidc.md
nblock 8c7d8ee34f
Restructure headscale documentation (#2163)
* Setup mkdocs-redirects

* Restructure existing documentation

* Move client OS support into the documentation

* Move existing Client OS support table into its own documentation page
* Link from README.md to the rendered documentation
* Document minimum Tailscale client version

* Reuse CONTRIBUTING.md" in the documentation

* Include "CONTRIBUTING.md" from the repository root
* Update FAQ and index page and link to the contributing docs

* Add configuration reference

* Add a getting started page and explain the first steps with headscale

* Use the existing "Using headscale" sections and combine them into a
  single getting started guide with a little bit more explanation.
* Explain how to get help from the command line client.
* Remove duplicated sections from existing installation guides

* Document requirements and assumptions

* Document packages provided by the community

* Move deb install guide to official releases

* Move manual install guide to official releases

* Move container documentation to setup section

* Move sealos documentation to cloud install page

* Move OpenBSD docs to build from source

* Simplify DNS documentation

* Add sponsor page

* Add releases page

* Add features page

* Add help page

* Add upgrading page

* Adjust mkdocs nav

* Update wording

Use the term headscale for the project, Headscale on the beginning of a
sentence and `headscale` when refering to the CLI.

* Welcome to headscale

* Link to existing documentation in the FAQ

* Remove the goal header and use the text as opener

* Indent code block in OIDC

* Make a few pages linter compatible

Also update ignored files for prettier

* Recommend HTTPS on port 443

Fixes: #2164

* Use hosts in acl documentation

thx @efficacy38 for noticing this

Ref: #1863

* Use mkdocs-macros to set headscale version once
2024-10-10 15:24:04 +02:00

6.0 KiB
Raw Permalink Blame History

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:

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

  # 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:

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:

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 account.

Google OAuth has a verification process 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 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:
    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.