headscale
headscale copied to clipboard
[OIDC] Allowed_groups directive issue
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:


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
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.
@yaroslavkasatikov Does the aforementionned workaround for the perceived issue work for you?
Maybe this could be closed, then.
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 Could you explain a little how you got it working with Authentik?
@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".
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
}
@LEI I too would be curious to see how you got groups working with authentik
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
}
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.
Same issue with Azure AD. Doesn't seems to be working with it for the moment.
This issue is stale because it has been open for 90 days with no activity.
This issue was closed because it has been inactive for 14 days since being marked as stale.