diff --git a/crates/core/tedge_write/src/bin.rs b/crates/core/tedge_write/src/bin.rs index c1da3f9753..0ad1195acf 100644 --- a/crates/core/tedge_write/src/bin.rs +++ b/crates/core/tedge_write/src/bin.rs @@ -6,12 +6,13 @@ use camino::Utf8PathBuf; use clap::Parser; use tedge_utils::atomic::MaybePermissions; -/// A binary used for writing to files which `tedge` user does not have write permissions for, using -/// sudo. +/// tee-like helper for writing to files which `tedge` user does not have write permissions to. +/// +/// To be used in combination with sudo, passing the file content via standard input. #[derive(Debug, Clone, PartialEq, Eq, Parser)] -#[command(about, version, long_about = None)] +#[command(about, version, long_about)] pub struct Args { - /// A canonical path to a file which will be written to. + /// A canonical path to a file to which standard input will be written. /// /// If the file does not exist, it will be created with the specified owner/group/permissions. /// If the file does exist, it will be overwritten, but its owner/group/permissions will remain diff --git a/crates/core/tedge_write/src/lib.rs b/crates/core/tedge_write/src/lib.rs index 88818e41af..483ae73fd5 100644 --- a/crates/core/tedge_write/src/lib.rs +++ b/crates/core/tedge_write/src/lib.rs @@ -18,7 +18,10 @@ //! - an implementation of the `tedge-write` binary //! - tedge-write API meant to be called by other tedge-components //! -//! https://github.com/thin-edge/thin-edge.io/issues/2456 +//! # References +//! +//! - https://github.com/thin-edge/thin-edge.io/issues/2456 +//! - docs/src/references/tedge-write.md const TEDGE_WRITE_BINARY: &str = "tedge-write"; diff --git a/docs/src/references/agent/tedge-configuration-management.md b/docs/src/references/agent/tedge-configuration-management.md index 5f39962aca..1cea746303 100644 --- a/docs/src/references/agent/tedge-configuration-management.md +++ b/docs/src/references/agent/tedge-configuration-management.md @@ -216,6 +216,8 @@ Upon receiving a configuration update command, the agent performs the following 1. It performs a `GET` request to the `tedgeUrl` specified in the command to retrieve the content. 2. The agent then uses the `type` information (`mosquitto`) to to look up the target path from the `tedge-configuration-plugin.toml` file and applies the new configuration content to the corresponding `path`(`/etc/mosquitto/mosquitto.conf`). + If `tedge` user/group does not have write permissions to the path and its parent directory, + [`tedge-write`](../tedge-write.md) will be used in combination with `sudo` for permission elevation. Throughout the process, the agent updates the command status via MQTT by publishing a retained message to the same `//cmd/config_update/` topic diff --git a/docs/src/references/tedge-write.md b/docs/src/references/tedge-write.md new file mode 100644 index 0000000000..7111b52c24 --- /dev/null +++ b/docs/src/references/tedge-write.md @@ -0,0 +1,77 @@ +--- +title: tedge-write +tags: [Reference, Configuration, CLI] +description: Granting thin-edge write access to protected files +--- + +**tedge-write** is a `tee`-like helper %%te%% component used by **tedge-agent** for privilege elevation. + +tedge-agent spawns a `tedge-write` process when it needs to write to files that `tedge` +user/group has no write permissions to (e.g. system files or files owned by other packages), for +example when writing an updated configuration file as part of [`config_update` operation][1]. +`tedge-agent` will first try to write to a file directly and only retry using `tedge-write` if +direct write fails due to `tedge` user/group not having write permissions to either the file itself +or its parent directory. + +[1]: agent/tedge-configuration-management.md#handling-config-update-commands + +## Permission elevation + +`tedge-write` relies on `sudo` to grant the process write and execute permissions to the target +file's parent directory. + +For example, when using following `sudoers` entry: + +```sudoers title="file: /etc/sudoers.d/tedge" +tedge ALL = (ALL) NOPASSWD: /usr/bin/tedge-write /etc/* +``` + +Permissions are granted when: + +- calling user is `tedge` +- binary is `/usr/bin/tedge-write` +- the 1st argument is `/etc/*`, i.e. the files `tedge-write` will be writing to are inside `/etc` + +The entry grants privileges without authentication, which is required when `tedge-write` is spawned +by `tedge-agent`. + + +:::note + +When %%te%% is installed using any one of the standard installation methods, the sudoers entry is +automatically created under `/etc/sudoers.d/tedge`, but in non-standard setups the sudoers +configuration may need to be updated manually. + +Feel free to customise the sudoers entry according to your requirements, but make sure the entry +correctly grants privileges to all required files and a full and valid path to `tedge-write` binary +is used. + +See [`sudoers(5)`][2] for additional details. + +::: + +[2]: https://www.man7.org/linux/man-pages/man5/sudoers.5.html + +If you prefer to disable this permission elevation mechanism or don't want to use `sudo`, set the +tedge config `sudo.enable` setting to `false`. `tedge-write` will still get spawned, but without +`sudo`. + +```sh +sudo tedge config set sudo.enable false +``` + +## Details + +Write permission to the parent directory is required to guarantee config updates are atomic. + + +While updating a file, `tedge-write` will perform an atomic write, i.e. it will write to a temporary +file, set file ownership and mode, and finally rename the temporary into the final file. +If the target file already exists, its original ownership/mode will be preserved and optionally +provided new values will be ignored. + + +## Command help + +```sh command="tedge-write --help" title="tedge-write --help" +```