mirror of
https://github.com/juanfont/headscale.git
synced 2026-01-11 20:00:28 +01:00
[Bug] EntraID OIDC - ACLs not being applied to OIDC registered users #922
Closed
opened 2025-12-29 02:26:08 +01:00 by adam
·
32 comments
No Branch/Tag Specified
main
update_flake_lock_action
gh-pages
kradalby/release-v0.27.2
dependabot/go_modules/golang.org/x/crypto-0.45.0
dependabot/go_modules/github.com/opencontainers/runc-1.3.3
copilot/investigate-headscale-issue-2788
copilot/investigate-visibility-issue-2788
copilot/investigate-issue-2833
copilot/debug-issue-2846
copilot/fix-issue-2847
dependabot/go_modules/github.com/go-viper/mapstructure/v2-2.4.0
dependabot/go_modules/github.com/docker/docker-28.3.3incompatible
kradalby/cli-experiement3
doc/0.26.1
doc/0.25.1
doc/0.25.0
doc/0.24.3
doc/0.24.2
doc/0.24.1
doc/0.24.0
kradalby/build-docker-on-pr
topic/docu-versioning
topic/docker-kos
juanfont/fix-crash-node-id
juanfont/better-disclaimer
update-contributors
topic/prettier
revert-1893-add-test-stage-to-docs
add-test-stage-to-docs
remove-node-check-interval
fix-empty-prefix
fix-ephemeral-reusable
bug_report-debuginfo
autogroups
logs-to-stderr
revert-1414-topic/fix_unix_socket
rename-machine-node
port-embedded-derp-tests-v2
port-derp-tests
duplicate-word-linter
update-tailscale-1.36
warn-against-apache
ko-fi-link
more-acl-tests
fix-typo-standalone
parallel-nolint
tparallel-fix
rerouting
ssh-changelog-docs
oidc-cleanup
web-auth-flow-tests
kradalby-gh-runner
fix-proto-lint
remove-funding-links
go-1.19
enable-1.30-in-tests
0.16.x
cosmetic-changes-integration
tmp-fix-integration-docker
fix-integration-docker
configurable-update-interval
show-nodes-online
hs2021
acl-syntax-fixes
ts2021-implementation
fix-spurious-updates
unstable-integration-tests
mandatory-stun
embedded-derp
prtemplate-fix
v0.28.0-beta.1
v0.27.2-rc.1
v0.27.1
v0.27.0
v0.27.0-beta.2
v0.27.0-beta.1
v0.26.1
v0.26.0
v0.26.0-beta.2
v0.26.0-beta.1
v0.25.1
v0.25.0
v0.25.0-beta.2
v0.24.3
v0.25.0-beta.1
v0.24.2
v0.24.1
v0.24.0
v0.24.0-beta.2
v0.24.0-beta.1
v0.23.0
v0.23.0-rc.1
v0.23.0-beta.5
v0.23.0-beta.4
v0.23.0-beta3
v0.23.0-beta2
v0.23.0-beta1
v0.23.0-alpha12
v0.23.0-alpha11
v0.23.0-alpha10
v0.23.0-alpha9
v0.23.0-alpha8
v0.23.0-alpha7
v0.23.0-alpha6
v0.23.0-alpha5
v0.23.0-alpha4
v0.23.0-alpha4-docker-ko-test9
v0.23.0-alpha4-docker-ko-test8
v0.23.0-alpha4-docker-ko-test7
v0.23.0-alpha4-docker-ko-test6
v0.23.0-alpha4-docker-ko-test5
v0.23.0-alpha-docker-release-test-debug2
v0.23.0-alpha-docker-release-test-debug
v0.23.0-alpha4-docker-ko-test4
v0.23.0-alpha4-docker-ko-test3
v0.23.0-alpha4-docker-ko-test2
v0.23.0-alpha4-docker-ko-test
v0.23.0-alpha3
v0.23.0-alpha2
v0.23.0-alpha1
v0.22.3
v0.22.2
v0.23.0-alpha-docker-release-test
v0.22.1
v0.22.0
v0.22.0-alpha3
v0.22.0-alpha2
v0.22.0-alpha1
v0.22.0-nfpmtest
v0.21.0
v0.20.0
v0.19.0
v0.19.0-beta2
v0.19.0-beta1
v0.18.0
v0.18.0-beta4
v0.18.0-beta3
v0.18.0-beta2
v0.18.0-beta1
v0.17.1
v0.17.0
v0.17.0-beta5
v0.17.0-beta4
v0.17.0-beta3
v0.17.0-beta2
v0.17.0-beta1
v0.17.0-alpha4
v0.17.0-alpha3
v0.17.0-alpha2
v0.17.0-alpha1
v0.16.4
v0.16.3
v0.16.2
v0.16.1
v0.16.0
v0.16.0-beta7
v0.16.0-beta6
v0.16.0-beta5
v0.16.0-beta4
v0.16.0-beta3
v0.16.0-beta2
v0.16.0-beta1
v0.15.0
v0.15.0-beta6
v0.15.0-beta5
v0.15.0-beta4
v0.15.0-beta3
v0.15.0-beta2
v0.15.0-beta1
v0.14.0
v0.14.0-beta2
v0.14.0-beta1
v0.13.0
v0.13.0-beta3
v0.13.0-beta2
v0.13.0-beta1
upstream/v0.12.4
v0.12.4
v0.12.3
v0.12.2
v0.12.2-beta1
v0.12.1
v0.12.0-beta2
v0.12.0-beta1
v0.11.0
v0.10.8
v0.10.7
v0.10.6
v0.10.5
v0.10.4
v0.10.3
v0.10.2
v0.10.1
v0.10.0
v0.9.3
v0.9.2
v0.9.1
v0.9.0
v0.8.1
v0.8.0
v0.7.1
v0.7.0
v0.6.1
v0.6.0
v0.5.2
v0.5.1
v0.5.0
v0.4.0
v0.3.6
v0.3.5
v0.3.4
v0.3.3
v0.3.2
v0.3.1
v0.3.0
v0.2.2
v0.2.1
v0.2.0
v0.1.1
v0.1.0
Labels
Clear labels
CLI
DERP
DNS
Nix
OIDC
SSH
bug
database
documentation
duplicate
enhancement
faq
good first issue
grants
help wanted
might-come
needs design doc
needs investigation
no-stale-bot
out of scope
performance
policy 📝
pull-request
question
regression
routes
stale
tags
tailscale-feature-gap
well described ❤️
wontfix
Mirrored from GitHub Pull Request
No Label
bug
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: starred/headscale#922
Reference in New Issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Originally created by @SysAdminSmith on GitHub (Jan 25, 2025).
Is this a support request?
Is there an existing issue for this?
Current Behavior
Users register via Entra ID OIDC. They are granted access by virtue of Security Group membership. When they login for the first time they are assigned a User ID, and their Name and Username are registered. The username is their EntraID email address (i.e. user@foo.bar). I have also created a local user (node.mgr) to manager subnet nodes and exit nodes. This user has an ID and username only (node.mgr).
When the default Allow All from All policy is in place all users can receive subnet routes, exit node routes, and have access to the DNS server.
However, when implementing the following ACL, only the node.mgr user has the proper policies applied. Any other user - which register via OIDC - can see (tailscale status) every node to which they should have access and can "tailscale ping" those devices, but none can resolve FQDN's. reach the outside world, or navigate the subnets provided by the subnet routers.
Expected Behavior
Expected behavior is that every user defined in a group has the policies applied based on the group to which they are party.
I am new to Headscale/Tailscale so I am fully cognizant that I may be misconstruing the ACL or misunderstanding how it works so I apologize in advance if this is not a bug but, rather, user error. If the latter, I would sincerely appreciate being pointed in the right direction.
Steps To Reproduce
Create ACL
Apply ACL
Login
Environment
Runtime environment
Anything else?
@GoodiesHQ commented on GitHub (Jan 26, 2025):
I am also experiencing this. In headscale version 0.24.0, ACL worked by the user's email address (the username has no effect). If no email was defined, it worked on Provider ID (which was horrendously ugly having an entire URL in the ACL entries, but it did work). Now in 0.24.1, the
user.namefield gets populated with the email address but nothing seems to work in the ACL.@kradalby commented on GitHub (Jan 26, 2025):
@SysAdminSmith
Could you give me some example output of your users?
Something like the output som
headscale users list --output json?Are you saying there is different behaviour in 0.24.0 and 0.24.1 ? from entra, which didnt seem to send emails based on another issue, it would not expect that.
@GoodiesHQ Could you give me the same output but from 0.24.0 and 0.24.1?
@SysAdminSmith commented on GitHub (Jan 26, 2025):
I just posted this in Discord in response to a suggestion I downgrade to 0.24.0 and manually change usernames - which auto populate with email names (user.name@domain.name) - to just user.name.
@kradalby
(Name, Display Name, and Tenant ID and sub claim are randomized)
This is in 0.24.0
@Codelica commented on GitHub (Jan 27, 2025):
Curious your OIDC user is missing an "email" property, perhaps your IDP isn't including
email_verified.@Codelica commented on GitHub (Jan 27, 2025):
This would match my experience.
In 0.24.0 with ODIC users that have plain usernames (fred, mike, etc) and email addresses (fred@domain.com, mike@domain.com, etc) populated, I have working user ACLs based on email address.
In 0.24.1, usernames get migrated to email addresses (as users login again), but I can't seem to get user ACLs to work based on email address.
@SysAdminSmith commented on GitHub (Jan 27, 2025):
Do you mind expanding a bit on this?
@Codelica commented on GitHub (Jan 27, 2025):
In 0.24.0 at least, user ACLs seem to key off email address, but your user with username
user.name1doesn't have any email address property set. I believe that happens when theemail_verifiedclaim isn't being sent by your IDP based on this comment.My OIDC users do have the email property set like:
And the email address can be used for user based ACLs in 0.24.0. But not in 0.24.1 it seems.
@SysAdminSmith commented on GitHub (Jan 27, 2025):
Thank you :) I did some further research an apparently Entra ID does not provide
email_verifiedby default. I'm looking into a solution@SysAdminSmith commented on GitHub (Jan 27, 2025):
I downgraded to 0.24.0 and went the UPN route since EntraID provides it by default (i.e. in the headscale config I set
email_claim: "upn").When I logged in, just the Display Name was populated; neither the username nor the email address was captured. I manually modified the user to create a username (user.name) which is referenced in the ACL.
No difference, sadly.
What is so damn odd is that when I set the endpoint to
--accept-routes,--accept-dns, and--exit-node=exitnodeFor whatever reason, it is forwarding dns requests to the exitnode (100.64.0.3). The dns is configured at 100.64.0.2.
Further:
I'm not sure what its trying to do by sending to port 53 on a private ip. That is a DNS server but I am not sure how tailscale even knows about it.
@Codelica commented on GitHub (Jan 27, 2025):
Well AFAIK email address has to be used for user ACLs in 0.24.0, so without that set you may be out of luck there. And 0.24.1 doesn't seem work with email or username as far as I can tell.
Not sure about the dns issue, but without a working ACL maybe it's trying whatever it can to get some dns back through your exit node. Pure guess, seems odd. I know Tailscale does try to transparently upgrade you to DNS over HTTPS (DoH).
@SlackingVeteran commented on GitHub (Jan 27, 2025):
I have been fighting this ACL issue about a week now. And I finally found a repro case on my end
If a User's user.name field is updated ACL no longer works for any user. On 0.24.0 I had manually assigned each user a username and it broke my ACL, Once I upgraded to 0.24.1 ACL started working soon as server was up and it broke again once a user logged out and logged-in, which caused the user.name to be updated to include email.
Then I renamed user's user.name back to what it was, and ACL stayed broken. I then downgraded to 0.24.0 and it magically started working again.
It looks like update of the user.name field for any user breaks the ACL and it cannot be fixed until a minor version upgrade is done? Is there any database migration that occurs during version upgrade/downgrade? Because it only seems to get fixed after that
@kradalby commented on GitHub (Jan 28, 2025):
@SlackingVeteran this is useful, can you show me your ACL?
Do you use your "old" usernames in the ACL or have you migrated to the what ends up being populated in the ACL (likely emails)?
@SlackingVeteran commented on GitHub (Jan 28, 2025):
@kradalby I was using usernames in ACL on v0.24.0 which was not working, upgrading to 0.24.1 fixed it to a point where username started working until username was updated by OIDC to be email. I swapped to use email in ACL after it stopped working, and it still did not apply appropriate ACL, i then changed username from email to custom username and used username on ACL and that did not work either, downgraded to 0.24.0 and username started working again.
Following is my ACL on 0.24.0:
@kradalby commented on GitHub (Jan 29, 2025):
@SlackingVeteran, you have to use the exact value present in the user object, it will check the
Emailand then theName(username) field in order. So if it used to be stripped down from email user2@example.com to user2, it will now be user2@example.com as we do not strip them anymore.When using OIDC, rename should not be used as it will be overwritten every time the user logs in, I filed #2387 to block the usage of it when OIDC is used to avoid confusion.
@SlackingVeteran commented on GitHub (Jan 29, 2025):
Thanks @kradalby
@Codelica commented on GitHub (Jan 29, 2025):
@kradalby I started fresh again thinking I may have made some mistake, but I'm afraid I can't get OIDC user based ACLs to work as you describe in 0.24.1.
Starting in a working state in 0.24.0 (note not .1) where I have 1 user (which is stable between login/logout as usernames can't be email addresses yet in 0.24.0):
And a very simple ACL:
It works as expected, the user fred (fred@domain.com) sees and can reach everything.
Then I update the system to 0.24.1 -- initially the ACL still works fine.
But the second fred (fred@domain.com) does a logout/login, his Headscale username is updated to email as expected:
But the ACL no longer works, with the following logged to the Headscale console:
2025-01-29T12:19:12-07:00 WRN No IPs found with the alias fred@domain.comWhich according to
headscale nodes listisn't true. fred@domain.com is shown as the user on his 4 nodes.If I try editing the ACL using his email fred@domain.com, Headscale will log
WRN No IPs found with the alias fred@domain.comeach time it's applied.The only thing that seems to work for me to identify his user in the ACL is using his
provider_id(which I tried based on some commits I was looking at).Is there some specific output that would help investigate this?
@Codelica commented on GitHub (Jan 29, 2025):
I think the problem may be here.
Once the user does a logout/login in 0.24.1 both
user.Emailanduser.Namewill match their email address, which would then hit the multiple user check every time?Edit: I just ran with trace logging and that is what is hitting for me:
2025-01-29T13:16:37-07:00 TRC home/runner/work/headscale/headscale/hscontrol/policy/acls.go:1043 > could not determine user to filter nodes by error="multiple users with token \"fred@domain.com\" found: no user matching"@SlackingVeteran commented on GitHub (Jan 29, 2025):
Great find @Codelica, I didn't update to 0.24.1 yet because of this issue and looks like you found the cause, might be worth creating a PR. A
else ifthere should fix the issue orcontinueinside first if block@Codelica commented on GitHub (Jan 29, 2025):
Unfortunately I'm not a Go dev :(, although it would be the one language I'd love to pick up if there's ever time. (seems doubtful) I have a feeling he'll want to preserve a check for legitimate multiple matches though -- just checking based on multiple unique users ids instead.
@kradalby commented on GitHub (Jan 29, 2025):
I think this is it!, good catch!
I have actually redone that function here https://github.com/juanfont/headscale/pull/2388, a bit by accident but it should fix that problem.
Can you test that branch?
@SlackingVeteran commented on GitHub (Jan 30, 2025):
I would test it but my Kubernetes deployment relies on pre-built docker images. If there is an image for it I can test it out right away
@SlackingVeteran commented on GitHub (Jan 30, 2025):
I built the docker container myself to test this and can verify email for OIDC logged in user is working as expected in ACL now
@SysAdminSmith commented on GitHub (Jan 30, 2025):
I updated to 0.24.2 and unforuntately I still am having issues. Am I right to believe that all users must have an email address, now? Because, as mentioned previously, EntraID does not provide email by default in a way that the email field is filled. The username will be filled by the email EntraID provides, but the email field will remain empty (user.name is retrieved via EntraID; node.mgr was a user created locally):
@suyashFSG commented on GitHub (Jan 30, 2025):
user.name will have email once user logs out and logs back in with OIDC. Account stays unchanged until user re-logins
@suyashFSG commented on GitHub (Jan 30, 2025):
As for email field, it will stay empty unless OIDC claim contains email_verified claim with
truevalue@Codelica commented on GitHub (Jan 30, 2025):
@SysAdminSmith Code in 0.24.2 checks the
UsernameandEmailfields you see in that table (user.Email and user.Name in the actual user object).So you should be able to reference those 2 users as "node.mgr" and "user.name@foo.bar" even with their
Emailfield empty.@suyashFSG commented on GitHub (Jan 30, 2025):
I use Entra as well and I have added additional claim on entra that has true value. You should be able to follow this instruction on Headscale discord to do so https://discord.com/channels/896711691637780480/1105842846386356294/1331037795900461106
@SysAdminSmith commented on GitHub (Jan 30, 2025):
Thank you for this! What "scopes" did you use in your config.yaml? Also, did you declare a separate "email_claim" in your config.yaml?
@suyashFSG commented on GitHub (Jan 30, 2025):
My scope is
openid profile emailand on Entra i had to fill every user’s Email field underProperties -> Contact Information, wish it was possible to define what claim to use for email instead. Because email for Entra is in UPN and preferred_username by default@SysAdminSmith commented on GitHub (Jan 30, 2025):
ooof.
Thank you!
@SysAdminSmith commented on GitHub (Feb 4, 2025):
I am not entirely sure why this bug was closed because I still cannot use ACL's with my headscale setup. I have upgraded to 0.24.2 and followed @suyashFSG suggestions but I am still unable to use acls.
Funny thing is, if the default is "deny all to all", then the directive of "accept all from all to all" is technically an acl that "works". But, outside of that, any acl rule will break a user's ability to: use dns and access anything outside of the tailnet.
Perhaps it has something to do with EntraID? I don't know. I am happy to provide whatever information is needed.
@andreyrd commented on GitHub (Feb 7, 2025):
I'm seeing very similar issues with a custom OIDC server. Email is populating correctly but ACLs are just seemingly not working. Haven't really been able to get to the root of what exactly is happening.
Edit: Never mind, I believe my issue is actually #1475