#!/usr/bin/env bash set -euo pipefail usage() { cat >&2 <<'EOF' Usage: hostexec [--root] [--] Run a command on the Docker host by starting a temporary privileged helper container through the mounted Docker socket and entering the host namespaces. Commands run as the current container UID/GID by default. Use --root to keep root privileges for administrative host commands. EOF } run_as_root=false while [ "$#" -gt 0 ]; do case "$1" in --root) run_as_root=true shift ;; --help|-h) usage exit 0 ;; --) shift break ;; *) break ;; esac done if [ "$#" -eq 0 ]; then usage exit 64 fi if ! command -v docker >/dev/null 2>&1; then echo "hostexec: docker CLI not found in this container" >&2 exit 127 fi docker_host="${DOCKER_HOST:-unix:///var/run/docker.sock}" if [[ "$docker_host" == unix://* ]]; then socket_path="${docker_host#unix://}" if [ ! -S "$socket_path" ]; then echo "hostexec: Docker socket is not accessible as a Unix socket at $socket_path" >&2 exit 69 fi fi helper_image="${HOSTEXEC_IMAGE:-alpine:3.22}" target_uid="$(id -u)" target_gid="$(id -g)" tty_args=(--interactive) if [ -t 0 ] && [ -t 1 ]; then tty_args+=(--tty) fi docker_args=( --rm "${tty_args[@]}" --pull=missing --privileged --security-opt label=disable --pid=host --network=host --volume /:/host:rw ) if [ "$run_as_root" = true ] || { [ "$target_uid" = 0 ] && [ "$target_gid" = 0 ]; }; then exec docker run \ "${docker_args[@]}" \ "$helper_image" \ nsenter -t 1 -m -u -i -n -p -- "$@" fi run_as_container_user='target_uid="${HOSTEXEC_TARGET_UID:?}" target_gid="${HOSTEXEC_TARGET_GID:?}" target_user="" if command -v getent >/dev/null 2>&1; then passwd_entry="$(getent passwd "$target_uid" || true)" if [ -n "$passwd_entry" ]; then target_user="${passwd_entry%%:*}" fi fi if [ -n "$target_user" ]; then if command -v runuser >/dev/null 2>&1; then exec runuser -u "$target_user" -- "$@" fi if command -v su >/dev/null 2>&1; then exec su -s /bin/sh -c '\''exec "$@"'\'' -- "$target_user" hostexec-su "$@" fi fi if command -v setpriv >/dev/null 2>&1; then if [ -n "$target_user" ]; then exec setpriv --reuid "$target_uid" --regid "$target_gid" --init-groups -- "$@" fi exec setpriv --reuid "$target_uid" --regid "$target_gid" --clear-groups -- "$@" fi if command -v nsenter >/dev/null 2>&1; then exec nsenter -t 1 -m -u -i -n -p -S "$target_uid" -G "$target_gid" -- "$@" fi echo "hostexec: unable to switch to host uid:gid $target_uid:$target_gid" >&2 exit 69 ' exec docker run \ "${docker_args[@]}" \ --env HOSTEXEC_TARGET_UID="$target_uid" \ --env HOSTEXEC_TARGET_GID="$target_gid" \ "$helper_image" \ nsenter -t 1 -m -u -i -n -p -- /bin/sh -c "$run_as_container_user" hostexec-user "$@"