feat: container-based Bitwarden CLI using native Rust binary (no Node.js)

Replace the Node.js @bitwarden/cli dependency with the pre-compiled
native Rust binary (v2026.7.0) for CMMC/ITAR/STIG audit readiness.
The Node.js dependency tree was a significant attack surface that
would fail security audits.

Infrastructure:
- docker/bw-native/Dockerfile: minimal debian-slim + native bw binary
- scripts/bw-cli.sh: host wrapper handling full auth lifecycle
  (config, API-key login, unlock, sync) inside the container
- scripts/bw-entrypoint.sh: container entrypoint for auth lifecycle
- scripts/bw-install.sh: one-command installer (download, build, deploy)

Root causes fixed:
- ~/.config/bw/env values now single-quoted (master password has $
  chars that shell expansion corrupted, truncating 32→16 chars)
- Added BW_SERVER for self-hosted instance (pwvault.turnsys.com)
- Entrypoint bw config server tolerates re-run (|| true)

All scripts pass shellcheck with zero warnings including info-level.
Verified: bw status (unlocked, coo@turnsys.com), generate, list items.

💘 Generated with Crush

Assisted-by: Crush:glm-5.2
This commit is contained in:
TSYS Group COO
2026-09-07 14:51:13 -05:00
parent 2c91545c0f
commit dce7164889
8 changed files with 349 additions and 15 deletions
+75
View File
@@ -0,0 +1,75 @@
#!/usr/bin/env bash
# bw-cli.sh — Bitwarden CLI host wrapper (container-based, native Rust binary).
#
# Provides transparent `bw` access on hosts where the CLI is not installed
# natively. Runs the pre-compiled Rust bw binary inside a minimal Docker
# container (debian-slim + ca-certificates, NO Node.js).
#
# All tool execution happens inside the container. Nothing runs on the host
# except this wrapper, which only invokes docker.
#
# Usage:
# bw-cli.sh status Check vault status
# bw-cli.sh list items List vault items
# bw-cli.sh list collections List collections
# bw-cli.sh get password "Item" Retrieve a password
# bw-cli.sh get totp "Item" Retrieve a TOTP code
# bw-cli.sh get item "Item" Full item JSON
# bw-cli.sh generate -ulns Generate a password
#
# Install to ~/.local/bin/bw via:
# scripts/bw-install.sh
#
# Environment overrides:
# BW_ENV_FILE Path to credentials (default: ~/.config/bw/env)
# BW_IMAGE Docker image (default: reachableceo-bw-native:2026.7.0)
# BW_VOLUME Docker volume for persisted login state
# (default: tsys-bw-cli-state)
# BW_LIB_DIR Directory containing entrypoint.sh (default: ~/.local/share/bw)
set -euo pipefail
BW_ENV_FILE="${BW_ENV_FILE:-$HOME/.config/bw/env}"
BW_IMAGE="${BW_IMAGE:-reachableceo-bw-native:2026.7.0}"
BW_VOLUME="${BW_VOLUME:-tsys-bw-cli-state}"
BW_LIB_DIR="${BW_LIB_DIR:-$HOME/.local/share/bw}"
# --- Validate prerequisites ---
if [ ! -f "$BW_ENV_FILE" ]; then
echo "bw: credential file not found: $BW_ENV_FILE" >&2
echo " expected BW_CLIENTID, BW_CLIENTSECRET, BW_PASSWORD, BW_SERVER" >&2
exit 1
fi
if ! docker image inspect "$BW_IMAGE" >/dev/null 2>&1; then
echo "bw: Docker image not found: $BW_IMAGE" >&2
echo " build it: scripts/bw-install.sh" >&2
exit 1
fi
if [ ! -f "$BW_LIB_DIR/entrypoint.sh" ]; then
echo "bw: entrypoint script missing: $BW_LIB_DIR/entrypoint.sh" >&2
echo " install via: scripts/bw-install.sh" >&2
exit 1
fi
# --- Load credentials (values are single-quoted in env file) ---
set -a
# shellcheck source=/dev/null
. "$BW_ENV_FILE"
set +a
# --- Create persistent volume for BW CLI login state ---
docker volume create "$BW_VOLUME" >/dev/null 2>&1 || true
# --- Run bw inside the container ---
docker run --rm -i \
-e BW_CLIENTID \
-e BW_CLIENTSECRET \
-e BW_PASSWORD \
-e BW_SERVER \
-v "$BW_VOLUME:/root/.config/Bitwarden CLI" \
-v "$BW_LIB_DIR/entrypoint.sh:/opt/bw/entrypoint.sh:ro" \
--entrypoint sh \
"$BW_IMAGE" \
/opt/bw/entrypoint.sh "$@"