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

Extend the 'per-device serviceinfo configuration' feature with files and commands #617

Open
wants to merge 31 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
719c3d8
Add functionality
RZandvoort Feb 7, 2024
4804eeb
Merge branch 'fdo-rs:main' into Add-per-device-files-configuration-im…
RZandvoort Feb 9, 2024
15c43ba
Update main.rs
RZandvoort Feb 9, 2024
9ed790e
Update cd.yml
RZandvoort Feb 9, 2024
29a22a9
Update cd.yml
RZandvoort Feb 9, 2024
1603532
Update cd.yml
RZandvoort Feb 9, 2024
bdf098d
Update action.yml
RZandvoort Feb 9, 2024
c2111c0
Update cd.yml
RZandvoort Feb 9, 2024
2f3b530
Update cd.yml
RZandvoort Feb 9, 2024
4b3a934
Update action.yml
RZandvoort Feb 9, 2024
a83f974
Update main.rs
RZandvoort Feb 9, 2024
2e3b8c2
To working state?
Feb 12, 2024
fe983df
Add per device files
Feb 12, 2024
3d1631c
Add per-device file implementation
RZandvoort Feb 14, 2024
a256e42
Merge branch 'Add-per-device-files-configuration-implementation' of h…
RZandvoort Feb 14, 2024
e2f7f41
Removed commented code
RZandvoort Feb 14, 2024
f7fa830
Merge branch 'main' into Add-per-device-files-configuration-implement…
RZandvoort-VSM Feb 21, 2024
d158ff3
Update cd.yml
RZandvoort Mar 20, 2024
609d16f
Merge branch 'fdo-rs:main' into main
RZandvoort Mar 22, 2024
2d8d9f8
Merge branch 'main' into Add-per-device-files-configuration-implement…
RZandvoort Mar 24, 2024
38d450e
-
RZandvoort Mar 24, 2024
6dbdee6
Merge branch 'main' into Add-per-device-files-configuration-implement…
RZandvoort Mar 24, 2024
759599f
Merge branch 'fdo-rs:main' into main
RZandvoort Oct 1, 2024
a255824
Merge remote-tracking branch 'origin/main' into Add-per-device-files-…
RZandvoort-VSM Oct 2, 2024
aa1e5cc
Add per device commands
RZandvoort-VSM Oct 2, 2024
cd93f42
Update example config
RZandvoort-VSM Oct 2, 2024
4283016
Update HOWTO.md
RZandvoort-VSM Oct 2, 2024
1d13963
Clean-up
RZandvoort-VSM Oct 2, 2024
fb72b83
Merge branch 'main' into Add-per-device-files-configuration-implement…
RZandvoort Oct 2, 2024
70b77b8
Revert "Clean-up"
RZandvoort-VSM Oct 2, 2024
894188f
Merge branch 'main' into Add-per-device-files-configuration-implement…
RZandvoort Oct 3, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions HOWTO.md
Original file line number Diff line number Diff line change
Expand Up @@ -967,9 +967,18 @@ still required to be set by the user (`DI_SIGN_KEY_PATH`, `DI_HMAC_KEY_PATH`).
If other devices do not have their `per-device serviceinfo` file under `device_specific_store_driver` they will get onboarded
with settings from the main file, which is `serviceinfo-api-server.yml`.

