106 lines
3.9 KiB
Bash
Executable file
106 lines
3.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
|
|
# Distribute a CA file from /home/vault/tls-<env>/... to /home/<user>/vault/ca/ca.pem
|
|
# Safe/idempotent: skips if identical; use --force to overwrite.
|
|
#
|
|
# Examples:
|
|
# ./distribute_ca_to_agents.sh --src "/home/vault/tls-test/root_ca.pem" --users "nctest apptest proxytest"
|
|
# ./distribute_ca_to_agents.sh --env test --which chain --users-file ./agents.txt
|
|
# (uses /home/vault/tls-test/ca_chain.pem)
|
|
#
|
|
# Options:
|
|
# --src <path> explicit source PEM (overrides --env/--which)
|
|
# --env <name> e.g. test|prod (builds /home/vault/tls-<env>/<file>)
|
|
# --which root|chain pick root_ca.pem (default) or ca_chain.pem
|
|
# --users "u1 u2" space-separated users
|
|
# --users-file <file> one user per line; # comments OK
|
|
# --force overwrite even if target exists
|
|
# -h|--help show help
|
|
|
|
# pretty logs
|
|
if [[ -t 1 ]]; then
|
|
B=$'\e[1m'; R=$'\e[0m'; BL=$'\e[34m'; G=$'\e[32m'; Y=$'\e[33m'; E=$'\e[31m'
|
|
else B= R= BL= G= Y= E=; fi
|
|
ts(){ date +"%Y-%m-%d %H:%M:%S"; }
|
|
info(){ echo -e "🟦 ${BL}${B}[$(ts)]${R} $*"; }
|
|
ok(){ echo -e "🟩 ${G}${B}[$(ts)]${R} $*"; }
|
|
warn(){ echo -e "🟨 ${Y}${B}[$(ts)]${R} $*"; }
|
|
err(){ echo -e "🟥 ${E}${B}[$(ts)]${R} $*" >&2; }
|
|
|
|
need(){ command -v "$1" >/dev/null 2>&1 || { err "missing: $1"; exit 2; }; }
|
|
need sudo; need install; need getent
|
|
command -v openssl >/dev/null 2>&1 || warn "openssl not found → skip PEM parse check"
|
|
|
|
SRC=""; ENV_NAME=""; WHICH="root"; USERS=""; USERS_FILE=""; FORCE=0
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
--src) SRC="$2"; shift 2;;
|
|
--env) ENV_NAME="$2"; shift 2;;
|
|
--which) WHICH="$2"; shift 2;;
|
|
--users) USERS="$2"; shift 2;;
|
|
--users-file) USERS_FILE="$2"; shift 2;;
|
|
--force) FORCE=1; shift;;
|
|
-h|--help) sed -n '1,200p' "$0"; exit 0;;
|
|
*) err "unknown arg: $1"; exit 2;;
|
|
esac
|
|
done
|
|
|
|
# resolve source
|
|
if [[ -z "$SRC" ]]; then
|
|
[[ -n "$ENV_NAME" ]] || { err "Either --src or --env is required."; exit 2; }
|
|
case "$WHICH" in
|
|
root) SRC="/home/vault/tls-${ENV_NAME}/root_ca.pem" ;;
|
|
chain) SRC="/home/vault/tls-${ENV_NAME}/ca_chain.pem" ;;
|
|
*) err "--which must be root|chain"; exit 2;;
|
|
esac
|
|
fi
|
|
sudo test -r "$SRC" || { err "source not readable via sudo: $SRC"; exit 3; }
|
|
if command -v openssl >/dev/null 2>&1; then
|
|
sudo openssl x509 -in "$SRC" -noout >/dev/null 2>&1 || warn "openssl can't parse a single cert from $SRC (bundle is still OK)"
|
|
fi
|
|
|
|
# users
|
|
USERS_ARR=()
|
|
[[ -n "$USERS" ]] && read -r -a USERS_ARR <<<"$USERS"
|
|
if [[ -n "$USERS_FILE" ]]; then
|
|
[[ -r "$USERS_FILE" ]] || { err "users file not readable: $USERS_FILE"; exit 2; }
|
|
while IFS= read -r line; do
|
|
line="${line%%#*}"; line="$(echo "$line" | xargs || true)"
|
|
[[ -z "$line" ]] && continue
|
|
USERS_ARR+=("$line")
|
|
done < "$USERS_FILE"
|
|
fi
|
|
(( ${#USERS_ARR[@]} > 0 )) || { err "No users specified. Use --users or --users-file."; exit 2; }
|
|
|
|
info "Source: $SRC"
|
|
info "Users: ${USERS_ARR[*]}"
|
|
info "Target name: ca.pem"
|
|
info "Mode: $([[ $FORCE -eq 1 ]] && echo 'force overwrite' || echo 'skip if exists / identical')"
|
|
echo
|
|
|
|
COPIED=0; SKIPPED=0; MISSING=0
|
|
for u in "${USERS_ARR[@]}"; do
|
|
if ! id -u "$u" >/dev/null 2>&1; then
|
|
warn "user not found: $u → skip"; ((MISSING++)); continue
|
|
fi
|
|
HOME_DIR="$(getent passwd "$u" | cut -d: -f6)"; [[ -n "$HOME_DIR" ]] || HOME_DIR="/home/$u"
|
|
DEST_DIR="${HOME_DIR}/vault/ca"; DEST="${DEST_DIR}/ca.pem"
|
|
|
|
sudo install -d -m 0755 -o "$u" -g "$u" "$DEST_DIR" >/dev/null
|
|
if [[ -f "$DEST" && $FORCE -eq 0 ]] && sudo cmp -s "$SRC" "$DEST"; then
|
|
ok "[$u] up-to-date → ${DEST}"; ((SKIPPED++)); continue
|
|
fi
|
|
if [[ -f "$DEST" && $FORCE -eq 0 ]]; then
|
|
ok "[$u] exists → skip (use --force to overwrite): ${DEST}"; ((SKIPPED++)); continue
|
|
fi
|
|
if sudo install -m 0644 -o "$u" -g "$u" "$SRC" "$DEST"; then
|
|
ok "[$u] wrote ${DEST}"; ((COPIED++))
|
|
else
|
|
err "[$u] failed to write ${DEST}"
|
|
fi
|
|
done
|
|
|
|
echo
|
|
ok "Done. Copied: ${COPIED}, Skipped: ${SKIPPED}, Missing users: ${MISSING}"
|
|
|