juanfont / headscale

An open source, self-hosted implementation of the Tailscale control server
BSD 3-Clause "New" or "Revised" License
20.64k stars 1.14k forks source link

Support for WireGuard only peers #1545

Open Nemo157 opened 9 months ago

Nemo157 commented 9 months ago

Why

Tailscale just announced their support for integrated Mullvad exit nodes. Being able to configure a similar setup via Headscale and an independent Mullvad account (or other wireguard VPN provider) would be useful for those of us without a Tailscale account.

Description

I haven't looked deeply into the details, but it's my understanding that this is implemented via a "WireGuard only peer" feature, and then support in the Tailscale coordination server to synchronize these peers with Mullvad. I assume it would be possible for Headscale to allow manually configuring these peer types.

sachiniyer commented 9 months ago

It also seems like mullvad publishes a script to connect to mullvad servers. The most interesting thing is that you basically link public keys with your account (which is why I think that there is a preconfiguration step to register devices in their announcement).

It seems like the simplest implementation could be to create an external script that calls registerNodeCmd on mullvad endpoints (marking them as WireguardOnly), and then calling the mullvad api with each of the node's public keys you want to link.

I think the RegisterMachine, machine config, and node conversion would need to be changed.

(I also am really not an expert in this, so please take it with a grain of salt)

Edit: what needs to be changed

averywinters commented 9 months ago

I think this was intended by the issue author, but to reiterate it seems more useful to me to allow any generic WireGuard-only peer as an exit node, not just Mullvad servers. That way headscale doesn't have to be tied to one VPN provider like the Tailscale coordination server currently is.

averywinters commented 9 months ago

It might be possible to support this for any WireGuard server peer by accepting peer config files like those generated by Mullvad's WireGuard config file generator like described in this guide, or by just asking the user to provide the generated fields we need at the CLI when adding the peer.

Nemo157 commented 9 months ago

I don't think it's possible to import a generated config file, because that contains a randomized private key. The provider needs to support uploading the existing public key from the devices that will connect. That doesn't seem possible through Mullvad's website, it wants the private key specified so it can embed it in the generated config files, but it is possible through the API. I haven't used other wireguard based vpn services so I'm not sure if being able to upload existing keys is common.

JadedHearth commented 9 months ago

Why would it be required to upload an existing public key?

averywinters commented 9 months ago

@WoodenMaxim From what I can tell, each Tailscale node only has a single private/public key pair that is generated when they are created, and then it uses that pair with every other node. So, when adding a non-Tailscale WireGuard endpoint like a Mullvad server, that other end needs to know (all of the) existing Tailscale nodes' public keys that are going to connect to it.

noseshimself commented 9 months ago

How does adding a Wireguard-only exit node get the public key of the nodes intending to use it into that node's configuration? If there was an easy solution for this we would not need Tailscale...

infogulch commented 9 months ago

How does mullvad do it?

noseshimself commented 9 months ago

How does mullvad do it?

No. "How does Tailscale do it?" Obviously by being a kind of "reseller" and having an interface to provision the mullvad IAM that way. The more interesting question is how the tailscale client is selecting the "exit node" it wants to use.

I was already wondering about this in other settings. If there are multiple possible exit nodes for a destination or multiple Internet gateways how is the most appropriate node selected and how can I influence the choice?

infogulch commented 9 months ago

https://tailscale.com/kb/1103/exit-nodes/?tab=linux

tailscale up --exit-node=<exit-node-ip>

With that resolved, we still need to figure out how to get the wireguard public keys of the tailscale nodes with permission to access the exit node into the wireguard-only peer, and vice-versa.

Maybe it's as simple as "run a command to dump the full list of keys in a form that the wireguard-only peer can consume, and expect the admin to put that configuration onto the node (and keep it up to date) manually". That may not be very palatable, but the alternative is writing software to sync keys automatically in which case why not just run a full tailscale node?

Maybe the best solution would be to just add some example docs showing how you can execute this pattern with a regular tailscale node...

sosnik commented 9 months ago

Mullvad themselves provide a script 1 to generate vanilla wg configs instead of mullvad's native client.

The client public key is communicated over mullvad's (sadly undocumented) API.

On Thu, Sep 28, 2023 at 4:05 AM Joe Taber @.***> wrote:

How does mullvad do it?

— Reply to this email directly, view it on GitHub https://github.com/juanfont/headscale/issues/1545#issuecomment-1737854626, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGMXXMWCDPE3INS5NYB5JVTX4RTGHANCNFSM6AAAAAA4PIQA6M . You are receiving this because you are subscribed to this thread.Message ID: @.***>

infogulch commented 9 months ago

Very interesting, thanks for sharing sosnik.

https://github.com/mullvad/mullvad-wg.sh/blob/main/mullvad-wg.sh#L59

