139 lines
4.8 KiB
Bash
Executable file
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
|