Files
netbird/client/test/rootless-arbitrary-uid-docker.sh
T

126 lines
3.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -eEuo pipefail
RUNTIME="${CONTAINER_RUNTIME:-}"
if [[ -z "${RUNTIME}" ]]; then
if command -v docker >/dev/null 2>&1; then
RUNTIME=docker
elif command -v podman >/dev/null 2>&1; then
RUNTIME=podman
else
echo "docker or podman is required" >&2
exit 127
fi
fi
if ! command -v "${RUNTIME}" >/dev/null 2>&1; then
echo "container runtime not found: ${RUNTIME}" >&2
exit 127
fi
if ! command -v go >/dev/null 2>&1; then
echo "go is required" >&2
exit 127
fi
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
IMAGE="${IMAGE:-netbird-rootless-arbitrary-uid-test:local}"
TARGETARCH="${TARGETARCH:-$(go env GOARCH)}"
PLATFORM="${PLATFORM:-linux/${TARGETARCH}}"
WAIT_TIMEOUT="${WAIT_TIMEOUT:-30}"
TMP_DIR="$(mktemp -d)"
CONTAINER="netbird-rootless-uid-${RANDOM}-$$"
cleanup() {
local status=$?
"${RUNTIME}" rm -f "${CONTAINER}" >/dev/null 2>&1 || true
rm -rf "${TMP_DIR}"
exit "${status}"
}
trap cleanup EXIT
container_logs() {
echo "---- ${CONTAINER} logs ----" >&2
"${RUNTIME}" logs "${CONTAINER}" >&2 || true
echo "----------------------------" >&2
}
build_image() {
echo "==> Building Linux ${TARGETARCH} netbird binary"
mkdir -p "${TMP_DIR}/context/client"
cp "${ROOT_DIR}/client/Dockerfile-rootless" "${TMP_DIR}/context/Dockerfile"
cp "${ROOT_DIR}/client/netbird-entrypoint.sh" "${TMP_DIR}/context/client/netbird-entrypoint.sh"
(
cd "${ROOT_DIR}"
CGO_ENABLED=0 GOOS=linux GOARCH="${TARGETARCH}" \
go build -o "${TMP_DIR}/context/netbird" ./client
)
echo "==> Building ${IMAGE} for ${PLATFORM}"
"${RUNTIME}" build \
--platform "${PLATFORM}" \
--build-arg NETBIRD_BINARY=netbird \
-t "${IMAGE}" \
-f "${TMP_DIR}/context/Dockerfile" \
"${TMP_DIR}/context"
}
start_container() {
echo "==> Starting ${CONTAINER} as unmapped UID 1001230000"
"${RUNTIME}" run --rm -d \
--name "${CONTAINER}" \
--user 1001230000:0 \
--cap-drop=ALL \
--security-opt=no-new-privileges \
--entrypoint /usr/local/bin/netbird \
"${IMAGE}" \
--log-file console \
service run >/dev/null
}
wait_until_live() {
local deadline=$((SECONDS + WAIT_TIMEOUT))
while (( SECONDS < deadline )); do
if "${RUNTIME}" exec "${CONTAINER}" \
/usr/local/bin/netbird status --check live >/dev/null 2>&1; then
return 0
fi
if [[ "$("${RUNTIME}" inspect -f '{{.State.Running}}' "${CONTAINER}" 2>/dev/null || true)" != "true" ]]; then
echo "container exited before the daemon became live" >&2
container_logs
return 1
fi
sleep 1
done
echo "timed out waiting for the daemon after ${WAIT_TIMEOUT}s" >&2
container_logs
return 1
}
assert_arbitrary_uid_contract() {
echo "==> Verifying arbitrary UID image contract"
"${RUNTIME}" exec "${CONTAINER}" sh -ec '
test "$(id -u)" = 1001230000
test "$(id -g)" = 0
test "${HOME}" = /var/lib/netbird
test -r /usr/local/bin/netbird-entrypoint.sh
test -x /usr/local/bin/netbird-entrypoint.sh
test "$(head -n 1 /usr/local/bin/netbird-entrypoint.sh)" = "#!/usr/bin/env bash"
bash -n /usr/local/bin/netbird-entrypoint.sh
touch /var/lib/netbird/.uid-smoke
rm /var/lib/netbird/.uid-smoke
test -S /var/lib/netbird/netbird.sock
'
"${RUNTIME}" exec "${CONTAINER}" \
/usr/local/bin/netbird profile list >/dev/null
}
build_image
start_container
wait_until_live
assert_arbitrary_uid_contract
echo "==> Rootless arbitrary UID validation passed"