curl -sSL https://api.mullvad.net/wg -d account="$ACCOUNT" --data-urlencode pubkey="$(wg pubkey <<<"$PRIVATE_KEY")"

Roughly the script:

I also found this gist that loosely documents uploading and revoking keys which may also be useful for mullvad: https://gist.github.com/izzyleung/98bcc1c0ecf424c1896dac10a3a4a1f8


So mullvad relays are configured via simple https POSTs to their api (which great, I love that they use simple tech). This may be useful if we want to implement mullvad support into headscale.

That said, it doesn't help us much if we just have a random wireguard relay sitting on a vps and we want to add "Support for WireGuard only peers", as the title of this issue suggests. Honestly I'm not even sure how we would expect a plain WG exit node to work in theory: Either you configure it completely manually, exporting private keys from tailnet nodes and importing them into the WG node which is annoying; or just... you know, install tailscale on that node instead, tailscale was invented to solve that annoyance in the first place.

With that in mind, I think we should open a new issue / retitle this issue to "Support for mullvad exit nodes" (if desired), and add a recipe to the docs showing how to set up your own exit node by running a headscale node on a vps or something, because a "WireGuard only peer" is a non starter.

Nemo157 commented 9 months ago

Either you configure it completely manually, exporting private keys from tailnet nodes and importing them into the WG node which is annoying

