55 karma · joined July 17, 2013
I think tailscale could become the #1 solution for personal users and small / mid-sized companies (some of them might not even have an IT dept). At least the easy installation, the single process design (no separate IKE service etc.) and the opinionated modern cryptography - that deliberately does not allow any configuration at all - would make it a really good candidate for those use cases.
This users can probably rent a cheap $3 VPS easily and use it as an on-prem coordination server. However, this increases the installation effort considerable and trusting the cheap $3 VPS to be an essential part of your cooperate network might be a deal breaker. Many of those users might not even have a dedicated team for server maintenance and might not apply security updates regularly.
So, please add an (optional) additional PSK (or key pair / certificate) to each node that is not shared with the coordination server and can be used to sign / verify the configuration on each client. Users that do not care don't have to specify anything (they just have to log-in and everything works). Users that do care would have to login and provide the PSK on each device.
(And to be clear, the problem is not that I do not trust you. I am sure you are doing a great job and I would really like to use your service. But you are an US based company and with the new data protection laws within the EU it might not be easy to convince all customers that potentially sending all their data to a third-party company within the US is necessary.)
Example: Start it on all your devices and you can always access the shared files from your PC at home on your phone or tablet, no matter where you are. If you happen to be at home, no packages will be sent over your internet connection (so you can easily use it to stream 4k movies for example), but the way to access those files is always the same (fixed IP) and always secure.
An additional advantage of Wireguard (which is used behind the scenes) is that it maintains a strict mapping of IP addresses and identities. Therefore, you can usually restrict access to services by IP (instead of using TLS certificates or complicated authentication mechanisms).
My main concern currently is the coordination server which does not fit the zero trust claim.
I know that the traffic between peers is end-to-end encrypted and you did a good job designing your DERP protocol. However, the ability of the coordination server (login.tailscale.com) to add arbitrary nodes to my private network without my consent scares me.
Maybe you can use Wireguard's PSK to add an additional pre-shared-key to all nodes that is not managed by the coordinator (and never transferred to it)? This would make the setup slightly more difficult (you need to login to tailscale.com AND you need to provide your PSK), but it would at least ensure that the system can never talk to foreign nodes added by the coordinator itself (because the foreign nodes do not know the PSK).
If you already use the PSK for something else, another passphrase/key-file that is never transmitted and is XOR'ed over the PSK will do the trick. The firewall configuration that is pushed to all clients should be probably signed by a local key too, since it is rather critical.
Another possible attack of the coordinator would be if he pushes a configuration with correct VPN IPs and correct public keys, but changes the mapping between them. Since the IP within a wireguard network is usually used as an identity, this might be a huge problem.
Some careful thoughts about the memory layout of your structs, especially which of them should be embedded and / or passed around by pointers and which of them shouldn't, might also pay off.
Another common optimization is to put the allocated objects back to a memory pool for later use. Take a look at the bufCache channel [1] from the bufio package for example (the http and the json package are using the same trick).
It's now quite funny to read a blog post from someone completely different (Tim Penhey) who had encountered and solved the same issue with exactly the same usecase on the very same day, complaining about Go without even mentioning the discussion [1] or the latest changeset [2] that solved the problem.
[1]: https://groups.google.com/d/topic/golang-dev/o9i_SbGRrzI/dis... [2]: https://codereview.appspot.com/11432044