81 lines
2.9 KiB
Bash
Executable file
81 lines
2.9 KiB
Bash
Executable file
#!/usr/bin/env bash
|
|
set -Eeuo pipefail
|
|
# 05_issue_admin_client_cert.sh
|
|
#
|
|
# Purpose:
|
|
# Issue an ADMIN mTLS client certificate from the environment's Intermediate PKI in Vault
|
|
# and store it under $HOME/vault/tls-admin (for VAULT_CLIENT_CERT/KEY).
|
|
#
|
|
# Usage:
|
|
# VAULT_TOKEN=hvs.XXX \
|
|
# ./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 || die "missing: $1"; }
|
|
need vault; need jq; need python3; need install
|
|
|
|
: "${VAULT_TOKEN:?Set VAULT_TOKEN (or VAULT_ADMIN_TOKEN)}"
|
|
if [[ -z "${VAULT_TOKEN:-}" && -n "${VAULT_ADMIN_TOKEN:-}" ]]; then
|
|
export VAULT_TOKEN="$VAULT_ADMIN_TOKEN"
|
|
fi
|
|
|
|
CFG="./config/apps.yaml"; ENV_NAME="test"; CN="vault-admin-setup"; TTL="180h"
|
|
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
|
|
|
|
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"
|
|
export VAULT_ADDR
|
|
|
|
ROLE="admin-client"
|
|
ok "Using Vault @ ${VAULT_ADDR} (mount: ${INT_MOUNT}) role=${ROLE} CN=${CN} TTL=${TTL}"
|
|
|
|
# Tighten for prod if desired (allowed_domains/allowed_uri_sans); default keeps it simple.
|
|
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 || true
|
|
|
|
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")"
|
|
|
|
OUT="$HOME/vault/tls-admin"; mkdir -p "$OUT"
|
|
echo "${KEY}" | install -m 0600 /dev/stdin "${OUT}/admin.key"
|
|
echo "${CERT}" | install -m 0644 /dev/stdin "${OUT}/admin.crt"
|
|
echo "${ISSUING_CA}" | install -m 0644 /dev/stdin "${OUT}/issuing_ca.pem"
|
|
|
|
ok "Wrote:"
|
|
echo " - ${OUT}/admin.key (0600)"
|
|
echo " - ${OUT}/admin.crt (0644)"
|
|
echo " - ${OUT}/issuing_ca.pem (issuer of admin.crt)"
|
|
|
|
cat <<EOF
|
|
Use:
|
|
export VAULT_CLIENT_CERT='${OUT}/admin.crt'
|
|
export VAULT_CLIENT_KEY='${OUT}/admin.key'
|
|
vault status
|
|
EOF
|
|
|