Where:
- `initial_user`: the initial user from the per-device serviceinfo configuration will be chosen over the base serviceinfo configuration, if exists.
- `files`: add additional [files](#per-device-files) to be written next to the base files.
- `commands`: add additional commands to be executed after the base commands.
- `diskencryption_clevis`: unhandled
- `additional_serviceinfo`: unhandled
- `after_onboarding_reboot`: unhandled

1. Initialize the device as mentioned in [How to generate an Ownership Voucher and Credential for a Device](#how-to-generate-an-ownership-voucher-ov-and-credential-for-a-device-device-initialization).

2. Dump the `device-credentials`

```bash
fdo-owner-tool dump-device-credential /path/to/device-credentials
```
Expand All @@ -979,3 +988,7 @@ still required to be set by the user (`DI_SIGN_KEY_PATH`, `DI_HMAC_KEY_PATH`).
4. You can refer to [per_device_serviceinfo.yml](https://github.com/fedora-iot/fido-device-onboard-rs/blob/main/examples/config/device_specific_serviceinfo.yml) as an example.

5. Follow the onboarding procedure and this particular device will get the serviceinfo settings as mentioned in the above file.

#### Per device files

Files will be written to the `path` location. Both the files from the base and per-device serviceinfo configuration will be written. If the same `path` is defined multiple times in a configuration, the latest `path` definition will be written. If the same `path` is defined in the base as well in the per-device serviceinfo configuration, the per device serviceinfo configuration will have precedence over the base serviceinfo configuration.
21 changes: 19 additions & 2 deletions examples/config/device_specific_serviceinfo.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,25 @@ initial_user:
username: username_per_device
sshkeys:
- "testkeyperdevice"
files: null
commands: null
files:
- path: /var/lib/fdo/service-info-api/files/hosts
permissions: 644
source_path: /server/local/etc/hosts
commands:
- command: ls
args:
- /etc/hosts
return_stdout: true
return_stderr: true
- command: ls
args:
- /etc/doesnotexist/whatever.foo
may_fail: true
return_stdout: true
return_stderr: true
- command: touch
args:
- /etc/command-testfile
diskencryption_clevis: null
additional_serviceinfo: null
after_onboarding_reboot: false
155 changes: 106 additions & 49 deletions serviceinfo-api-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,64 +261,66 @@ async fn serviceinfo_handler(
.contains(&FedoraIotServiceInfoModule::BinaryFile.into())
{
if let Some(files) = &user_data.service_info_configuration.settings.files {
for file in files {
reply.add_extra(FedoraIotServiceInfoModule::BinaryFile, "name", &file.path);
reply.add_extra(
FedoraIotServiceInfoModule::BinaryFile,
"length",
&file.contents_len,
);
if let Some(parsed_permissions) = &file.parsed_permissions {
reply.add_extra(
FedoraIotServiceInfoModule::BinaryFile,
"mode",
&parsed_permissions,
);
}
reply.add_extra(
FedoraIotServiceInfoModule::BinaryFile,
"data001|hex",
&file.contents_hex,
);
reply.add_extra(
FedoraIotServiceInfoModule::BinaryFile,
"sha-384|hex",
&file.hash_hex,
);
}
add_binary_files_to_reply(files, &mut reply);

log::debug!("Added base configuration binary files");
}

// precedence is given to 'per_device' settings over base serviceinfo_api_server.yml config
match settings_per_device(&query_info.device_guid.to_string().replace('\"', "")) {
Ok(config) => {
let per_device_settings = config;
match ServiceInfoConfiguration::from_settings(per_device_settings){
Ok(per_device_service_info_configuration) => {
if let Some(files) = &per_device_service_info_configuration.settings.files {
add_binary_files_to_reply(files, &mut reply);

log::debug!("Added per-device configuration binary files");
}
}
Err(e) => {
log::error!("{}", e);
}
};
}
Err(_) => {
log::info!("No per-device configuration file found");
}
};
}

if query_info
.modules
.contains(&FedoraIotServiceInfoModule::Command.into())
{
// Add base configuration commands
if let Some(commands) = &user_data.service_info_configuration.settings.commands {
for command in commands {
reply.add_extra(
FedoraIotServiceInfoModule::Command,
"command",
&command.command,
);
reply.add_extra(FedoraIotServiceInfoModule::Command, "args", &command.args);
reply.add_extra(
FedoraIotServiceInfoModule::Command,
"may_fail",
&command.may_fail,
);
reply.add_extra(
FedoraIotServiceInfoModule::Command,
"return_stdout",
&command.return_stdout,
);
reply.add_extra(
FedoraIotServiceInfoModule::Command,
"return_stderr",
&command.return_stderr,
);
reply.add_extra(FedoraIotServiceInfoModule::Command, "execute", &true);
}
add_commands_to_reply(commands, &mut reply);

log::debug!("Added base configuration commands");
}

// Add device specific commands to reply
match settings_per_device(&query_info.device_guid.to_string().replace('\"', "")) {
Ok(config) => {
let per_device_settings = config;
match ServiceInfoConfiguration::from_settings(per_device_settings){
Ok(per_device_service_info_configuration) => {
if let Some(commands) = &per_device_service_info_configuration.settings.commands {
add_commands_to_reply(commands, &mut reply);

log::debug!("Added per-device configuration commands");
}
}
Err(e) => {
log::error!("{}", e);
}
};
}
Err(_) => {
log::info!("No per-device configuration file found");
}
};
}

if query_info
Expand Down Expand Up @@ -391,6 +393,61 @@ async fn serviceinfo_handler(
Ok(warp::reply::json(&reply.reply))
}

fn add_binary_files_to_reply(files: &Vec<fdo_util::servers::configuration::serviceinfo_api_server::ServiceInfoFile>, reply: &mut ServiceInfoApiReplyBuilder) {
for file in files {
reply.add_extra(FedoraIotServiceInfoModule::BinaryFile, "name", &file.path);
reply.add_extra(
FedoraIotServiceInfoModule::BinaryFile,
"length",
&file.contents_len,
);
if let Some(parsed_permissions) = &file.parsed_permissions {
reply.add_extra(
FedoraIotServiceInfoModule::BinaryFile,
"mode",
&parsed_permissions,
);
}
reply.add_extra(
FedoraIotServiceInfoModule::BinaryFile,
"data001|hex",
&file.contents_hex,
);
reply.add_extra(
FedoraIotServiceInfoModule::BinaryFile,
"sha-384|hex",
&file.hash_hex,
);
}
}

fn add_commands_to_reply(commands: &Vec<fdo_util::servers::configuration::serviceinfo_api_server::ServiceInfoCommand>, reply: &mut ServiceInfoApiReplyBuilder) {
for command in commands {
reply.add_extra(
FedoraIotServiceInfoModule::Command,
"command",
&command.command,
);
reply.add_extra(FedoraIotServiceInfoModule::Command, "args", &command.args);
reply.add_extra(
FedoraIotServiceInfoModule::Command,
"may_fail",
&command.may_fail,
);
reply.add_extra(
FedoraIotServiceInfoModule::Command,
"return_stdout",
&command.return_stdout,
);
reply.add_extra(
FedoraIotServiceInfoModule::Command,
"return_stderr",
&command.return_stderr,
);
reply.add_extra(FedoraIotServiceInfoModule::Command, "execute", &true);
}
}

fn deserialize_from_str<'de, D>(deserializer: D) -> Result<fdo_data_formats::types::Guid, D::Error>
where
D: serde::de::Deserializer<'de>,
Expand Down
6 changes: 4 additions & 2 deletions util/src/servers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ pub fn settings_per_device(guid: &str) -> Result<ServiceInfoSettings> {
log::debug!("Loaded device specific config from {path_per_device_store}");
let per_device_settings = config.try_deserialize::<ServiceInfoSettings>()?;
log::debug!(
"device specific serviceinfosettings: initial_user: {:#?} username: {:#?} sshkeys {:#?}",
"device specific serviceinfosettings: initial_user: {:#?} username: {:#?} sshkeys {:#?} files {:#?} commands {:#?}",
per_device_settings.initial_user,
per_device_settings
.initial_user
Expand All @@ -99,7 +99,9 @@ pub fn settings_per_device(guid: &str) -> Result<ServiceInfoSettings> {
per_device_settings
.initial_user
.as_ref()
.map(|user| &user.sshkeys)
.map(|user| &user.sshkeys),
per_device_settings.files,
per_device_settings.commands
);
Ok(per_device_settings)
}
Expand Down
Loading