Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Show HN: A WireGuard Powered Remote Shell (github.com/noisysockets)
170 points by dpeckett on May 12, 2024 | hide | past | favorite | 74 comments
Time to announce Noisy Sockets Shell, the first in a series of WireGuard powered applications I'm working on. Noisy Sockets Shell is an SSH replacement that uses WireGuard for authentication and encryption, and WebSockets for communication.

CLI and browser client available.



Thanks everyone for the wonderful Sunday afternoon surprise, I'd posted this originally on a Friday and I guess a lot of us were out watching the polar lights. This was a fun project to work on.

Right now it doesn't support a multi-user daemon mode, kind of similar to mosh. But in the future because the server is able to cryptographically verify the source of connections, it's only a matter of time until I implement something akin to a per user `~/ssh/authorized_keys`.

With noisysockets I'm effectively building out a suite of WireGuard powered "apps". Which are small, unprivileged, programs you can attach to a WireGuard network and will act as virtual peers.


What does this bring over binding sshd to the Wireguard interface address?

That’s what I do currently with some of my hosts.


I heard that ssh is kinda of an unnecessary step, since wireguard is already encrypted by default. Even legacy rsh should work fine in that setup. But I'm still not convinced, having double encryption is not a real performance problem in the real world. And I prefer it, just to be safe


SSH can authenticate a user, wireguard (as typically deployed) only authenticates a computer.

SSH can sometimes authenticate intent, like Yubikey touch.

Using wireguard for authentication is a mistake. The category of mistake is usually referred to as ambient authority, often exploited via a confused deputy.


I think you are misunderstanding the use of wireguard here - this is a userspace wireguard connection, so the process has the same permissions as the user executing it.

In one sense, this is no different than adding a public key to ~/ssh/authorized_keys.

If you control the key, you control the authentication.


In the case of the project linked, yes. I'm responding to the comment that said

> I heard that ssh is kinda of an unnecessary step


rsh would fill the same gap for authentication, (or even raw telnet), or anything that integrates with unix users.

What makes SSH different is the encrypting part. The keys were only introduced to be used by the encryption algorithms. Users and multiple identities were a core detail of nixes much before SSH


rsh relies on the client host to not lie, that's quite a different level of guarantee than touching a Yubikey.


Ok, I get what you mean rlogin and rsh are not safe because of inumerous legacy problems. But I think you get what I meant as well, authorization problems can be solved without SSH.

I said that even rsh would do because will can ignore all the weird outdated stuff and just login with an user and password, same as a local login. In that case telnet would also work.

However, I truly believe that cryptographic keys are way superior to passwords. And going back to them would be a huge step back


Is there a small writeup available somewhere about this? I like the idea.


I guess you just need to configure `ListenAddress` in your `/etc/ssh/sshd_config` properly (see `man sshd_config`).


You also need to change the boot behavior of sshd to wait for wireguard (tailscale in my case) to be available. I had to add a couple of lines to the ssh systemd unit.


Yep. And also pay attention during package and system upgrades on some systems. In certain cases it messes up this ordering, and you end up with sshd starting before Wireguard again and then sshd doesn’t find any interface with the specified address, which in turn makes it so that it won’t bind to that address. Making the machine unreachable until you manually fix it again.


A less finnicky approach would be binding to 0.0.0.0, then configuring incoming firewall policy. By default deny, then allow SSH through wireguard network. Or by default allow then deny SSH through public network.


I like that idea a lot. I may start doing that.


if you want to get fancy and/or over engineered you would use systemd templated units to setup sshd@.service and a ListenAddress in the config listening on %i. Then you could bring up sshd@(expectedip).service for each expected IP

.. but that doesn't gain all that much tbh.if anything the only hesitation I'd have on listening to * and relying on firewall rules is if the service comes up before its configured. but exposing sshd isn't even that bad


You can create an override file for sshd to avoid issues due to package config changes.

https://www.freedesktop.org/software/systemd/man/latest/syst...


I did something like that but somehow after an upgrade I still lost access to one of my systems that I had set up like that. This machine is physically in a different city from me so I rarely have the chance to go there. And lately I’ve even been in another country.


Yeah I would do it with nftables so you don't have to change the sshd listen address.


Why don't you just add sshd restart as an interface PostUp step in the client's wireguard config file?


