headscale icon indicating copy to clipboard operation
headscale copied to clipboard

[OIDC] Allowed_groups directive issue

Open yaroslavkasatikov opened this issue 1 year ago • 10 comments

Hey team,

I faced with the issue while testing new allowed_groups directive. I have tried to use it with auth0 and Keycloak, but received unauthorized principal (allowed groups) and an error in Headscale log.

2023-01-03T18:38:46Z ERR authenticated principal not in any allowed groups

My oidc config in config.yaml:

Keycloak version:

   oidc:
      client_id: headscale
      client_secret: xxxxxxxxxx
      enabled: true
      issuer: http://keycloak.tld/realms/headscale
      only_start_if_oidc_is_available: true
      scope:
      - openid
      - profile
      - email
      strip_email_domain: true
      allowed_groups:
      - /headscale
      

auth0.com Version:

  oidc:
      client_id: 7zxh8KmXXXXXXXXXXXX
      client_secret: X-2AYCpXXXXXXXXXXXXXs-od3
      enabled: true
      issuer: https://dev-r4uxxxxxxxxx.us.auth0.com/
      only_start_if_oidc_is_available: true
      scope:
      - openid
      - profile
      - email
      strip_email_domain: true
      allowed_groups:
      - headscale
      - /headscale ### Added just in case if auth0 needs leading slash too

Some screnshots from Keycloak and auth0:

image image

yaroslavkasatikov avatar Jan 03 '23 21:01 yaroslavkasatikov

Tried to upgrade up to beta3, but the same issue. Also got sometime SIGSEGV on container start:

[yaroslav@yaroslav-new templates]$ oc logs hs2-headscale-5699fbd96d-k66kz -p -c headscale
2023-01-06T14:05:19Z INF Setting up a DERPMap update worker frequency=86400000
2023-01-06T14:05:19Z WRN Listening without TLS but ServerURL does not start with http://
2023-01-06T14:05:19Z INF listening and serving HTTP on: 0.0.0.0:8080
2023-01-06T14:05:19Z INF listening and serving metrics on: 0.0.0.0:9090
panic: runtime error: invalid memory address or nil pointer dereference
[signal SIGSEGV: segmentation violation code=0x1 addr=0x58 pc=0xfc87e2]

goroutine 119 [running]:
github.com/puzpuzpuz/xsync/v2.(*MapOf[...]).Load(0x0?, {0xc0006d00f0?, 0x15})
        /go/pkg/mod/github.com/puzpuzpuz/xsync/[email protected]/mapof.go:154 +0x22
github.com/juanfont/headscale.(*Headscale).getLastStateChange(0xc000185980, {0xc000641be0?, 0x1, 0xc0006acc00?})
        /go/src/headscale/app.go:934 +0x29a
github.com/juanfont/headscale.(*Headscale).expireExpiredMachinesWorker(0xc000185980?)
        /go/src/headscale/app.go:306 +0x330
github.com/juanfont/headscale.(*Headscale).expireExpiredMachines(0x566bca?, 0x1c?)
        /go/src/headscale/app.go:225 +0x5b
created by github.com/juanfont/headscale.(*Headscale).Serve
        /go/src/headscale/app.go:552 +0x310

yaroslavkasatikov avatar Jan 06 '23 14:01 yaroslavkasatikov

This is not a bug and rather a configuration issue.

The following works for Keycloak (tested as of version 20.0.3):

  • Create your headscale client in keycloak
  • Go to client configuration, roles tab
  • Add a role (e.g allow_access)
  • Go to client scopes tab, click the dedicated client scope config, add new mapper, from predefined mappers, choose client roles
  • Change client ID to the same as your headscale client ID, change token claim name to groups, make sure add to ID token is checked
  • Go to groups in Keycloak config, create a new group that will have access to headscale, in group config go to role mapping, select the role that you added to the headscale client. Add your keycloak user to be part of the group.
  • Make sure the id token is valid, go back to your headscale client, client scopes tab, click the "evaluate" tab, choose your user from the dropdown, go to "generated ID token" and you should see:
  "groups": [
    "allow_access"
  ],

(or whatever the name of your role is)

Your headscale config can then be e.g:

oidc:
  allowed_groups:
  - allow_access

No need for the leading slash.

