diff options
| author | Tim Orling <tim.orling@konsulko.com> | 2026-04-16 13:30:36 -0700 |
|---|---|---|
| committer | Bruce Ashfield <bruce.ashfield@gmail.com> | 2026-04-29 20:15:49 +0000 |
| commit | 4ba5825ee16fcded87f4d555b4ed7a7615dc67ac (patch) | |
| tree | bee754b16d2c50d9b819ca237b9a7aa8b7bc4513 /recipes-containers/vcontainer/README.md | |
| parent | 002f915a432467dca4a9c61f75947f10f96e63e2 (diff) | |
| download | meta-virtualization-4ba5825ee16fcded87f4d555b4ed7a7615dc67ac.tar.gz | |
vcontainer: add --config / VDKR_CONFIG for docker/podman auth credentials
Add a VDKR_CONFIG / VPDMN_CONFIG env var and a matching --config <path>
CLI flag that passes an existing docker config.json / podman auth.json
into the QEMU-hosted container runtime so pulls from private registries
work without having to retype --registry-user / --registry-pass on every
command.
Security posture (defence in depth):
- Host-side pre-flight validation in vrunner.sh (validate_auth_config):
reject symlinks, non-regular files, missing / unreadable files, files
smaller than 2 bytes (minimum "{}") or larger than 1 MiB, and any
permissions other than 0400 / 0600 / 0200. WARN if not owned by the
invoking user.
- Stage the file into a dedicated per-invocation directory under
$TEMP_DIR at mode 0400 inside a 0700 parent; auto-cleanup rides the
existing EXIT/INT/TERM trap.
- Expose the staged file over a *separate* read-only virtio-9p tag
("${TOOL_NAME}_auth") so credentials cannot leak into the general
/mnt/share input/output directory or into storage.tar outputs.
- Only a boolean flag ("${CMDLINE_PREFIX}_auth=1") is appended to the
kernel cmdline - never the path, the env var name, or the contents.
- Guest mounts /mnt/auth ro,nosuid,nodev,noexec, copies to the runtime's
canonical path, then unmounts immediately so neither the runtime nor
user workloads keep a reference to the host staging directory.
vrunner.sh:
- Initialise AUTH_CONFIG from $VDKR_CONFIG / $VPDMN_CONFIG
- Parse --config <path> (overrides the env vars)
- Add validate_auth_config() and setup_auth_share() with the rules above
- Call setup_auth_share in both the daemon start path and the
non-daemon / batch-import path
vcontainer-init-common.sh:
- Default RUNTIME_AUTH="0" and parse ${VCONTAINER_RUNTIME_PREFIX}_auth=*
from the kernel cmdline
- Define mount_auth_share() / unmount_auth_share() using the per-runtime
"${VCONTAINER_RUNTIME_NAME}_auth" 9p tag, mounted at /mnt/auth with
ro,nosuid,nodev,noexec
vdkr-init.sh:
- install_auth_config() copies /mnt/auth/config.json to
/root/.docker/config.json (mode 0600; parent dir 0700)
- Called after install_registry_ca in main flow so --config takes
precedence over --registry-user / --registry-pass; logs a NOTE when
both mechanisms are supplied
- Unmounts /mnt/auth after copy
vpdmn-init.sh:
- install_auth_config() copies to /run/containers/0/auth.json (the
rootful podman canonical path) and exports REGISTRY_AUTH_FILE so the
creds are picked up regardless of podman's search order
- Mode 0600 on the file, 0700 on the containing directory
- Unmounts /mnt/auth after copy
vcontainer-common.sh:
- Honour $VDKR_CONFIG / $VPDMN_CONFIG, parse --config, and forward
AUTH_CONFIG to vrunner.sh via --config in build_runner_args
- Document the flag and env vars in show_usage
README.md:
- New "Passing an existing docker/podman auth file (--config)" section
with examples for both runtimes, a table of target paths, and the
full security model
AI-Generated: Claude Cowork Opus 4.7
Signed-off-by: Tim Orling <tim.orling@konsulko.com>
Signed-off-by: Bruce Ashfield <bruce.ashfield@gmail.com>
Diffstat (limited to 'recipes-containers/vcontainer/README.md')
| -rw-r--r-- | recipes-containers/vcontainer/README.md | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/recipes-containers/vcontainer/README.md b/recipes-containers/vcontainer/README.md index 657dd02e..e44616f4 100644 --- a/recipes-containers/vcontainer/README.md +++ b/recipes-containers/vcontainer/README.md | |||
| @@ -317,6 +317,60 @@ use `--secure-registry --ca-cert`: | |||
| 317 | vdkr --secure-registry --ca-cert /path/to/ca.crt pull myimage | 317 | vdkr --secure-registry --ca-cert /path/to/ca.crt pull myimage |
| 318 | ``` | 318 | ``` |
| 319 | 319 | ||
| 320 | ### Passing an existing docker/podman auth file (`--config`) | ||
| 321 | |||
| 322 | If you already have credentials set up on the host (for example, from | ||
| 323 | running `docker login` locally), you can pass the resulting auth file | ||
| 324 | straight through into the emulated environment instead of re-entering | ||
| 325 | credentials with `--registry-user`/`--registry-pass`: | ||
| 326 | |||
| 327 | ```bash | ||
| 328 | # Docker (vdkr): uses ~/.docker/config.json by default | ||
| 329 | vdkr --config ~/.docker/config.json pull registry.example.com/myimage | ||
| 330 | |||
| 331 | # Podman (vpdmn): uses $XDG_RUNTIME_DIR/containers/auth.json | ||
| 332 | vpdmn --config $XDG_RUNTIME_DIR/containers/auth.json pull registry.example.com/myimage | ||
| 333 | ``` | ||
| 334 | |||
| 335 | The path can also be supplied via environment: | ||
| 336 | |||
| 337 | ```bash | ||
| 338 | export VDKR_CONFIG=$HOME/.docker/config.json | ||
| 339 | vdkr pull registry.example.com/myimage | ||
| 340 | ``` | ||
| 341 | |||
| 342 | (`VPDMN_CONFIG` is honoured identically by `vpdmn`.) | ||
| 343 | |||
| 344 | **What the file ends up as inside the VM:** | ||
| 345 | |||
| 346 | | Tool | Target path | Notes | | ||
| 347 | | ----- | --------------------------------- | ------------------------------------------------- | | ||
| 348 | | vdkr | `/root/.docker/config.json` | Mode 0600; containing dir 0700 | | ||
| 349 | | vpdmn | `/run/containers/0/auth.json` | Mode 0600; `$REGISTRY_AUTH_FILE` exported | | ||
| 350 | |||
| 351 | **Security model.** The credential file is treated as secret material: | ||
| 352 | |||
| 353 | - The host-side file **must** be a regular file with mode `0600` or `0400`. | ||
| 354 | World/group-readable files are rejected outright. Symlinks are rejected. | ||
| 355 | Files larger than 1 MiB are rejected. | ||
| 356 | - On the host it is copied into a per-invocation private directory under | ||
| 357 | `$TMPDIR/vdkr-$$/auth_share` (mode 0700; file mode 0400) and removed | ||
| 358 | automatically by the `EXIT`/`INT`/`TERM` trap when `vrunner.sh` exits. | ||
| 359 | - It is exposed to the guest on a **dedicated** virtio-9p share whose | ||
| 360 | mount tag (`vdkr_auth` / `vpdmn_auth`) is distinct from the general | ||
| 361 | `*_share` share used for input/output. The guest mounts it **read-only** | ||
| 362 | at `/mnt/auth`, copies it into the runtime's credential location, then | ||
| 363 | **unmounts** `/mnt/auth` so nothing in the VM retains an open reference | ||
| 364 | to the host staging directory. | ||
| 365 | - Nothing about the file appears on the kernel command line. Only a | ||
| 366 | boolean flag (`docker_auth=1` / `podman_auth=1`) is passed so the guest | ||
| 367 | init script knows to look on the auth share. | ||
| 368 | - When both `--config` and `--registry-user`/`--registry-pass` are | ||
| 369 | supplied, `--config` wins and a NOTE is logged. | ||
| 370 | - `--config` is NOT forwarded into container workloads (it only reaches | ||
| 371 | the container engine's credential store); containers themselves never | ||
| 372 | see `/mnt/auth`. | ||
| 373 | |||
| 320 | ## Volume Mounts | 374 | ## Volume Mounts |
| 321 | 375 | ||
| 322 | Mount host directories into containers using `-v` (requires memory resident mode): | 376 | Mount host directories into containers using `-v` (requires memory resident mode): |