Just to clarify, you need to export public keys to configure the WG node (and import the WG nodes' public key into headscale).

I think there are still situations where this could be useful. One thought is that you want to connect devices to an organization managed WG node, where you don't have permission to install tailscale but you are able to provide your public keys to be configured on the node.

The other main reason I think to target just supporting "wireguard only peers" first is that they are the only thing that the tailscale protocol knows about. If they are supported by headscale then scripts can be written to configure them for whatever situation is needed, while if headscale instead only supports talking to the Mullvad API it blocks being able to configure for other situations. That doesn't mean headscale shouldn't support talking to Mullvad itself, but I think it should build on the general functionality of wireguard only peers.

sosnik commented 9 months ago

I am with Nemo157 on this one. At a bare minimum, headscale should support exporting a vanilla wireguard config (peer public keys and endpoints) for use with other wireguard clients. Supporting only mullvad opens the door to "But why not Proton" / "Why not X" conversations. One other thing to consider is that commercial VPN providers will limit you to X number of concurrent connections (I think mullvad's limit is 5?). If someone's tailnet (headnet?) has more than 5 devices, we don't want to give mullvad more than 5 public keys and run up against such limits by accident.

On Thu, Sep 28, 2023 at 7:05 PM Nemo157 @.***> wrote:

Either you configure it completely manually, exporting private keys from tailnet nodes and importing them into the WG node which is annoying

Just to clarify, you need to export public keys to configure the WG node (and import the WG nodes' public key into headscale).

I think there are still situations where this could be useful. One thought is that you want to connect devices to an organization managed WG node, where you don't have permission to install tailscale but you are able to provide your public keys to be configured on the node.

The other main reason I think to target just supporting "wireguard only peers" first is that they are the only thing that the tailscale protocol knows about. If they are supported by headscale then scripts can be written to configure them for whatever situation is needed, while if headscale instead only supports talking to the Mullvad API it blocks being able to configure for other situations. That doesn't mean headscale shouldn't support talking to Mullvad itself, but I think it should build on the general functionality of wireguard only peers.

— Reply to this email directly, view it on GitHub https://github.com/juanfont/headscale/issues/1545#issuecomment-1738757384, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGMXXMXH5IN3WLT6HDXLFZDX4U4V3ANCNFSM6AAAAAA4PIQA6M . You are receiving this because you are subscribed to this thread.Message ID: @.***>

almereyda commented 9 months ago

I strongly believe this would come with all the overhead involved in implementing a WireGuard management API, for which exist many examples.

Examples

* https://github.com/firezone/firezone * https://github.com/gravitl/netmaker * https://github.com/netbirdio/netbird * https://github.com/ngoduykhanh/wireguard-ui

Do we already know the API surface of the Tailscale coordination server, which needs to be mimicked by Headscale for supporting the client feature implemented in tailscale/tailscale#7821?


Practically speaking, it appears this use case will be much easier to achieve with a Tailscale network and a given WireGuard network residing in the same namespace, and routing being allowed between their subnets.

To continute to distinguish between (1) sole support for WireGuard peers and (2) a default route via an external WireGuard VPN:

infogulch commented 9 months ago

Just to clarify, you need to export public keys

Thanks for the correction, please excuse my typo.


I'll relax my stance a bit here, it seems perfectly reasonable to allow headscale users to manually configure wireguard peers by exporting node public keys and importing remote endpoint public keys by some cli or api, and to expect VPN configuration scripts to be layered on top of this feature. Though, how it interacts with ACL and other tailscale features appears to present some non-trivial remaining challenges.


Wrt namespacing and routing, are routing "announcements" a thing in wg? The mullvad script explicitly sets config on the client to route ips over the interface with AllowedIPs = 0.0.0.0/0, ::/0. From that I'd guess the admin would have to set the route manually.

sosnik commented 9 months ago

Wrt namespacing and routing, are routing "announcements" a thing in wg? The mullvad script explicitly sets config on the client to route ips over the interface with AllowedIPs = 0.0.0.0/0, ::/0. From that I'd guess the admin would have to set the route manually.

Not that I am aware of. wg-quick uses native methods (ip route) to define routes in the host, and no "announcements" per se are actually happening. But I don't think this is a problem:

  1. The people who will use vanilla wireguard will be savvy enough to be aware of the need for manual routing; and
  2. Wireguard exit node config is going to be a per-node thing anyway, and if you have access to the node, you (or your management script) can define the routes like it normally would for vanilla wg.

On Fri, Sep 29, 2023 at 3:18 AM Joe Taber @.***> wrote:

Just to clarify, you need to export public keys

Thanks for the correction, please excuse my typo.

I'll relax my stance a bit here, it seems perfectly reasonable to allow headscale users to manually configure wireguard peers by exporting node public keys and importing remote endpoint public keys by some cli or api, and to expect VPN configuration scripts to be layered on top of this feature. Though, how it interacts with ACL and other tailscale features appears to present some non-trivial remaining challenges.

Wrt namespacing and routing, are routing "announcements" a thing in wg? The mullvad script explicitly sets config on the client to route ips over the interface with AllowedIPs = 0.0.0.0/0, ::/0. From that I'd guess the admin would have to set the route manually.

— Reply to this email directly, view it on GitHub https://github.com/juanfont/headscale/issues/1545#issuecomment-1739725218, or unsubscribe https://github.com/notifications/unsubscribe-auth/AGMXXMWSNVU4TWT2BVN27HLX4WWNPANCNFSM6AAAAAA4PIQA6M . You are receiving this because you are subscribed to this thread.Message ID: @.***>

github-actions[bot] commented 6 months ago

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

Victor239 commented 6 months ago

Still relevant.

noseshimself commented 6 months ago

Still relevant.

But still without any idea about the implementation by those who want it. To summarize: Tailscale (and a few others) exist because there is no simple auto-configuration for Wireguard links in the basic protocol. You either tell us how to introduce the Tailnet to some arbitrary wireguard (exit-)node or we can just as well close this for good.

Nemo157 commented 6 months ago

Tailscale already has the client-side feature for this, someone needs to investigate exactly how it is represented by the server and add it to the details provided by Headscale, there is no design work needed for the tailnet side of it. I'm pretty sure once the backend side of how to represent it is investigated the interface to configure that from the CLI will be relatively self-evident, so I'm not sure if there's any point in trying to design it externally. (I would have worked on this myself already, except I really dislike golang, maybe one day I'll eventually give up waiting for someone else and get over my aversion).

smehrens commented 4 months ago

I think this feature would be very helpful in several scenarios:

  1. clients with ssh but without headscale/tailscale client
  2. clients controlled by a deployment system like ansible, chef, puppet, intune, apple mdm
  3. clients controlled by second headscale server
  4. nodes belong to different company.

if you can

I) import to headscale a) a dataset of nodename, owner, publickey, wireguard ip address, external address ... for each wireguard only node
II) export a) a list of datasets for the headscale nodes, which should be able to connect these nodes b) a n*m matrix which headscale node should be able to connect to which "wireguard" node III) send a webhook if reconfiguration ist needed the deployment tools should be able to do the rest.

Company rules could require to use a specific deployment tool and automation process so headscale client may be no option for some systems. Or company rules do not allow headscale installation without a time consuming certification process for every new software version.

Some appliances do not have support for head/tailscale and dont allow installing third party software, but allow deloyment over ssh, api, ldap or whatever.

A second headscale server may import the exported list and use this for federation.

Of course all these scenarios dont fit to the general idea of headscale, but .... maybe there no other way ....

unixfox commented 3 months ago

Does anyone have a mullvad account for testing? I want to check the traffic between the tailscale control plane and the tailscale client in order to understand how mullvad servers are served to the client.

If so, email me at github1545 [at] unixfox.eu

sefidel commented 3 months ago

@unixfox I want to check the traffic between the tailscale control plane and the tailscale client in order to understand how mullvad servers are served to the client.

I think you need a Tailscale account with Mullvad add-on for that.

github-actions[bot] commented 2 weeks ago

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

aniqueta commented 2 weeks ago

Not stale.