mirror of
https://github.com/juanfont/headscale.git
synced 2026-01-11 20:00:28 +01:00
[Feature] Add option to expire node on disconnect #979
Closed
opened 2025-12-29 02:27:00 +01:00 by adam
·
7 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
enhancement
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: starred/headscale#979
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 @dmeremyanin on GitHub (Mar 21, 2025).
Use case
We want to enforce user authentication on every connection attempt to ensure 2FA is used each time. We've configured an OIDC provider (Authentik) for this purpose, but currently, Headscale doesn't require re-authentication unless the node is expired.
Setting a shorter expiration time (e.g., 1 hour) isn't ideal, as it forces Tailscale to disconnect frequently, interrupting user access. We need a solution that ensures authentication on each connection attempt without forcing disconnections every few hours.
Description
This feature enforces stricter authentication by expiring the node upon disconnection. When enabled, it ensures that users must re-authenticate via the OIDC provider on the next connection attempt, requiring 2FA each time.
Contribution
How can it be implemented?
I propose adding a new configuration option,
expire_node_on_disconnect, which will be disabled by default to preserve current behavior. When enabled, the node will expire upon disconnection, and users will be prompted to re-authenticate on the next connection attempt.The expiration can be implemented in the
updateNodeOnlineStatusfunction here:707438f25e/hscontrol/poll.go (L404-L410)@dmeremyanin commented on GitHub (Mar 21, 2025):
I've implemented a draft with the proposed change:
79521df1b0If it looks good, I'll open a PR.
@dmeremyanin commented on GitHub (Mar 23, 2025):
@kradalby would really appreciate your review when you have a chance. Thanks
@kradalby commented on GitHub (Mar 24, 2025):
Hi, sorry, we try to be very strict and avoid infinite accessibility. This feature will both add more surface for us to keep track of, but also prevent a footgun for people who dont understand it.
I do not think this mode would be the right way to do things from a security perspective as people can just make sure they keep the connection alive. In addition it would be a very bad user experience if the headscale/tailscale or laptop gets into a flaky connection state.
@dmeremyanin commented on GitHub (Mar 24, 2025):
I agree with your concerns. However, we can set a maximum connection time limit (e.g., 1 day) to ensure it doesn't interrupt normal usage while still enforcing 2FA on the next connection attempt, and preventing established connections from being used for too long. As far as I understand, this wouldn't be possible without the proposed change.
I thought it was a pretty small change, easy to implement, and could be disabled by default via a config flag to preserve the current behavior, which would help make Headscale a bit more secure. If you feel this approach doesn't align with the Headscale vision, I completely understand.
@kradalby commented on GitHub (Mar 24, 2025):
I do not think it aligns, we aim to mirror upstream Tailscale SaaS, and expanding and supporting edgecases which is not possible there is making it harder for us to focus on achieving that.
I think the other aspect that is quite important is that Tailscale's platform is essentially distributed, the control server is really only meaningful to exchange the information and a continuous connection to it is more of a "best case". For example, if Headscale (or Tailscale SaaS) goes down, then all nodes currently online will still work as they have a view of the world.
This change will break this property, which is one of the core parts of the platform.
@dmeremyanin commented on GitHub (Mar 24, 2025):
It makes total sense to me now, especially the part about the platform's distributed nature. I hadn't fully considered the case where Headscale goes down. Thanks for taking the time to explain!
@dmeremyanin commented on GitHub (Mar 25, 2025):
Just in case someone wants to achieve the behavior described in the issue, here's the code we added to the crontab to run every minute:
This script forces users to re-authenticate on the next connection attempt (and optionally use two-factor authentication) if they have been disconnected for longer than 30 minutes. If the user reconnects within that period, the connection proceeds normally without requiring re-authentication.
It's worth mentioning that this should be combined with the
oidc.expiryconfiguration option to ensure that users can't stay connected indefinitely (or for too long). We have set it to 24 hours to enforce a maximum connection time.