vault-ops/infra/versions/05_issue_admin_client_cert-v2.sh
2026-04-14 11:45:15 +07:00

139 lines
4.8 KiB
Bash
Executable file

#!/usr/bin/env bash
set -Eeuo pipefail
# 05_issue_admin_client_cert_v2.sh (strict)
#
# Zweck:
# - Aus /root/vault/offline-root/vault-<env>-init.json den root_token lesen
# - Admin-Token mit policy=admin erzeugen (falls /root/vault/tokens/<env>-admin.token nicht existiert)
# - Admin-Token nach /root/vault/tokens/<env>-admin.token schreiben
# - Admin-mTLS-Client-Zert aus Intermediate PKI holen
# - Zert nach /root/vault/tls-admin/<env>/admin.{crt,key} schreiben
#
# Aufruf (über Wrapper):
# sudo vault-run-home-safe test -- \
# /home/blade34242/vault/infra/05_issue_admin_client_cert.sh \
# --env test --config ./config/apps.yaml \
# --cn vault-admin-setup --ttl 180h
if [[ -t 1 ]]; then
B=$'\e[1m'; R=$'\e[0m'; G=$'\e[32m'; Y=$'\e[33m'; E=$'\e[31m'
else
B= R= G= Y= E=
fi
ok(){ echo -e "🟩 ${G}${B}$*${R}"; }
warn(){ echo -e "🟨 ${Y}${B}$*${R}"; }
die(){ echo -e "🟥 ${E}${B}$*${R}" >&2; exit 1; }
need(){ command -v "$1" >/dev/null 2>&1 || die "missing: $1"; }
need vault; need jq; need python3; need install
CFG="./config/apps.yaml"
ENV_NAME="test"
CN="vault-admin-setup"
TTL="180h"
# --- Argumente parsen (nur das Nötigste) ---
while [[ $# -gt 0 ]]; do
case "$1" in
--config) CFG="$2"; shift 2;;
--env) ENV_NAME="$2"; shift 2;;
--cn) CN="$2"; shift 2;;
--ttl) TTL="$2"; shift 2;;
-h|--help) sed -n '1,200p' "$0"; exit 0;;
*) die "Unknown arg: $1";;
esac
done
# --- Vault-Config aus apps.yaml lesen ---
CFG_ABS="$(readlink -f "$CFG")" || die "cannot resolve $CFG"
CFGJSON="$(python3 - <<PY
import yaml, json; print(json.dumps(yaml.safe_load(open("$CFG_ABS","r",encoding="utf-8"))))
PY
)"
jqenv(){ echo "$CFGJSON" | jq -r ".environments.\"$ENV_NAME\"$1"; }
VAULT_ADDR="$(jqenv '.vault_addr')"
INT_MOUNT="$(jqenv '.pki_mount')"
[[ "$VAULT_ADDR" != "null" && "$INT_MOUNT" != "null" ]] || die "incomplete config: vault_addr/pki_mount in apps.yaml for env=$ENV_NAME"
export VAULT_ADDR
ok "Env=${ENV_NAME} Vault=${VAULT_ADDR} PKI_MOUNT=${INT_MOUNT}"
# ⚠️ Bootstrap OHNE Client-mTLS (admin.crt existiert noch nicht)
#unset VAULT_CLIENT_CERT VAULT_CLIENT_KEY VAULT_TLS_SERVER_NAME
export VAULT_SKIP_VERIFY=1
INIT_JSON="/root/vault/offline-root/vault-${ENV_NAME}-init.json"
TOKEN_FILE="/root/vault/tokens/${ENV_NAME}-admin.token"
TLS_DIR="/root/vault/tls-admin/${ENV_NAME}"
[[ -r "$INIT_JSON" ]] || die "Init JSON not readable: $INIT_JSON"
mkdir -p /root/vault/tokens "$TLS_DIR"
ADMIN_TOKEN=""
# --- 1) Admin-Token: wenn Datei existiert, strikt verwenden ---
if [[ -r "$TOKEN_FILE" ]]; then
ADMIN_TOKEN="$(<"$TOKEN_FILE")"
[[ -n "$ADMIN_TOKEN" ]] || die "admin token file $TOKEN_FILE is empty"
ok "Using existing admin token from ${TOKEN_FILE}"
else
# --- 2) Sonst: root_token lesen & neuen Admin-Token erzeugen ---
ROOT_TOKEN="$(jq -r '.root_token // empty' "$INIT_JSON")"
[[ -n "$ROOT_TOKEN" ]] || die "root_token missing/empty in $INIT_JSON"
warn "No admin token file; creating new admin token from root_token in $INIT_JSON for env=${ENV_NAME}"
RESP_TOKEN="$(
VAULT_TOKEN="$ROOT_TOKEN" vault token create \
-policy=admin \
-display-name="${ENV_NAME}-admin-bootstrap" \
-format=json
)" || die "failed to create admin token via root_token"
ADMIN_TOKEN="$(echo "$RESP_TOKEN" | jq -r '.auth.client_token')"
[[ -n "$ADMIN_TOKEN" && "$ADMIN_TOKEN" != "null" ]] || die "no client_token in token create response"
echo "$ADMIN_TOKEN" | install -m 0600 /dev/stdin "$TOKEN_FILE"
ok "Wrote new admin token to ${TOKEN_FILE}"
fi
# Ab hier nur noch mit Admin-Token
VAULT_TOKEN="$ADMIN_TOKEN"
export VAULT_TOKEN
ROLE="admin-client"
ok "Using role=${ROLE} CN=${CN} TTL=${TTL}"
# Rolle (best effort) konfigurieren (keine Fallback-Logik, einfach versuchen)
vault write "${INT_MOUNT}/roles/${ROLE}" \
server_flag=false client_flag=true \
allow_any_name=true key_usage="DigitalSignature" ext_key_usage="ClientAuth" \
max_ttl="720h" >/dev/null 2>&1 || warn "could not configure role ${ROLE}, continuing"
RESP="$(vault write -format=json "${INT_MOUNT}/issue/${ROLE}" common_name="${CN}" ttl="${TTL}")" \
|| die "issue failed"
CERT="$(echo "$RESP" | jq -r .data.certificate)"
KEY="$(echo "$RESP" | jq -r .data.private_key)"
ISSUING_CA="$(vault read -field=certificate "${INT_MOUNT}/cert/ca")"
echo "${KEY}" | install -m 0600 /dev/stdin "${TLS_DIR}/admin.key"
echo "${CERT}" | install -m 0644 /dev/stdin "${TLS_DIR}/admin.crt"
echo "${ISSUING_CA}" | install -m 0644 /dev/stdin "${TLS_DIR}/issuing_ca.pem"
ok "Wrote:"
echo " - ${TLS_DIR}/admin.key (0600)"
echo " - ${TLS_DIR}/admin.crt (0644)"
echo " - ${TLS_DIR}/issuing_ca.pem (issuer of admin.crt)"
cat <<EOF
Use (root):
export VAULT_CLIENT_CERT='${TLS_DIR}/admin.crt'
export VAULT_CLIENT_KEY='${TLS_DIR}/admin.key'
# VAULT_CACERT / VAULT_TLS_SERVER_NAME kommen aus /root/vault/env/${ENV_NAME}.env
vault status
EOF