From 3a67eacfbe73349e74310f92d22fee22d8ce9fdb Mon Sep 17 00:00:00 2001 From: Reactor Scram Date: Wed, 10 Apr 2024 17:01:55 -0500 Subject: [PATCH] refactor(linux-client): replace `client-tunnel` with `headless-client` which is the same thing (#4516) Unfortunately I had to keep `linux-client` to get the compatibility tests to pass. #4578 aims to remove that package. Please add to this list if you think of anything: ```[tasklist] # Things that may break that CI/CD won't catch - [ ] Github release artifacts - [ ] Knowledge base - [ ] Docker images - [ ] Docker containers - [ ] Existing `linux-client` users - [ ] Anything that downloads ghcr artifacts - [ ] Nix (Not sure if it's built in CI. It had a merge conflict) ``` Refs #4515, and #3712, #3782 I think this is what Thomas and I agreed on in Slack / Github --------- Signed-off-by: Reactor Scram Co-authored-by: Thomas Eizinger --- .github/actions/setup-rust/action.yml | 2 +- .github/workflows/e2e.yml | 4 +- docker-compose.yml | 1 + docs/README.md | 2 +- rust/Cargo.lock | 46 ++++++------- rust/Cargo.toml | 7 +- rust/client-tunnel/README.md | 10 --- rust/docker-compose-dev.yml | 2 +- rust/gui-client/docs/process_split.md | 2 + rust/gui-client/src-tauri/Cargo.toml | 2 +- .../src/bin/firezone-client-tunnel.rs | 2 +- .../Cargo.toml | 6 +- rust/headless-client/README.md | 65 +++++++++++++++++++ .../docs/debian_dns.md | 0 .../docs/use_cases.md | 0 .../src/lib.rs | 0 .../src/linux.rs | 0 rust/headless-client/src/main.rs | 4 ++ rust/linux-client/Cargo.toml | 5 +- rust/linux-client/README.md | 54 +-------------- rust/linux-client/src/main.rs | 2 +- scripts/nix/flake.nix | 4 +- scripts/tests/systemd/dns-systemd-resolved.sh | 2 +- 23 files changed, 117 insertions(+), 105 deletions(-) delete mode 100644 rust/client-tunnel/README.md rename rust/{client-tunnel => headless-client}/Cargo.toml (90%) create mode 100644 rust/headless-client/README.md rename rust/{linux-client => headless-client}/docs/debian_dns.md (100%) rename rust/{linux-client => headless-client}/docs/use_cases.md (100%) rename rust/{client-tunnel => headless-client}/src/lib.rs (100%) rename rust/{client-tunnel => headless-client}/src/linux.rs (100%) create mode 100644 rust/headless-client/src/main.rs diff --git a/.github/actions/setup-rust/action.yml b/.github/actions/setup-rust/action.yml index b582afbfe..ca72b4b8d 100644 --- a/.github/actions/setup-rust/action.yml +++ b/.github/actions/setup-rust/action.yml @@ -22,7 +22,7 @@ outputs: value: ${{ (runner.os == 'Linux' && '--workspace') || (runner.os == 'macOS' && '-p connlib-client-apple -p connlib-client-shared -p firezone-tunnel -p snownet') || - (runner.os == 'Windows' && '-p connlib-client-shared -p firezone-client-tunnel -p firezone-gui-client -p firezone-tunnel -p snownet') }} + (runner.os == 'Windows' && '-p connlib-client-shared -p firezone-headless-client -p firezone-gui-client -p firezone-tunnel -p snownet') }} runs: using: "composite" diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 754c6d27f..7a4375185 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -151,10 +151,10 @@ jobs: sccache_enabled: false targets: x86_64-unknown-linux-gnu - run: | - cargo build --package firezone-linux-client + cargo build --package firezone-headless-client # TODO Run tests - # ./target/debug/firezone-linux-client + # ./target/debug/firezone-headless-client android: needs: setup diff --git a/docker-compose.yml b/docker-compose.yml index 01a7dc004..9fe773f59 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -295,6 +295,7 @@ services: cache_from: - type=registry,ref=us-east1-docker.pkg.dev/firezone-staging/cache/client:main args: + # TODO: Fix after #4516 lands PACKAGE: firezone-linux-client image: ${CLIENT_IMAGE:-us-east1-docker.pkg.dev/firezone-staging/firezone/dev/client}:${CLIENT_TAG:-main} cap_add: diff --git a/docs/README.md b/docs/README.md index 8ad1d0285..91ed31da0 100644 --- a/docs/README.md +++ b/docs/README.md @@ -97,7 +97,7 @@ product documentation, organized as follows: and deployed to your infrastructure. - [rust/relay](../rust/relay): Relay - STUN/TURN server to facilitate holepunching. - - [rust/linux-client](../rust/linux-client): Linux CLI client. + - [rust/headless-client](../rust/headless-client): Cross-platform CLI client. - [rust/gui-client](../rust/gui-client): Cross-platform GUI client. - [swift/](../swift/apple): macOS / iOS clients. - [kotlin/](../kotlin/android): Android / ChromeOS clients. diff --git a/rust/Cargo.lock b/rust/Cargo.lock index e72915adb..770a7bb24 100644 --- a/rust/Cargo.lock +++ b/rust/Cargo.lock @@ -1848,27 +1848,6 @@ dependencies = [ "url", ] -[[package]] -name = "firezone-client-tunnel" -version = "0.1.0" -dependencies = [ - "anyhow", - "clap", - "connlib-client-shared", - "connlib-shared", - "dirs", - "firezone-cli-utils", - "humantime", - "nix 0.28.0", - "resolv-conf", - "secrecy", - "serde", - "serde_json", - "tokio", - "tracing", - "url", -] - [[package]] name = "firezone-gateway" version = "1.0.0" @@ -1915,7 +1894,7 @@ dependencies = [ "connlib-shared", "crash-handler", "dirs", - "firezone-client-tunnel", + "firezone-headless-client", "futures", "git-version", "hex", @@ -1954,12 +1933,33 @@ dependencies = [ "zip", ] +[[package]] +name = "firezone-headless-client" +version = "1.0.0" +dependencies = [ + "anyhow", + "clap", + "connlib-client-shared", + "connlib-shared", + "dirs", + "firezone-cli-utils", + "humantime", + "nix 0.28.0", + "resolv-conf", + "secrecy", + "serde", + "serde_json", + "tokio", + "tracing", + "url", +] + [[package]] name = "firezone-linux-client" version = "1.0.0" dependencies = [ "anyhow", - "firezone-client-tunnel", + "firezone-headless-client", "tokio", ] diff --git a/rust/Cargo.toml b/rust/Cargo.toml index 68a69bc4a..92e7ad4d3 100644 --- a/rust/Cargo.toml +++ b/rust/Cargo.toml @@ -1,6 +1,5 @@ [workspace] members = [ - "client-tunnel", "connlib/clients/android", "connlib/clients/apple", "connlib/clients/shared", @@ -8,8 +7,9 @@ members = [ "connlib/tunnel", "connlib/snownet", "gateway", - "linux-client", "firezone-cli-utils", + "headless-client", + "linux-client", "snownet-tests", "phoenix-channel", "relay", @@ -39,9 +39,8 @@ rtnetlink = { version = "0.14.1", default-features = false, features = ["tokio_s connlib-client-android = { path = "connlib/clients/android"} connlib-client-apple = { path = "connlib/clients/apple"} connlib-client-shared = { path = "connlib/clients/shared"} -firezone-client-tunnel = { path = "client-tunnel" } firezone-gateway = { path = "gateway"} -firezone-linux-client = { path = "linux-client"} +firezone-headless-client = { path = "headless-client"} firezone-gui-client = { path = "gui-client/src-tauri"} firezone-cli-utils = { path = "firezone-cli-utils"} snownet = { path = "connlib/snownet"} diff --git a/rust/client-tunnel/README.md b/rust/client-tunnel/README.md deleted file mode 100644 index 44f3d4554..000000000 --- a/rust/client-tunnel/README.md +++ /dev/null @@ -1,10 +0,0 @@ -# firezone-client-tunnel - -A privileged tunnel process that can communicate with the Linux GUI Client (and eventually Windows) - -## Files - -- `/etc/dev.firezone.client/token` - The service account token, provided by the human administrator. Must be owned by root and have 600 permissions (r/w by owner, nobody else can read) If present, the tunnel will ignore any GUI Client and run as a headless Client. If absent, the tunnel will wait for commands from a GUI Client -- `/usr/bin/firezone-client-tunnel` - The tunnel binary. This must run as root so it can modify the system's DNS settings. If DNS is not needed, it only needs CAP_NET_ADMIN. -- `/usr/lib/systemd/system/firezone-client-tunnel.service` - A systemd service unit, installed by the deb package. -- `/var/lib/dev.firezone.client/config/firezone-id` - The device ID, unique across an organization. The tunnel will generate this if it's not present. diff --git a/rust/docker-compose-dev.yml b/rust/docker-compose-dev.yml index d4ca6bd9d..a16bc347e 100644 --- a/rust/docker-compose-dev.yml +++ b/rust/docker-compose-dev.yml @@ -4,7 +4,7 @@ services: build: target: test volumes: - - ./rust/target/x86_64-unknown-linux-musl/debug/firezone-linux-client:/bin/firezone-linux-client + - ./rust/target/x86_64-unknown-linux-musl/debug/firezone-headless-client:/bin/firezone-headless-client gateway: build: diff --git a/rust/gui-client/docs/process_split.md b/rust/gui-client/docs/process_split.md index 2a0b0c490..978b9b281 100644 --- a/rust/gui-client/docs/process_split.md +++ b/rust/gui-client/docs/process_split.md @@ -1,3 +1,5 @@ +(TODO: Change "client-tunnel" to "headless-client") + # Process split This is meant for Linux, but it will be similar on Windows. diff --git a/rust/gui-client/src-tauri/Cargo.toml b/rust/gui-client/src-tauri/Cargo.toml index 3c3fd29fd..42f873297 100644 --- a/rust/gui-client/src-tauri/Cargo.toml +++ b/rust/gui-client/src-tauri/Cargo.toml @@ -20,7 +20,7 @@ clap = { version = "4.5", features = ["derive", "env"] } connlib-client-shared = { workspace = true } connlib-shared = { workspace = true } crash-handler = "0.6.1" -firezone-client-tunnel = { path = "../../client-tunnel" } +firezone-headless-client = { path = "../../headless-client" } git-version = "0.3.9" hex = "0.4.3" # Same crate Hickory uses diff --git a/rust/gui-client/src-tauri/src/bin/firezone-client-tunnel.rs b/rust/gui-client/src-tauri/src/bin/firezone-client-tunnel.rs index b640f16b8..d55e6595c 100644 --- a/rust/gui-client/src-tauri/src/bin/firezone-client-tunnel.rs +++ b/rust/gui-client/src-tauri/src/bin/firezone-client-tunnel.rs @@ -1,4 +1,4 @@ #[tokio::main] async fn main() -> anyhow::Result<()> { - firezone_client_tunnel::run().await + firezone_headless_client::run().await } diff --git a/rust/client-tunnel/Cargo.toml b/rust/headless-client/Cargo.toml similarity index 90% rename from rust/client-tunnel/Cargo.toml rename to rust/headless-client/Cargo.toml index 20b156a10..8107003b8 100644 --- a/rust/client-tunnel/Cargo.toml +++ b/rust/headless-client/Cargo.toml @@ -1,7 +1,9 @@ [package] -name = "firezone-client-tunnel" -version = "0.1.0" +name = "firezone-headless-client" +# mark:automatic-version +version = "1.0.0" edition = "2021" +authors = ["Firezone, Inc."] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/rust/headless-client/README.md b/rust/headless-client/README.md new file mode 100644 index 000000000..df1aabbe0 --- /dev/null +++ b/rust/headless-client/README.md @@ -0,0 +1,65 @@ +# headless-client + +This crate acts as the CLI / headless Client, and the privileged tunnel service for the GUI Client, for both Linux and Windows. + +It is built as: +- `linux-client` to act as the Linux headless Client +- `firezone-headless-client` to act as the Linux tunnel service, Windows headless Client, or Windows tunnel service + +In general, the brand name should be part of the file name, but the OS name should not be. + +## Running + +To run the headless Client: + +1. Generate a new Service account token from the "Actors -> Service Accounts" + section of the admin portal and save it in your secrets manager. The Firezone + Linux client requires a service account at this time. +1. Ensure `/etc/dev.firezone.client/token` is only readable by root (i.e. `chmod 400`) +1. Ensure `/etc/dev.firezone.client/token` contains the Service account token. The Client needs this before it can start +1. Set `FIREZONE_ID` to a unique string to identify this client in the portal, + e.g. `export FIREZONE_ID=$(uuidgen)`. The client requires this variable at + startup. +1. Set `LOG_DIR` to a suitable directory for writing logs + ``` + export LOG_DIR=/tmp/firezone-logs + mkdir $LOG_DIR + ``` +1. Now, you can start the client with: + +``` +./firezone-headless-client +``` + +If you're running as an unprivileged user, you'll need the `CAP_NET_ADMIN` +capability to open `/dev/net/tun`. You can add this to the client binary with: + +``` +sudo setcap 'cap_net_admin+eip' /path/to/firezone-headless-client +``` + + +## Building + +Assuming you have Rust installed, you can build the headless Client with: + +``` +cargo build --release -p firezone-headless-client +``` + +The binary will be in `target/release/firezone-headless-client` + +The release on Github are built with musl. To build this way, use: + +```bash +rustup target add x86_64-unknown-linux-musl +sudo apt-get install musl-tools +cargo build --release -p headless-client --target x86_64-unknown-linux-musl +``` + +## Files + +- `/etc/dev.firezone.client/token` - The service account token, provided by the human administrator. Must be owned by root and have 600 permissions (r/w by owner, nobody else can read) If present, the tunnel will ignore any GUI Client and run as a headless Client. If absent, the tunnel will wait for commands from a GUI Client +- `/usr/bin/firezone-headless-client` - The tunnel binary. This must run as root so it can modify the system's DNS settings. If DNS is not needed, it only needs CAP_NET_ADMIN. +- `/usr/lib/systemd/system/firezone-headless-client.service` - A systemd service unit, installed by the deb package. +- `/var/lib/dev.firezone.client/config/firezone-id` - The device ID, unique across an organization. The tunnel will generate this if it's not present. diff --git a/rust/linux-client/docs/debian_dns.md b/rust/headless-client/docs/debian_dns.md similarity index 100% rename from rust/linux-client/docs/debian_dns.md rename to rust/headless-client/docs/debian_dns.md diff --git a/rust/linux-client/docs/use_cases.md b/rust/headless-client/docs/use_cases.md similarity index 100% rename from rust/linux-client/docs/use_cases.md rename to rust/headless-client/docs/use_cases.md diff --git a/rust/client-tunnel/src/lib.rs b/rust/headless-client/src/lib.rs similarity index 100% rename from rust/client-tunnel/src/lib.rs rename to rust/headless-client/src/lib.rs diff --git a/rust/client-tunnel/src/linux.rs b/rust/headless-client/src/linux.rs similarity index 100% rename from rust/client-tunnel/src/linux.rs rename to rust/headless-client/src/linux.rs diff --git a/rust/headless-client/src/main.rs b/rust/headless-client/src/main.rs new file mode 100644 index 000000000..d55e6595c --- /dev/null +++ b/rust/headless-client/src/main.rs @@ -0,0 +1,4 @@ +#[tokio::main] +async fn main() -> anyhow::Result<()> { + firezone_headless_client::run().await +} diff --git a/rust/linux-client/Cargo.toml b/rust/linux-client/Cargo.toml index f4f4f843c..49d52d142 100644 --- a/rust/linux-client/Cargo.toml +++ b/rust/linux-client/Cargo.toml @@ -3,13 +3,14 @@ name = "firezone-linux-client" # mark:automatic-version version = "1.0.0" edition = "2021" +authors = ["Firezone, Inc."] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] anyhow = { version = "1.0" } -firezone-client-tunnel = { workspace = true } -tokio = { version = "1.36", default-features = false, features = ["rt", "macros"] } +firezone-headless-client = { path = "../headless-client" } +tokio = { version = "1.36.0", features = ["macros", "signal"] } [lints] workspace = true diff --git a/rust/linux-client/README.md b/rust/linux-client/README.md index f09b11a0f..f8c5066af 100644 --- a/rust/linux-client/README.md +++ b/rust/linux-client/README.md @@ -1,53 +1 @@ -# linux-client - -This crate houses the Firezone linux client. - -## Building - -Assuming you have Rust installed, you can build the Linux client from a Linux -host with: - -``` -cargo build --release --bin firezone-linux-client -``` - -You should then find a binary in `target/release/firezone-linux-client`. - -The releases on Github are built with musl. To build this way, use: - -```bash -rustup target add x86_64-unknown-linux-musl -sudo apt-get install musl-tools -cargo build --release --bin firezone-linux-client --target x86_64-unknown-linux-musl -``` - -## Running - -To run the Linux client: - -1. Generate a new Service account token from the "Actors -> Service Accounts" - section of the admin portal and save it in your secrets manager. The Firezone - Linux client requires a service account at this time. -1. Ensure the `FIREZONE_TOKEN=` environment variable is - set securely in your client's shell environment. The client requires this - variable at startup. -1. Set `FIREZONE_ID` to a unique string to identify this client in the portal, - e.g. `export FIREZONE_ID=$(uuidgen)`. The client requires this variable at - startup. -1. Set `LOG_DIR` to a suitable directory for writing logs - ``` - export LOG_DIR=/tmp/firezone-logs - mkdir $LOG_DIR - ``` -1. Now, you can start the client with: - -``` -./firezone-linux-client -``` - -If you're running as an unprivileged user, you'll need the `CAP_NET_ADMIN` -capability to open `/dev/net/tun`. You can add this to the client binary with: - -``` -sudo setcap 'cap_net_admin+eip' /path/to/firezone-linux-client -``` +This is a stub to fix a build issue in CI. Remove it once PR #4516 is merged into main. diff --git a/rust/linux-client/src/main.rs b/rust/linux-client/src/main.rs index b640f16b8..d55e6595c 100644 --- a/rust/linux-client/src/main.rs +++ b/rust/linux-client/src/main.rs @@ -1,4 +1,4 @@ #[tokio::main] async fn main() -> anyhow::Result<()> { - firezone_client_tunnel::run().await + firezone_headless_client::run().await } diff --git a/scripts/nix/flake.nix b/scripts/nix/flake.nix index a67a017f3..d88d671a1 100644 --- a/scripts/nix/flake.nix +++ b/scripts/nix/flake.nix @@ -63,9 +63,9 @@ }; in { - packages.firezone-linux-client = naersk.buildPackage { + packages.firezone-headless-client = naersk.buildPackage { name = "foo"; - src = ../../rust/linux-client; + src = ../../rust/headless-client; }; devShells.default = mkShellWithRustVersion [ diff --git a/scripts/tests/systemd/dns-systemd-resolved.sh b/scripts/tests/systemd/dns-systemd-resolved.sh index acf49523a..4a37226d7 100755 --- a/scripts/tests/systemd/dns-systemd-resolved.sh +++ b/scripts/tests/systemd/dns-systemd-resolved.sh @@ -5,7 +5,7 @@ set -euo pipefail BINARY_NAME=firezone-linux-client -docker compose exec client cat firezone-linux-client >"$BINARY_NAME" +docker compose exec client cat firezone-linux-client > "$BINARY_NAME" chmod u+x "$BINARY_NAME" sudo mv "$BINARY_NAME" "/usr/bin/$BINARY_NAME" # TODO: Check whether this is redundant with the systemd service file