it only takes 3 lines in a systemd override fille (which I think don't suffer the overwrite-on-upgrade problem). To my mind, that keeps the startup logic nicely local in service files.


So allow sshd to start in a failed mode and then restart it?


Why does the client have a listen port?

    nsh config init -c server.yaml -n server --listen-port=51820 --ip=172.21.248.1
    nsh config init -c client.yaml -n client --listen-port=51821 --ip=172.21.248.2
Typically, servers have easiest to configure NAT/firewall/port forwarding and clients (to me) are basically thought of as "not going to get through their router/firewall configuration no matter what".


Because WireGuard is a P2P protocol and if you want the server could be behind a NAT (eg. reverse shell). Very useful for accessing your home machine without having to open up a port etc. In the near future noisysockets will get NAT traversal support (with a Nebula lighthouse type server) which will make this use-case a lot simpler.


I don't think this is accurate?

The flow I've seen is "Wireguard server has its listening port open. Clients (with all ports closed) connect to the server on its open port."

After that, all connections can still happen. Server -> client, client -> server.

> NAT Traversal: The NAT entry created by the client's outgoing connection allows the server to send packets back to the client.

> VPN Tunnel: The established VPN tunnel enables bidirectional communication, allowing the server to reach the client without the client needing an open port.


Would you consider dual-licensing this under a FOSS license like the AGPLv3? That's strong enough copyleft that I think you'll be safe from what you're trying to avoid with your current nonstandard license.


Done, the noisysockets CLI is now available under the AGPLv3 (and NSSL-1.0), pick the license of your choosing with no legal ambiguity. If it turns out the FSL-1.1, and by virtue of being a derivative the NSSL-1.0 is legally sound, after four years the code will be available under the MPL-2.0.

But you don't have to trust me, the AGPLv3 starts immediately.

I'll update the source headers in the following days.

Thanks!


That's actually a really good suggestion, the main reason for using a time limited source available license was that I didn't want to impose a viral copyleft on everyone and lock up the code forever.

The custom license is a pretty basic derivative of the FSL-1.1 with MPL-2.0 instead of Apache (for a weak copyleft), I think I might keep the custom license in place (I'll make the very minimal changes from the stock FSL-1.1 clear).

But adding an AGPLv3 license for those with ambiguity concerns is totally okay with me (it's ultimately more restrictive than the source available license in a lot of ways).

Thank you for the great suggestion.


Pretty cool, but the license is pretty toxic to commercial adoption. I would suggest also licensing under MIT, BSD or Apache if you want this to ever achieve any widespread usage. Unfortunately you are competing against SSH which has a mature ecosystem so if you want widespread usage then you need to make it attractive legally as well as technologically.


One surprising tricky part of encrypting "live input" protocols (like typing send over a shell) is that just encrypting them is not enough.

You can use timing of packages send to e.g. extract passwords.

(hence why SSH clients normally take additional precautions)


Why fork/copy&paste wireguard-go source code instead of using wireguard-go's existing netstack package? Couldn't you help improve instead?


Can you explain which problem this tool / these tools solve? I’m not sure I understand the purpose.


A similar tool is Tailscale SSH. They replace SSH keys, which are clunky to distribute and invalidate, with the same authentication mechanisms you use for the rest of your digital security.

A great use case in the enterprise is wrapping old but mission critical systems that don't support modern encryption or authn requirements with WireGuard. SSH is a demo for that use case- there's a lot of proprietary TCP data protocols out there in the legacy enterprise world!


One of the things on my TODO radar is to implement a LD_PRELOAD'able Unix sockets implementation. Plus I need to get some additional language bindings done (eg. Python).



Thanks for the explanation!


To what extent does this replace mosh? https://mosh.org/

It seems like it could do some of the same usecases.


Mosh was a big inspiration but I took a more traditional PTY based approach rather than object orientated updates.

One thing it does have in common with mosh, is excellent roaming support. And the other major selling point is that the remote shell protocol is browser compatible. No need for things like "Shell In A Box".


eternal terminal is better than mosh. it renders properly and provides scrollback.


Looks like you created a bespoke license for your tool, which is your perogative but also means many people won't even consider using it.


Why would people consider using it over "regular WireGuard setup with opensshd somewhere"?


Perhaps to use it as a jump host. Oftentimes running ssh via ssh is not that good performance wise.


I was wondering the same thing, but another comment on this post pointed one out.

It’s clunky to distribute and rotate ssh keys, but much easier to do that with WireGuard credentials.


I'm drawing a blank; why would it be easier to rotate wg keys than ssh keys? They're both asymmetric keys that fit in one line of text, which should be generated on the client and then have the public key uploaded to the server(s), and which can be dynamically loaded at runtime. If anything, I'd think ssh was marginally easier because it supports CAs out of the box and you can just have your auth system dynamically signing the user's certificate.


And that's totally fine :). It's worth noting that as a derivative of the FSL/BSL in four calendar years everything will be released back to the community under the MPL-2.0.

The shell implementation is already under the MPL-2.0 and worth a look at for anyone who's interested https://github.com/noisysockets/shell


> It's worth noting that as a derivative of the FSL/BSL in four calendar years everything will be released back to the community under the MPL-2.0.

A 4-year-old version of security-critical software. You understand why this is less than compelling?


>It's worth noting that as a derivative of the FSL/BSL i

Maybe, but we don't know until we hire a lawyer to check it out. And we don't.

On the other hand, I don't think you can afford a lawyer to defend your bespoke license either.

In either case, the license is meaningless.


Clearly not meaningless if you’re avoiding using it to avoid risk of infringement


It's the same as no license.


It's a license that hasn't been reviewed by legal, which is not the same as no license.


If I can make a rough attempt at summarizing this: this is basically a PoC of a remote shell using the Noise Protocol Framework[1] with implementation Noisy Sockets[2] to effectively use UDP to tunnel a connection from one application to another directly and securely. If you squint at it, Noisy Sockets is basically like TCP+TLS, but UDP+SomeOtherCrypto. The library is a drop-in replacement for the Go 'net' library. All the protocols (including tcp/udp) are implemented in userspace.

This has some really interesting use cases (like not having to use HTTPS to get a bidirectional secure communication channel... not being limited by firewalls... not requiring an OS to upgrade its tcp/ip stack...). Normally I'm a pessimist but I kinda like this thing (the library, not the remote shell). Just needs a less clunky way to discover and route to services, a simpler way to configure a connection to the remote host, and extensible authentication/authorization (public keys pose management problems and don't fit some use cases).

That custom license may stop people from using the remote shell. Luckily the library is just MPL 2.0

[1] https://noiseprotocol.org/noise.html#introduction [2] https://github.com/noisysockets/noisysockets


Very good summary, and thanks for bringing up the license distinction, the noisysockets core library will always be MPL-2.0 and open to the community.

The fundamental thesis behind noisy sockets is, "What if your network endpoints were processes instead of machines?"

And as you say bypassing the host networking stack actually brings a lot of benefits (eg. avoiding those VPN leak shenanigans), it's actually interesting when you squint enough it begins to even look vaguely something like QUIC (in that you have multiple encapsulated streams/channels/sockets going over UDP with their own congestion control).

Peer discovery and NAT traversal are next on my list. I'm going to implement a kind of userspace lighthouse peer that will advertise peer endpoints to the network. I'm still trying to think about how I will deal with TURN/DERP. I suspect I'll tunnel WireGuard over WebSockets and just have each peer listen on UDP/TCP. Maybe one day that will allow even an in browser peer with WASM (which I'm sure someone will find an interesting use case for).

Also on the list is fine grained authentication/authorization (interestingly netstack has an iptables implementation), some of it will be opensource and some of it will be source available (sorry for the SSO tax).


I feel like you're very close to an implementation which would finally break the HTTP hegemony on network protocols. I would strongly suggest looking at non-Web methods (I haven't done much research into TURN/DERP so I can't suggest anything specific)

I would also suggest looking at ZeroMQ if you haven't yet; their design & implementation is really fantastic. They implement the bare bones in the library, and then you can go implement your own components with it for whatever architectural topology you want. So for example, you could make a closed-source paid product of a connection broker using the library, and somebody else could make one for free as open-source. Both have their use-cases, and they're both compatible with all the other apps in the ecosystem. This benefits you as it legitimizes the product and grows the ecosystem, and encourages more use due to its flexibility


Thanks for the kind words and great suggestions, I'll take a very close look into ZeroMQ, I'm also keeping an eye on NATS.

Some kind of paid connection broker / app platform actually sounds like a solid way to build a sustainable business out of something like this.

I'm trying to avoid the tailscale model of having to lock up the control plane.


I agree it could be a viable business model, but the trick seems finding a market.

Since QUIC exists, most people (including virtually all client-side apps) will just use that. But QUIC is still TLS and HTTP, which is unnecessary for a lot of use cases and adds complexity. I think if you created developer-friendly tooling/libraries/servers/etc that were dead-stupid-simple, people would use that over TLS/HTTP, for anything other than a web browser. Android apps and tunneling applications might use it on the client side, and MQTT would be a great use case on the backend.

The one thing I think would be a stumbling block to the simplicity is the use of public keys. It's just super clunky compared to basic username/password or PSK auth. I don't have any suggestions here, I know Wireguard is pretty much wedded to public keys, but anything you can do to eliminate the many problems/limitations with public keys would help drive adoption.

I think you can lock up the control plane if you want for an implementation, but keep the interfaces loosely coupled and part of an open standard with the library having simple hooks for everything. That way those that have some money and just need a fix now, will pay for your thing, and those that can't will write their own implementation and grow the ecosystem which you can then market off of.

Like, Terraform could have been a closed-source tool, but the fact that anyone can write a provider means Hashi didn't have to write them all, and as more providers and modules were written, the tool cemented itself ever more as indispensable. (Which pisses me the hell off because Terraform sucks so bad, but it was a good business strategy heh)

Last thought: I would also quietly advertise the library as as "TCP evolved" or something similar, because that's how I see this. Assuming you deal with NAT, I would absolutely use a protocol like this over TCP by default for all my applications. QUIC was almost there but the TLS and HTTP is so unnecessary for 99% of applications.


congrats on the release - it sounds like this will be very useful. can you explain what you mean by "having to lock up the control plane" here?


> I'm working on a simple protocol capable of tunneling TCP/UDP over WebSockets. Basically you can think of it as a way of providing QUIC/WebTransport functionality over WebSockets (multiple streams, backpressure, datagrams, etc). Reference implementation is in Go. Feel free to reach out if it might be useful.


[flagged]


why is that?


WG itself doesn't support user authentication of any kind, it's just a tunnel. If you have the right key and send a properly signed packet WG will pass it. Encryption keys are not authentication in of themselves.


> properly signed packet

How would an adversary do this without the private key?

Wireguard uses ChaCha20Poly1305, an AEAD scheme. The first A stands for Authenticated.


This is pedantism, and is also just wrong. "if you have the right key" IS authentication. Encryption keys are used as a form as authentication all the time, it's one of the main use cases of public/private key encryption. I challenge you to explain how OpenSSH does non-password authentication without referring to encryption.

Authentication just means proving who or what you are. Secret keys, whether they be passwords or encryption keys, are one of the primary ways to do this. Just because the key is also used for something else in addition to, or as part of, that process doesn't change it from being authentication.


Well, regular WG authenticates at the host level (roughly), not the user level, which can matter. I think this actually does auth at the user level, but there is some nuance there.


If the tool runs in userspace and authenticates with a key stored in the user's home directory, isn't it authenticating the user? AIUI this isn't running a generic tunnel; it's shuffling packets inside the program and then putting WG UDP on the wire.


...much like an ssh key?


Which can have a passphrase and an agent, all sorts of MFA. One benefit to wireguard though is it's using UDP with a much less noisy handshake, you will never even know if the port you tried connecting to runs it (if your firewall is configured correctly). It's much more stealthy, an ssh server will pronounce it's version banner and public host key to literally anyone.


Could you elaborate?


Hello, it’s my understanding that WireGuard isn’t very secure, but it is very fast. Is that correct?


Wireguard is the most secure VPN protocol.


A quick google search seems to indicate OpenVPN is more secure.


Google is not a source; what exactly are you seeing that suggests that? The only things I can find against wg are that 1. it hardcodes crypto options, so if ex. its cipher choices proved vulnerable then it would be harder to fix (vs openvpn allowing, more or less, plug and play of whatever cipher you want), and 2. openvpn has been around longer. But wg is much less code to audit, has been audited, is now widely deployed and used at scale, and hardcodes extremely safe cryptographic choices. So... again, what specific claims/sources say that openvpn is safer?


Wireguard is written by Jason Donenfield, a renowned developer with deep crypto knowledge. You can search him up and see for yourself. https://www.zx2c4.com/


Yes, I apologize to all who downvoted me, someone told me OpenVPN was still the more secure choice for a VPN.


Please don’t anthropomorphize ChatGPT.


No.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: