Skip to content

Commit 040be24

Browse files
committed
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>
1 parent 999007f commit 040be24

File tree

2 files changed

+38
-16
lines changed

2 files changed

+38
-16
lines changed

crates/lib/src/podstorage.rs

Lines changed: 33 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -9,22 +9,22 @@
99
//! At the current time, this is only used for Logically Bound Images.
1010
1111
use std::collections::HashSet;
12-
use std::io::Seek;
12+
use std::io::{Seek, Write};
1313
use std::os::unix::process::CommandExt;
1414
use std::process::{Command, Stdio};
1515
use std::sync::Arc;
1616

1717
use anyhow::{Context, Result};
1818
use bootc_utils::{AsyncCommandRunExt, CommandRunExt, ExitStatusExt};
1919
use camino::{Utf8Path, Utf8PathBuf};
20-
use cap_std_ext::cap_std;
2120
use cap_std_ext::cap_std::fs::Dir;
2221
use cap_std_ext::cap_tempfile::TempDir;
2322
use cap_std_ext::cmdext::CapStdExtCommandExt;
2423
use cap_std_ext::dirext::CapStdExtDirExt;
24+
use cap_std_ext::{cap_std, cap_tempfile};
2525
use fn_error_context::context;
2626
use ostree_ext::ostree::{self};
27-
use std::os::fd::{AsRawFd, OwnedFd};
27+
use std::os::fd::{AsFd, AsRawFd, OwnedFd};
2828
use tokio::process::Command as AsyncCommand;
2929

3030
// 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) ->
119119
Ok(())
120120
}
121121

122-
fn new_podman_cmd_in(storage_root: &Dir, run_root: &Dir) -> Result<Command> {
122+
// Initialize a `podman` subprocess with:
123+
// - storage overridden to point to to storage_root
124+
// - Authentication (auth.json) using the bootc/ostree owned auth
125+
fn new_podman_cmd_in(sysroot: &Dir, storage_root: &Dir, run_root: &Dir) -> Result<Command> {
123126
let mut cmd = Command::new("podman");
124127
bind_storage_roots(&mut cmd, storage_root, run_root)?;
125128
let run_root = format!("/proc/self/fd/{STORAGE_RUN_FD}");
126129
cmd.args(["--root", STORAGE_ALIAS_DIR, "--runroot", run_root.as_str()]);
130+
131+
let tmpd = &cap_std::fs::Dir::open_ambient_dir("/tmp", cap_std::ambient_authority())?;
132+
let mut tempfile = cap_tempfile::TempFile::new_anonymous(tmpd).map(std::io::BufWriter::new)?;
133+
134+
// Keep this in sync with https://github.com/bootc-dev/containers-image-proxy-rs/blob/b5e0861ad5065f47eaf9cda0d48da3529cc1bc43/src/imageproxy.rs#L310
135+
// We always override the auth to match the bootc setup.
136+
let authfile_fd = ostree_ext::globals::get_global_authfile(sysroot)?.map(|v| v.1);
137+
if let Some(mut fd) = authfile_fd {
138+
std::io::copy(&mut fd, &mut tempfile)?;
139+
} else {
140+
// Note that if there's no bootc-owned auth, then we force an empty authfile to ensure
141+
// that podman doesn't fall back to searching the user-owned paths.
142+
tempfile.write_all(b"{}")?;
143+
}
144+
145+
let tempfile = tempfile
146+
.into_inner()
147+
.map_err(|e| e.into_error())?
148+
.into_std();
149+
let fd: Arc<OwnedFd> = std::sync::Arc::new(tempfile.into());
150+
let target_fd = fd.as_fd().as_raw_fd();
151+
cmd.take_fd_n(fd, target_fd);
152+
cmd.env("REGISTRY_AUTH_FILE", format!("/proc/self/fd/{target_fd}"));
153+
127154
Ok(cmd)
128155
}
129156

@@ -167,7 +194,7 @@ impl CStorage {
167194
/// Create a `podman image` Command instance prepared to operate on our alternative
168195
/// root.
169196
pub(crate) fn new_image_cmd(&self) -> Result<Command> {
170-
let mut r = new_podman_cmd_in(&self.storage_root, &self.run)?;
197+
let mut r = new_podman_cmd_in(&self.sysroot, &self.storage_root, &self.run)?;
171198
// We want to limit things to only manipulating images by default.
172199
r.arg("image");
173200
Ok(r)
@@ -233,7 +260,7 @@ impl CStorage {
233260
// There's no explicit API to initialize a containers-storage:
234261
// root, simply passing a path will attempt to auto-create it.
235262
// We run "podman images" in the new root.
236-
new_podman_cmd_in(&storage_root, &run)?
263+
new_podman_cmd_in(&sysroot, &storage_root, &run)?
237264
.stdout(Stdio::null())
238265
.arg("images")
239266
.run_capture_stderr()
@@ -353,16 +380,6 @@ impl CStorage {
353380
cmd.stdin(Stdio::null());
354381
cmd.stdout(Stdio::null());
355382
cmd.args(["pull", image]);
356-
let authfile_fd =
357-
ostree_ext::globals::get_global_authfile(&self.sysroot)?.map(|(_authfile, fd)| fd);
358-
if let Some(fd) = authfile_fd {
359-
let authfile_path = std::fs::read_link(format!("/proc/self/fd/{}", fd.as_raw_fd()))
360-
.map_err(Into::into)
361-
.and_then(|p| {
362-
Utf8PathBuf::from_path_buf(p).map_err(|_| anyhow::anyhow!("Invalid UTF-8"))
363-
})?;
364-
cmd.args(["--authfile", authfile_path.as_str()]);
365-
}
366383
tracing::debug!("Pulling image: {image}");
367384
let mut cmd = AsyncCommand::from(cmd);
368385
cmd.run().await.context("Failed to pull image")?;

tmt/tests/booted/test-logically-bound-switch.nu

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ bootc status
2121
let st = bootc status --json | from json
2222
let booted = $st.status.booted.image
2323

24+
# The tests here aren't fetching from a registry which requires auth by default,
25+
# but we can replicate the failure in https://github.com/bootc-dev/bootc/pull/1852
26+
# by just injecting any auth file.
27+
echo '{}' | save -f /run/ostree/auth.json
28+
2429
def initial_setup [] {
2530
bootc image copy-to-storage
2631
podman images

0 commit comments

Comments
 (0)