mirror of
https://github.com/juanfont/headscale.git
synced 2026-01-11 20:00:28 +01:00
Shoehorn PSK-based authentication to provide key rotation and stronger identity guarantees #658
Closed
opened 2025-12-29 02:21:42 +01:00 by adam
·
9 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
Milestone
No items
No Milestone
Projects
Clear projects
No project
Notifications
Due Date
No due date set.
Dependencies
No dependencies set.
Reference: starred/headscale#658
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 @gdonval on GitHub (Mar 6, 2024).
Why
Headscale, like Tailscale, currently considers Wireguard's public-private key pair as disposable: they are created and then distributed everywhere through Headscale's backend and rotated as needed.
Description
What I propose, as a separate mode, is the following:
In terms of how this helps with the points above:
@github-actions[bot] commented on GitHub (Jun 5, 2024):
This issue is stale because it has been open for 90 days with no activity.
@gdonval commented on GitHub (Jun 5, 2024):
Shouldn't be stale.
@kradalby commented on GitHub (Jun 5, 2024):
I think this would require changes to the Tailscale client, and therefore would be out of scope for this project.
@github-actions[bot] commented on GitHub (Sep 4, 2024):
This issue is stale because it has been open for 90 days with no activity.
@mjohnson9 commented on GitHub (Sep 10, 2024):
There is a significant weakness in the proposed design.
The Headscale server should never know the PSK of any pair of peers.
If, as in the proposed scenario, there is a cryptographic break of ed25519, the PSK becomes the sole cryptographic key material protecting the connection. If, as in the proposed solution, the Headscale server generated and/or stored the PSK, it is now capable of decrypting and spoofing traffic.
There are a few potential solutions, but I don't want to put out ideas using cryptographic primitives from back-of-the-napkin thoughts, because cryptographic primitives are prone to severe weakening through subtle misuse.
@gdonval commented on GitHub (Sep 11, 2024):
If the private key can be retrieved from the public key, then it is correct. With the current system in such situation, every eavesdropper can decrypt everything though. The PSK makes it at least a tiny bit harder. But the situation is no worse than keeping using no PSK.
In my mind, there are multiple levels of "flaws" before reaching the dreaded private key full compromise so I wasn't thinking "what if your crypto is completely broken and you want to keep using it?". That doesn't sound like a reasonable threat model, which is why I didn't even try to think about it.
Plus the main boon, I think, is to provide a mechanism that scales for 2M nodes as well as it does for 2 nodes while retaining strong node identity (you can even get something like tailnet-lock-like feature for free with this)! As long as ed25519 is not completely broken, a headscale provided PSK is a simple way to achieve all this. And if it is broken in the future, eavesdropper would have to hope they also captured that exchange, that might not have been performed with elliptic curve crypto.
I'm obviously not against getting a fancy post-quantum key exchange algorithm mixed in everything instead of just Headscale saying "here's your PSK to peer X" but I just found the latter very elegant (and not any worse than the normal scheme security-wise).
But yeah, we could let the nodes do a fancy post-quantum key exchange. Actually, for the sake of simplicity and to ensure headscale itself doesn't eavesdrop, that could occur in a wireguard channel first established without a PSK to kickstart the negotiation and then updated with negotiated keys. (I'm actually serious even though I know it sounds convoluted, using the channel is a great way to achieve mutual authentication)
There is just one thing though... If the private keys are compromised (i.e. if ed25519 is completely broken), you don't get mutual authentication anymore. The key exchange would still provide protection against passive attackers, which is a good thing, but active attackers can MitM the whole thing. At prime position to do this kind of naughty stuff is the headscale server (which is a reason why I suggested establishing and using a wireguard channel to do the key exchange).
@github-actions[bot] commented on GitHub (Dec 27, 2024):
This issue is stale because it has been open for 90 days with no activity.
@github-actions[bot] commented on GitHub (Jan 4, 2025):
This issue was closed because it has been inactive for 14 days since being marked as stale.
@marek22k commented on GitHub (Jan 8, 2025):
It would also be a change in the tailscale client and therefore outside the project, but Rosenpass does something similar. Rosenpass uses post-quantum secure algorithms to negotiate new PSKs every two minutes.
netbird, a kind of Tailscale competitor, has already integrated this, for example.
Related issue: https://github.com/tailscale/tailscale/issues/14370