mirror of
https://github.com/containers/bootc.git
synced 2026-02-05 06:45:13 +01:00
podstorage: Improve authfile handling more
We should match exactly the logic we use with containers-image-proxy. - If bootc doesn't have auth setup, then we need to not let podman fall back to the defaults - Always pass a copy of the auth in a tempfile so we aren't reliant on absolute paths as we're continually trying to reduce our usage of those. Signed-off-by: Colin Walters <walters@verbum.org>
This commit is contained in:
@@ -9,7 +9,7 @@
|
||||
//! At the current time, this is only used for Logically Bound Images.
|
||||
|
||||
use std::collections::HashSet;
|
||||
use std::io::Seek;
|
||||
use std::io::{Seek, Write};
|
||||
use std::os::unix::process::CommandExt;
|
||||
use std::process::{Command, Stdio};
|
||||
use std::sync::Arc;
|
||||
@@ -17,14 +17,14 @@ use std::sync::Arc;
|
||||
use anyhow::{Context, Result};
|
||||
use bootc_utils::{AsyncCommandRunExt, CommandRunExt, ExitStatusExt};
|
||||
use camino::{Utf8Path, Utf8PathBuf};
|
||||
use cap_std_ext::cap_std;
|
||||
use cap_std_ext::cap_std::fs::Dir;
|
||||
use cap_std_ext::cap_tempfile::TempDir;
|
||||
use cap_std_ext::cmdext::CapStdExtCommandExt;
|
||||
use cap_std_ext::dirext::CapStdExtDirExt;
|
||||
use cap_std_ext::{cap_std, cap_tempfile};
|
||||
use fn_error_context::context;
|
||||
use ostree_ext::ostree::{self};
|
||||
use std::os::fd::{AsRawFd, OwnedFd};
|
||||
use std::os::fd::{AsFd, AsRawFd, OwnedFd};
|
||||
use tokio::process::Command as AsyncCommand;
|
||||
|
||||
// Pass only 100 args at a time just to avoid potentially overflowing argument
|
||||
@@ -119,11 +119,38 @@ fn bind_storage_roots(cmd: &mut Command, storage_root: &Dir, run_root: &Dir) ->
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn new_podman_cmd_in(storage_root: &Dir, run_root: &Dir) -> Result<Command> {
|
||||
// Initialize a `podman` subprocess with:
|
||||
// - storage overridden to point to to storage_root
|
||||
// - Authentication (auth.json) using the bootc/ostree owned auth
|
||||
fn new_podman_cmd_in(sysroot: &Dir, storage_root: &Dir, run_root: &Dir) -> Result<Command> {
|
||||
let mut cmd = Command::new("podman");
|
||||
bind_storage_roots(&mut cmd, storage_root, run_root)?;
|
||||
let run_root = format!("/proc/self/fd/{STORAGE_RUN_FD}");
|
||||
cmd.args(["--root", STORAGE_ALIAS_DIR, "--runroot", run_root.as_str()]);
|
||||
|
||||
let tmpd = &cap_std::fs::Dir::open_ambient_dir("/tmp", cap_std::ambient_authority())?;
|
||||
let mut tempfile = cap_tempfile::TempFile::new_anonymous(tmpd).map(std::io::BufWriter::new)?;
|
||||
|
||||
// Keep this in sync with https://github.com/bootc-dev/containers-image-proxy-rs/blob/b5e0861ad5065f47eaf9cda0d48da3529cc1bc43/src/imageproxy.rs#L310
|
||||
// We always override the auth to match the bootc setup.
|
||||
let authfile_fd = ostree_ext::globals::get_global_authfile(sysroot)?.map(|v| v.1);
|
||||
if let Some(mut fd) = authfile_fd {
|
||||
std::io::copy(&mut fd, &mut tempfile)?;
|
||||
} else {
|
||||
// Note that if there's no bootc-owned auth, then we force an empty authfile to ensure
|
||||
// that podman doesn't fall back to searching the user-owned paths.
|
||||
tempfile.write_all(b"{}")?;
|
||||
}
|
||||
|
||||
let tempfile = tempfile
|
||||
.into_inner()
|
||||
.map_err(|e| e.into_error())?
|
||||
.into_std();
|
||||
let fd: Arc<OwnedFd> = std::sync::Arc::new(tempfile.into());
|
||||
let target_fd = fd.as_fd().as_raw_fd();
|
||||
cmd.take_fd_n(fd, target_fd);
|
||||
cmd.env("REGISTRY_AUTH_FILE", format!("/proc/self/fd/{target_fd}"));
|
||||
|
||||
Ok(cmd)
|
||||
}
|
||||
|
||||
@@ -167,7 +194,7 @@ impl CStorage {
|
||||
/// Create a `podman image` Command instance prepared to operate on our alternative
|
||||
/// root.
|
||||
pub(crate) fn new_image_cmd(&self) -> Result<Command> {
|
||||
let mut r = new_podman_cmd_in(&self.storage_root, &self.run)?;
|
||||
let mut r = new_podman_cmd_in(&self.sysroot, &self.storage_root, &self.run)?;
|
||||
// We want to limit things to only manipulating images by default.
|
||||
r.arg("image");
|
||||
Ok(r)
|
||||
@@ -233,7 +260,7 @@ impl CStorage {
|
||||
// There's no explicit API to initialize a containers-storage:
|
||||
// root, simply passing a path will attempt to auto-create it.
|
||||
// We run "podman images" in the new root.
|
||||
new_podman_cmd_in(&storage_root, &run)?
|
||||
new_podman_cmd_in(&sysroot, &storage_root, &run)?
|
||||
.stdout(Stdio::null())
|
||||
.arg("images")
|
||||
.run_capture_stderr()
|
||||
@@ -353,16 +380,6 @@ impl CStorage {
|
||||
cmd.stdin(Stdio::null());
|
||||
cmd.stdout(Stdio::null());
|
||||
cmd.args(["pull", image]);
|
||||
let authfile_fd =
|
||||
ostree_ext::globals::get_global_authfile(&self.sysroot)?.map(|(_authfile, fd)| fd);
|
||||
if let Some(fd) = authfile_fd {
|
||||
let authfile_path = std::fs::read_link(format!("/proc/self/fd/{}", fd.as_raw_fd()))
|
||||
.map_err(Into::into)
|
||||
.and_then(|p| {
|
||||
Utf8PathBuf::from_path_buf(p).map_err(|_| anyhow::anyhow!("Invalid UTF-8"))
|
||||
})?;
|
||||
cmd.args(["--authfile", authfile_path.as_str()]);
|
||||
}
|
||||
tracing::debug!("Pulling image: {image}");
|
||||
let mut cmd = AsyncCommand::from(cmd);
|
||||
cmd.run().await.context("Failed to pull image")?;
|
||||
|
||||
@@ -15,6 +15,14 @@ if $is_composefs {
|
||||
|
||||
# And verify this works
|
||||
bootc image cmd list -q o>/dev/null
|
||||
|
||||
bootc image cmd pull busybox
|
||||
podman --storage-opt=additionalimagestore=/usr/lib/bootc/storage image exists busybox
|
||||
|
||||
'corrupted JSON!@#%!@#' | save -f /run/ostree/auth.json
|
||||
let e = bootc image cmd pull busybox | complete | get exit_code
|
||||
assert not equal $e 0
|
||||
rm -v /run/ostree/auth.json
|
||||
}
|
||||
|
||||
tap ok
|
||||
|
||||
@@ -21,6 +21,11 @@ bootc status
|
||||
let st = bootc status --json | from json
|
||||
let booted = $st.status.booted.image
|
||||
|
||||
# The tests here aren't fetching from a registry which requires auth by default,
|
||||
# but we can replicate the failure in https://github.com/bootc-dev/bootc/pull/1852
|
||||
# by just injecting any auth file.
|
||||
echo '{}' | save -f /run/ostree/auth.json
|
||||
|
||||
def initial_setup [] {
|
||||
bootc image copy-to-storage
|
||||
podman images
|
||||
|
||||
Reference in New Issue
Block a user