feat(openbao): add SSH engine automation for ops-warden signing
Declarative roles, warden-sign policy, apply/verify scripts, and Makefile targets openbao-configure-ssh and openbao-verify-ssh. Document operator flow in docs/openbao.md for NET-WP-0020 T5 / WP-0008 T2.
This commit is contained in:
111
scripts/openbao-verify-ssh-engine.sh
Executable file
111
scripts/openbao-verify-ssh-engine.sh
Executable file
@@ -0,0 +1,111 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
OPENBAO_NAMESPACE="${OPENBAO_NAMESPACE:-openbao}"
|
||||
OPENBAO_RELEASE="${OPENBAO_RELEASE:-openbao}"
|
||||
KUBECTL="${KUBECTL:-kubectl}"
|
||||
TOKEN_FILE="${OPENBAO_TOKEN_FILE:-}"
|
||||
SSH_MOUNT="${OPENBAO_SSH_MOUNT:-ssh}"
|
||||
EXPECTED_ROLES="${OPENBAO_SSH_EXPECTED_ROLES:-adm-role agt-role atm-role}"
|
||||
USE_TOKEN_HELPER=0
|
||||
DRY_RUN=0
|
||||
|
||||
usage() {
|
||||
cat <<'USAGE'
|
||||
Usage: scripts/openbao-verify-ssh-engine.sh [--dry-run] [--use-token-helper]
|
||||
|
||||
Non-mutating checks: ssh/ mount present, expected roles listed, warden-sign policy.
|
||||
USAGE
|
||||
}
|
||||
|
||||
while [ "$#" -gt 0 ]; do
|
||||
case "$1" in
|
||||
--dry-run) DRY_RUN=1; shift ;;
|
||||
--use-token-helper) USE_TOKEN_HELPER=1; shift ;;
|
||||
-h|--help) usage; exit 0 ;;
|
||||
*) echo "ERROR: unknown argument: $1" >&2; usage >&2; exit 2 ;;
|
||||
esac
|
||||
done
|
||||
|
||||
pod="${OPENBAO_RELEASE}-0"
|
||||
FAILURES=0
|
||||
|
||||
fail() { FAILURES=$((FAILURES + 1)); printf '[FAIL] %s\n' "$*" >&2; }
|
||||
ok() { printf '[OK] %s\n' "$*"; }
|
||||
|
||||
read_token() {
|
||||
if [ "$USE_TOKEN_HELPER" -eq 1 ]; then
|
||||
printf '__USE_TOKEN_HELPER__\n'
|
||||
return
|
||||
fi
|
||||
if [ "$DRY_RUN" -eq 1 ]; then
|
||||
printf 'dry-run-token\n'
|
||||
return
|
||||
fi
|
||||
if [ -n "$TOKEN_FILE" ] && [ -f "$TOKEN_FILE" ]; then
|
||||
head -n 1 "$TOKEN_FILE"
|
||||
return
|
||||
fi
|
||||
local token
|
||||
read -r -s -p "OpenBao token: " token
|
||||
printf '\n' >&2
|
||||
printf '%s\n' "$token"
|
||||
}
|
||||
|
||||
remote_bao() {
|
||||
local token="$1"
|
||||
shift
|
||||
if [ "$token" = "__USE_TOKEN_HELPER__" ]; then
|
||||
$KUBECTL exec -n "$OPENBAO_NAMESPACE" "$pod" -- bao "$@"
|
||||
return
|
||||
fi
|
||||
if [ "$DRY_RUN" -eq 1 ]; then
|
||||
printf 'DRY-RUN: bao %s\n' "$*"
|
||||
return 0
|
||||
fi
|
||||
printf '%s\n' "$token" | $KUBECTL exec -i -n "$OPENBAO_NAMESPACE" "$pod" -- \
|
||||
sh -c 'read -r BAO_TOKEN; export BAO_TOKEN; exec bao "$@"' sh "$@"
|
||||
}
|
||||
|
||||
token="$(read_token)"
|
||||
secrets_out="$(remote_bao "$token" secrets list 2>&1)" || {
|
||||
fail "secrets list failed: $secrets_out"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if printf '%s\n' "$secrets_out" | grep -Eq "(^|[[:space:]])${SSH_MOUNT}/"; then
|
||||
ok "SSH mount ${SSH_MOUNT}/ is enabled"
|
||||
else
|
||||
fail "SSH mount ${SSH_MOUNT}/ not found in secrets list"
|
||||
fi
|
||||
|
||||
roles_out="$(remote_bao "$token" list "${SSH_MOUNT}/roles" 2>&1)" || {
|
||||
fail "list ${SSH_MOUNT}/roles failed: $roles_out"
|
||||
exit 1
|
||||
}
|
||||
|
||||
for role in $EXPECTED_ROLES; do
|
||||
if printf '%s\n' "$roles_out" | grep -q "$role"; then
|
||||
ok "role ${role} exists"
|
||||
else
|
||||
fail "role ${role} missing"
|
||||
fi
|
||||
done
|
||||
|
||||
policy_out="$(remote_bao "$token" policy list 2>&1)" || {
|
||||
fail "policy list failed: $policy_out"
|
||||
exit 1
|
||||
}
|
||||
|
||||
if printf '%s\n' "$policy_out" | grep -q 'warden-sign'; then
|
||||
ok "policy warden-sign present"
|
||||
else
|
||||
fail "policy warden-sign missing"
|
||||
fi
|
||||
|
||||
if [ "$FAILURES" -gt 0 ]; then
|
||||
printf '\nSSH engine verification failed (%s failure(s)).\n' "$FAILURES" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
printf '\nSSH engine verification passed.\n'
|
||||
Reference in New Issue
Block a user