Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature request: support Zero Trust networking #308

Open
ruzko opened this issue Feb 23, 2024 · 4 comments
Open

Feature request: support Zero Trust networking #308

ruzko opened this issue Feb 23, 2024 · 4 comments

Comments

@ruzko
Copy link

ruzko commented Feb 23, 2024

Hi!

I'm building a free software project to offer predator alerts and deterrence for farms, using NVR and zero-trust, overlay mesh networking. There aren't any NVR offerings which implement zero-trust principles directly at this time, so in testing I've mostly had to try "bolting on" that capability, using OpenZiti and their tunnelers.

The OpenZiti maintainers suggested on a forum post I made about my project, that embedding OpenZiti using their SDKs would be ideal.
OpenZiti has SDKs for embedding zero-trust communication in applications, which is superior to the tunneling approach both in terms of security and usability. They don't have a rust SDK yet, but the C SDK is usable via FFI.

OpenZiti can bootstrap a regular browser session into zero-trust without needing to install anything on the client device, by relying on an OIDC provider. For PWAs like Moonfire, this is nice.

Being written in Rust, Moonfire is a prime candidate for security-minded environments.

I'd like to see integrated support for zero-trust networking in Moonfire, and am prepared to spend ~40 hours on it initially.
Is integrated zero-trust via OpenZiti something you'd consider supporting in Moonfire?

*edit: this would touch on #27, #26, #216, #154, and #133

@scottlamb
Copy link
Owner

I finally did some reading on OpenZiti.

So the idea is that this would be for the browser->Moonfire leg? And it would be an alternative to binding a TCP port which is reachable by the client (over the LAN, VPN, or public Internet)? And Moonfire could use Ziti APIs to provide authenticated identity and possibly even role-based authorization, as an alternative to the current password->web session or Unix socket permissions-based authentication and/or the per-user permissions in its own database?

I'm looking through a few details of how it might work.

Build/linking: we'd have to link to the OpenZiti APIs. I don't know if it's too compatible with the "build a zero-dependencies, almost-pure-Rust binary" approach I've adopted. How would you feel about this being an optional feature not included in the main release builds?

Threading model: I don't see this documented in their SDK docs. Currently Moonfire uses a multi-threaded tokio reactor. Is Ziti thread-safe? or would we need to handle all Ziti operations in one thread?

General lifecycle: looks like for each [[bind]] ziti = ... item we'd set up a service with ziti_listen. Then in ziti_client_cb, ziti_accept it, then in ziti_conn_cb set up a matching hyper Connection. We receive data via ziti_read_cb; we start writes via ziti_write and get their completion status via ziti_write_cb. Closing happens by ziti_close (locally initiated) / ziti_close_cb (fully closed by either party).

Flow control: I'm a little concerned that I don't see much mention of this.

  • Read side: Looks like Ziti calls us via ziti_read_cb. Hyper expects to drive the thing, reading when it wants to. How do we bridge those? Is there a way to tell Ziti "stop reading for a while" / "start reading again"? or do we have to buffer everything that comes in and just drop the connection abruptly if the inbound buffer becomes absurdly large?
  • Write side: We could make a tokio::io::AsyncWrite impl in which poll_write returns not ready between our call to ziti_write and the matching ziti_write_cb acknowledgement. Possibly we have to layer on our own buffering and only start those writes after reaching a threshold or on poll_flush calls to avoid short writes though, as if I'm understanding correctly only one write can be in flight at once.

@scottlamb
Copy link
Owner

btw, there's something vaguely similar I've been thinking of adding: Cloudflare Tunnel support, perhaps via the libcfd crate if it matures a bit. Comparing the two...

  • Cloudflare Tunnel is similar in that it's described as Zero Trust Networking and is something where you use a client library that connects to some other entity and gives you abstract connections, instead of you directly accepting TCP conns from the OS.
  • My intent may be more modest. Where I think you're looking to use OpenZiti to provide a way of keeping outsiders from connecting to Moonfire at all and get some level of client identity information, I'm thinking of Cloudflare Tunnel as an alternative way to expose "stuff" (both Moonfire's HTTP endpoint and possibly camera config UIs) to the public Internet without requiring you to do port forwarding + dynamic DNS + TLS cert management. But I guess Cloudflare Tunnel can do more; the landing page says this:

    When Tunnel is combined with Cloudflare Access, our comprehensive Zero Trust access solution, users are authenticated by major identity providers (like Gsuite and Okta) without the help of a VPN.

  • A mature libcfd would be a pure Rust approach: rustls rather than openssl, tokio rather than libuv, easily able to be added to the default zero-dependencies binary.
  • One downside of Cloudflare Tunnel is that it's a single-vendor thing which relates to paid services. It looks like the basic stuff is free, but I doubt Cloudflare Access is.

@scottlamb
Copy link
Owner

A third option in this general space is Tailscale. Again it's a commercial freemium service thing. They have a page here on enabling https that mentions Caddy integration; we could rely on something external (tailscale's software or caddy) or add similar integration to Moonfire.

@ruzko
Copy link
Author

ruzko commented Apr 19, 2024

Thanks for replying :)
I had some trouble getting Moonfire up and running reliably, and to connect to the cameras in my network. I needed to have a working prototype (for my thesis) two weeks after this issue was opened, so I restarted work on a NVR project in Python I'd developed previously. If I manage to get some funding to keep working after my thesis finishes in June; I'm still keen on reimplementing stuff in Rust for Moonfire.

A central theme in the thesis is how transparency and digital self-sovereignity is crucial for building trust and security in a rapidly IoT-connected world. The NVR project I'm working on for the thesis is licensed AGPLv3-or-later, to ensure that users always have access to the source code, even if a service provider decides to sell it as a service; e.g. by linking their cams to a cloud-hosted NVR server.

This might be a little off-topic, but may I ask why you chose GPLv3-or-later over AGPLv3-or-later for Moonfire?

So the idea is that this would be for the browser->Moonfire leg? And it would be an alternative to binding a TCP port which is reachable by the client (over the LAN, VPN, or public Internet)? And Moonfire could use Ziti APIs to provide authenticated identity and possibly even role-based authorization, as an alternative to the current password->web session or Unix socket permissions-based authentication and/or the per-user permissions in its own database?

Yes, to all of that. A future possibility as well is splicing into the radio circuits of an existing camera with a daugtherboard running openziti SDK, so the cam <--> Moonfire connection is zero trust as well; or running openziti SDK on an open-firmware cam.

How would you feel about this being an optional feature not included in the main release builds?
Sure, that'd be alright. In order to make use of Openziti the user would have to get access to a ziti network (ziti controller + ziti edge router) either via a network provider like Netfoundry; or by spinning up their own network. Since Moonfire philosophy is minimalistic wrt deps and binary size, having ZT as a build option or separate release for those who need it makes sense.

I've got good experiences with using Cloudflare Tunnels, as well as their Access thing. It works. Buut it's kinda sus that it has a couple neat features, that can easily enable Cloudflare (or attackers in their infra) to extract info; and the backend is proprietary. It works and I use it for some non-critical services, but I don't feel good about it.

Same deal with Tailscale, although they're significantly smaller and don't have as much of a stranglehold on global network infra as CF. It's also way more sysadmin oriented. There's thankfully an open implementation of Tailscale's backend, Headscale, but I couldn't get it to work right.

For the technicalities of using Openziti in Rust, I'm not sure. My experience is via the Python SDK, which uses the C SDK under the hood; but there are probably differences between using it in Python or Rust. Pinging @dovholuknf, who has helped me out a lot regarding Python; could you chime in?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants