Skip to content

Commit

Permalink
Merge pull request #1068 from cgwalters/install-config-verity-prep
Browse files Browse the repository at this point in the history
Install config verity prep
  • Loading branch information
cgwalters authored Feb 3, 2025
2 parents c54fefa + cca41fb commit 63f49d3
Show file tree
Hide file tree
Showing 14 changed files with 219 additions and 61 deletions.
5 changes: 3 additions & 2 deletions .packit.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,9 @@ jobs:
# rawhide is basically nil.
- fedora-rawhide-x86_64
- fedora-rawhide-aarch64
- rhel-9-x86_64
- rhel-9-aarch64
# Temporarily disabled due to too old Rust...reenable post 9.6
# - rhel-9-x86_64
# - rhel-9-aarch64

- job: tests
trigger: pull_request
Expand Down
64 changes: 62 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ license = "MIT OR Apache-2.0"
repository = "https://github.com/containers/bootc"
readme = "README.md"
publish = false
# For now don't bump this above what is currently shipped in RHEL9.
rust-version = "1.75.0"
default-run = "bootc"

# See https://github.com/coreos/cargo-vendor-filterer
Expand Down
8 changes: 7 additions & 1 deletion contrib/packaging/bootc.spec
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,11 @@ Provides: ostree-cli(ostree-container)

%prep
%autosetup -p1 -a1
%cargo_prep -v vendor
# Default -v vendor config doesn't support non-crates.io deps (i.e. git)
cp .cargo/vendor-config.toml .
%cargo_prep -N
cat vendor-config.toml >> .cargo/config.toml
rm vendor-config.toml

%build
%if 0%{?fedora} || 0%{?rhel} >= 10
Expand All @@ -74,6 +78,8 @@ Provides: ostree-cli(ostree-container)
%endif

%cargo_vendor_manifest
# https://pagure.io/fedora-rust/rust-packaging/issue/33
sed -i -e '/https:\/\//d' cargo-vendor.txt
%cargo_license_summary
%{cargo_license} > LICENSE.dependencies

Expand Down
2 changes: 1 addition & 1 deletion deny.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,4 +12,4 @@ name = "ring"
[sources]
unknown-registry = "deny"
unknown-git = "deny"
allow-git = []
allow-git = ["https://github.com/containers/composefs-rs"]
2 changes: 1 addition & 1 deletion hack/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ set -xeu
. /usr/lib/os-release
case $ID in
centos|rhel) dnf config-manager --set-enabled crb;;
fedora) dnf -y install dnf-utils ;;
fedora) dnf -y install dnf-utils 'dnf5-command(builddep)';;
esac
dnf -y builddep ./contrib/packaging/bootc.spec
# Extra dependencies
Expand Down
8 changes: 5 additions & 3 deletions lib/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ name = "bootc-lib"
readme = "README.md"
repository = "https://github.com/containers/bootc"
version = "1.1.4"
# For now don't bump this above what is currently shipped in RHEL9;
# also keep in sync with the version in cli.
rust-version = "1.75.0"
# In general we try to keep this pinned to what's in the latest RHEL9.
# However right now, we bumped to 1.82 as that's what composefs-rs uses.
rust-version = "1.82.0"

include = ["/src", "LICENSE-APACHE", "LICENSE-MIT"]

Expand All @@ -23,6 +23,8 @@ ostree-ext = { path = "../ostree-ext", features = ["bootc"] }
chrono = { workspace = true, features = ["serde"] }
clap = { workspace = true, features = ["derive","cargo"] }
clap_mangen = { workspace = true, optional = true }
#composefs = "0.2.0"
composefs = { git = "https://github.com/containers/composefs-rs", rev = "55ae2e9ba72f6afda4887d746e6b98f0a1875ac4" }
cap-std-ext = { workspace = true, features = ["fs_utf8"] }
hex = { workspace = true }
fn-error-context = { workspace = true }
Expand Down
36 changes: 36 additions & 0 deletions lib/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ use cap_std_ext::cap_std;
use cap_std_ext::cap_std::fs::Dir;
use clap::Parser;
use clap::ValueEnum;
use composefs::fsverity;
use fn_error_context::context;
use ostree::gio;
use ostree_container::store::PrepareResult;
Expand Down Expand Up @@ -376,6 +377,21 @@ pub(crate) enum SchemaType {
Progress,
}

/// Options for consistency checking
#[derive(Debug, clap::Subcommand, PartialEq, Eq)]
pub(crate) enum FsverityOpts {
/// Measure the fsverity digest of the target file.
Measure {
/// Path to file
path: Utf8PathBuf,
},
/// Enable fsverity on the target file.
Enable {
/// Ptah to file
path: Utf8PathBuf,
},
}

/// Hidden, internal only options
#[derive(Debug, clap::Subcommand, PartialEq, Eq)]
pub(crate) enum InternalsOpts {
Expand All @@ -392,6 +408,8 @@ pub(crate) enum InternalsOpts {
#[clap(long)]
of: SchemaType,
},
#[clap(subcommand)]
Fsverity(FsverityOpts),
/// Perform cleanup actions
Cleanup,
/// Proxy frontend for the `ostree-ext` CLI.
Expand Down Expand Up @@ -1113,6 +1131,24 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
)
.await
}
// We don't depend on fsverity-utils today, so re-expose some helpful CLI tools.
InternalsOpts::Fsverity(args) => match args {
FsverityOpts::Measure { path } => {
let fd =
std::fs::File::open(&path).with_context(|| format!("Reading {path}"))?;
let digest =
fsverity::measure_verity_digest::<_, fsverity::Sha256HashValue>(&fd)?;
let digest = hex::encode(digest);
println!("{digest}");
Ok(())
}
FsverityOpts::Enable { path } => {
let fd =
std::fs::File::open(&path).with_context(|| format!("Reading {path}"))?;
fsverity::ioctl::fs_ioc_enable_verity::<_, fsverity::Sha256HashValue>(&fd)?;
Ok(())
}
},
InternalsOpts::FixupEtcFstab => crate::deploy::fixup_etc_fstab(&root),
InternalsOpts::PrintJsonSchema { of } => {
let schema = match of {
Expand Down
20 changes: 19 additions & 1 deletion lib/src/install.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ pub(crate) mod config;
mod osbuild;
pub(crate) mod osconfig;

use std::collections::HashMap;
use std::io::Write;
use std::os::fd::{AsFd, AsRawFd};
use std::os::unix::process::CommandExt;
Expand All @@ -37,11 +38,11 @@ use chrono::prelude::*;
use clap::ValueEnum;
use fn_error_context::context;
use ostree::gio;
use ostree_ext::container as ostree_container;
use ostree_ext::oci_spec;
use ostree_ext::ostree;
use ostree_ext::prelude::Cast;
use ostree_ext::sysroot::SysrootLock;
use ostree_ext::{container as ostree_container, ostree_prepareroot};
#[cfg(feature = "install-to-disk")]
use rustix::fs::FileTypeExt;
use rustix::fs::MetadataExt as _;
Expand Down Expand Up @@ -349,6 +350,8 @@ pub(crate) struct State {
#[allow(dead_code)]
pub(crate) config_opts: InstallConfigOpts,
pub(crate) target_imgref: ostree_container::OstreeImageReference,
#[allow(dead_code)]
pub(crate) prepareroot_config: HashMap<String, String>,
pub(crate) install_config: Option<config::InstallConfiguration>,
/// The parsed contents of the authorized_keys (not the file path)
pub(crate) root_ssh_authorized_keys: Option<String>,
Expand Down Expand Up @@ -1267,6 +1270,20 @@ async fn prepare_install(
tracing::debug!("No install configuration found");
}

// Convert the keyfile to a hashmap because GKeyFile isnt Send for probably bad reasons.
let prepareroot_config = {
let kf = ostree_prepareroot::require_config_from_root(&rootfs)?;
let mut r = HashMap::new();
for grp in kf.groups() {
for key in kf.keys(&grp)? {
let key = key.as_str();
let value = kf.value(&grp, key)?;
r.insert(format!("{grp}.{key}"), value.to_string());
}
}
r
};

// Eagerly read the file now to ensure we error out early if e.g. it doesn't exist,
// instead of much later after we're 80% of the way through an install.
let root_ssh_authorized_keys = config_opts
Expand All @@ -1284,6 +1301,7 @@ async fn prepare_install(
config_opts,
target_imgref,
install_config,
prepareroot_config,
root_ssh_authorized_keys,
container_root: rootfs,
tempdir,
Expand Down
14 changes: 4 additions & 10 deletions lib/src/lints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,15 @@ use std::collections::BTreeSet;
use std::env::consts::ARCH;
use std::os::unix::ffi::OsStrExt;

use anyhow::{Context, Result};
use anyhow::Result;
use camino::{Utf8Path, Utf8PathBuf};
use cap_std::fs::Dir;
use cap_std_ext::cap_std;
use cap_std_ext::cap_std::fs::MetadataExt;
use cap_std_ext::dirext::CapStdExtDirExt as _;
use fn_error_context::context;
use indoc::indoc;
use ostree_ext::ostree_prepareroot;
use serde::Serialize;

/// Reference to embedded default baseimage content that should exist.
Expand Down Expand Up @@ -286,15 +287,8 @@ fn check_baseimage_root_norecurse(dir: &Dir) -> LintResult {
return lint_err("Expected /ostree -> {expected}, not {link:?}");
}

// Check the prepare-root config
let prepareroot_path = "usr/lib/ostree/prepare-root.conf";
let config_data = dir
.read_to_string(prepareroot_path)
.context(prepareroot_path)?;
let config = ostree_ext::glib::KeyFile::new();
config.load_from_data(&config_data, ostree_ext::glib::KeyFileFlags::empty())?;

if !ostree_ext::ostree_prepareroot::overlayfs_enabled_in_config(&config)? {
let config = ostree_prepareroot::require_config_from_root(dir)?;
if !ostree_prepareroot::overlayfs_enabled_in_config(&config)? {
return lint_err("{prepareroot_path} does not have composefs enabled");
}

Expand Down
1 change: 0 additions & 1 deletion ostree-ext/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ name = "ostree-ext"
readme = "../README.md"
repository = "https://github.com/ostreedev/ostree-rs-ext"
version = "0.15.3"
rust-version = "1.74.0"

[dependencies]
# Note that we re-export the oci-spec types
Expand Down
Loading

0 comments on commit 63f49d3

Please sign in to comment.