-
Notifications
You must be signed in to change notification settings - Fork 269
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
docs(linux-client): launch modes, flags, etc, for Linux CLI and GUI #4106
Conversation
The latest updates on your projects. Learn more about Vercel for Git ↗︎ 1 Ignored Deployment
|
Terraform Cloud Plan Output
|
Performance Test ResultsTCP
UDP
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think maybe we should backup here a bit and rethink the design to simplify things, otherwise this is going to be a nightmare to maintain going forward.
What do you think of this approach? I tried to take the best parts of your initial design and simplify them to the common use cases I expect users to encounter:
- Have a separate, standalone binary,
firezone-client
with the current CLI flags, DNS behavior, etc. This can run on its own as a plain binary, via systemd, or Docker like it does now. This always runs as a privileged user. - Have a separate, standalone GUI binary,
firezone-gui
that handles auth essentially and UI notifications, and that's it. This always runs unprivileged. - They speak to each over over an IPC interface just like the FFI between the other clients. They could both belong to the same
firezone
group and speak JSON over a Unix socket for example. To testfirezone-gui
, we can use a mockfirezone-client
that responds to the calls, and vice-versa. firezone-gui
can "call" Session.connect with similar parameters as the other clients to launchfirezone-client
.- Accordingly,
firezone-client
checks for a token inENV
upon launch and calls itsSession.connect
if it finds it, otherwise it waits idle for the GUI to callconnect
over the IPC interface with a token provided. onUpdateRoutes
, happens insidefirezone-client
only.onUpdateResources
issues a "callback" over the IPC interface to the GUI to update the list of Resources, etc.- The token is stored in the user's keychain
firezone-gui
(or similar).
If firezone-client
is running from a GUI launch, it should open the IPC interface. Otherwise, if it's running from a standalone install, don't start the IPC interface. Then, if firezone-gui
is launched with already-running firezone-client
that it started previously, it can connect to it and populate the Resources list, and the menu items will be functional -- Sign out, Disconnect and Quit, etc. Otherwise, if a firezone-gui
is trying to control firezone-client
that's managed via systemd with a Service Account token, "Sign out" doesn't make any sense.
The above model should work similarly for Windows as well -- the firezone-client.exe tunnel service operated by the firezone-gui.exe frontend, communicating over a bidirectional local socket.
When building firezone-gui
with Tauri, we can just bundle firezone-client
as a sidecar binary. This should make signing a similar process for both Linux (gpg) and Windows as well.
(Without thinking of systemd yet) | ||
|
||
1. No GUI allowed | ||
2. GUI spawns its own tunnel subprocess |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can a userspace gui spawn a privileged process?
If we can spawn the process from the GUI binary after launch then package management becomes much easier, but I suspect we'll hit issues with this approach. For example -- if I add a shortcut to my GNOME desktop to launch firezone, does that launch using sudo
too? What if sudo requires a password?
If we can't reliably spawn a privileged process, then we might be stuck with the two process model. In this case then we can ship two binaries in the GUI package and configure setuid / setcap in the postinst
or equivalent packaging script.
This should already be a solved problem in Linux -- aren't there userspace applications that need access to privileged devices, and access is controlled via group membership? E.g. udev or docker or network groups. The "privileged daemon / userspace client" model seems well-used in Linux so maybe that's why I keep intuitively going back to it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't understand. If we're spawning another process then we are using two processes, right? Running the GUI as root is breaking a lot of stuff, so if the GUI spawns a tunnel subprocess, that means the GUI sticks around as the non-privileged parent process.
Sudo will require a password on most systems. There is a graphical sudo for desktop environments that will kick in, sometimes I think it happens automagically even if we just call sudo
in the app.
Yeah we should see what Docker does. "Privileged daemon / userspace client" would be Mode 3 in this doc.
Due to DNS I think we are required to run the tunnel as root. I didn't find any more fine-grained security for setting DNS on an interface. (Other than hooking into NetworkManager) If we run as root, there's no need to do setcap.
I think we're really still talking past each other on 2 processes vs 2 binaries. We can run a privileged process and an unprivileged process from the same binary. Even if unprivileged code has a vulnerability and jumps into privileged code, it couldn't do anything since it won't have root powers.
So there is no need to package 2 binaries using Tauri sidecar bundling or anything - It's already easy to do Busybox-style multi-call binaries where two "binaries" are packed into one binary at the source code level, and I'm already doing that for the crash handling.
Like I would not be surprised if it turns out that Docker's privileged daemon and non-privileged userspace client both run from the same binary on disk. That's how web browsers do it.
|
||
1. No GUI allowed | ||
2. GUI spawns its own tunnel subprocess | ||
3. GUI and tunnel start up separately, GUI connects to the tunnel |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was thinking either (2) or (3), but not both just to keep things as simple as possible for the two use cases.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure maybe we should focus on (3) first. (2) requires sudo so it's like, if you're a power user with sudo powers, you could just use the CLI, or you would have the expertise to configure Mode 3 anyway.
The only reason I was thinking of starting with Mode 2 is that it might be simpler to test, and the security is simpler (The processes trust each other based on a parent-child relationship, same as web browsers do) But customers probably won't want Mode 2, they'll probably need Mode 3.
|
||
(These might actually be subcommands, but I kept the leading hyphens for now.) | ||
|
||
`firezone-linux-client` only accepts `--headless`, for the purpose of flag compatibility with `firezone-gui-client`. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's ok if they don't have flag compatibility I think
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Right now the Tauri bundles have the binary as just firezone
, honestly I'd prefer it be more descriptive, e.g. firezone-cli-client
and firezone-gui-client
. We can allow the arch and OS to be implicit, but firezone
could be anything, even a gateway if we ever allow Clients and Gateways on the same system.
The flags must be compatible between both binaries, since they may be installed as `firezone-client`. | ||
|
||
1. `--headless` means Mode 1. `firezone-gui-client` pretends to be `firezone-linux-client`, refusing any GUI connections. | ||
2. `--standalone-gui` means Mode 2. `firezone-gui-client` becomes a GUI process, then calls `sudo` to launch its own tunnel subprocess. Closing the GUI closes the tunnel. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
sudo
is a complex system -- I'm not sure we can rely on the assumption it will be callable in the manner you're expecting.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
True, they may want it to run on a system where normal users don't have sudo
powers. But in that case they wouldn't be using Mode 2, they'd be using Mode 3, which doesn't need sudo
.
|
||
# CLI / GUI conflict | ||
|
||
What if both packages are installed on the system? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In many cases the headless client won't use a package manager (e.g. Docker)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's ok if both packages are installed, but you wouldn't want to allow both to run at the same time due to route conflicts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Okay well even without a package manager, if we say "Put this systemd unit here" then either they have the same name to make the conflict obvious, or they have separate names and remind customers not to enable / run both at once.
Windows even supports domain sockets since 2018: https://stackoverflow.com/questions/3872558/af-unix-in-windows |
Just some more thoughts... Starting |
Yeah there's a lot to think about
|
Will re-draft this |
Right now it only works on my dev VM, not on my test VMs, due to #4053 and #4103, but it passes tests and should be safe to merge. There's one doc fix and one script fix which are unrelated and could be their own PRs, but they'd be tiny, so I left them in here. Ref #4106 and #3713 for the plan to fix all this by splitting the tunnel process off so that the GUI runs as a normal user.
Closing in favor of #4153 |
This is my proposal for the CLI and GUI to get along and for the GUI to do whatever customers need.