madjam002 avatar Feb 14 '23 13:02 madjam002

@yaroslavkasatikov Does the aforementionned workaround for the perceived issue work for you?

Maybe this could be closed, then.

almereyda avatar Sep 13 '23 21:09 almereyda

I was facing the same error with Authentik, creating a group bind policy had no effect. Removing the leading slash seems to be the solution, maybe the basic configuration example could be updated in the documentation.

LEI avatar Oct 07 '23 16:10 LEI

@LEI Could you explain a little how you got it working with Authentik?

NiklasRosenstein avatar Oct 18 '23 01:10 NiklasRosenstein

@madjam002 Thanks for this, it worked! After some more investigating, I found it a bit easier to set it up with a "group membership mapper".

image

image

And you can turn off "Full group path" off to remove the leading / from the group name in the groups claim.

As that may be helpful to some as well, the Terraform code I'm using to create this configuration is:


resource "keycloak_openid_group_membership_protocol_mapper" "group_membership_mapper" {
  realm_id            = keycloak_realm.main.id
  client_id           = keycloak_openid_client.headscale.id
  name                = "group membership mapper"
  claim_name          = "groups"
  add_to_id_token     = true
  add_to_access_token = true
  add_to_userinfo     = true
  full_path           = true
}

NiklasRosenstein avatar Oct 18 '23 22:10 NiklasRosenstein

@LEI I too would be curious to see how you got groups working with authentik

SirBomble avatar Nov 06 '23 16:11 SirBomble

To get it working I changed the issuer and removed the leading slash from the configuration:

server_url: https://headscale.example.com:443
# ...
oidc:
  only_start_if_oidc_is_available: true
  issuer: "https://authentik.example.com/application/o/headscale/"
  client_id: "headscale"
  client_secret: "..."
  scope: ["openid", "profile", "email"]
  extra_params:
    domain_hint: example.com
  allowed_domains:
    - example.com
  allowed_groups:
    - headscale
  strip_email_domain: true

OIDC authentication required the scope mapping to be correctly defined, the group part is relatively simple:

data "authentik_certificate_key_pair" "generated" {
  name = "authentik Self-signed Certificate"
}

data "authentik_flow" "default" {
  slug = "default-authentication-flow"
}

data "authentik_group" "admins" {
  name = "authentik Admins"
}

resource "authentik_group" "headscale" {
  name = "headscale"
}

resource "authentik_user" "example" {
  username = "example"
  name     = "Example"
  groups = [
    data.authentik_group.admins.id,
    authentik_group.headscale.id,
  ]
}

data "authentik_scope_mapping" "openid" {
  managed_list = [
    "goauthentik.io/providers/oauth2/scope-email",
    "goauthentik.io/providers/oauth2/scope-openid",
    "goauthentik.io/providers/oauth2/scope-profile",
  ]
}

resource "authentik_provider_oauth2" "headscale" {
  name                  = "headscale"
  client_id             = "headscale"
  authorization_flow    = data.authentik_flow.default.id
  access_token_validity = "minutes=5"
  property_mappings     = data.authentik_scope_mapping.openid.ids
  redirect_uris = [
    "https://headscale.example.com:443/oidc/callback"
  ]
  signing_key = data.authentik_certificate_key_pair.generated.id
}

resource "authentik_application" "headscale" {
  name              = "Headscale"
  slug              = "headscale"
  protocol_provider = authentik_provider_oauth2.headscale.id
}

LEI avatar Nov 06 '23 18:11 LEI

Any example of configuration on Azure AD? I am configuring the integration based on https://headscale.net/oidc/#azure-ad-example

And there is the same error: "Unauthorised principal (allowed groups)"

Without "allowed_groups" it works. But I want groups. I tried with "/" and without.

kfkawalec avatar Dec 14 '23 18:12 kfkawalec

Same issue with Azure AD. Doesn't seems to be working with it for the moment.

deepbluemussel avatar Jan 09 '24 16:01 deepbluemussel

This issue is stale because it has been open for 90 days with no activity.

github-actions[bot] avatar Apr 09 '24 01:04 github-actions[bot]

This issue was closed because it has been inactive for 14 days since being marked as stale.

github-actions[bot] avatar Apr 16 '24 01:04 github-actions[bot]