vault-ops/infra/archiv/03_issue_vault_server_cert.sh.bk2
Blade34242 e0b3c80819 Update
2025-11-26 08:56:50 +01:00

116 lines
4.1 KiB
Bash
Executable file

#!/usr/bin/env bash
set -Eeuo pipefail
# 03_issue_vault_server_cert.sh
#
# Purpose:
# Issue a Vault server cert from the environment's Intermediate in Vault,
# and write files into /home/vault/tls-<env>.
#
# It composes:
# - fullchain.crt = server cert + intermediate
# - ca_chain.pem = intermediate + root (root from your offline-root location)
#
# Usage:
# VAULT_TOKEN=hvs.XXX ./03_issue_vault_server_cert.sh \
# --env test --config ./config/apps.yaml \
# --cn vault.test.privsec.ch \
# --dns "vault.test.privsec.ch,localhost" \
# --ips "127.0.0.1,::1" \
# --ttl 720h
#
# NOTE:
# If your offline-root is elsewhere, pass --root-dir <path>.
if [[ -t 1 ]]; then B=$'\e[1m'; R=$'\e[0m'; G=$'\e[32m'; E=$'\e[31m'; else B= R= G= E=; fi
ok(){ echo -e "🟩 ${G}${B}$*${R}"; }
die(){ echo -e "🟥 ${E}${B}$*${R}" >&2; exit 1; }
: "${VAULT_TOKEN:?Set VAULT_TOKEN}"
# ---- Defaults (updated) ----
CFG="./config/apps.yaml"
ENV_NAME="test"
CN="vault.test.privsec.ch"
DNS="" # if empty, will default to "<CN>,localhost"
IPS="127.0.0.1,::1"
TTL="720h"
ROOT_DIR_OVERRIDE=""
# ---- Args ----
while [[ $# -gt 0 ]]; do
case "$1" in
--config) CFG="$2"; shift 2;;
--env) ENV_NAME="$2"; shift 2;;
--cn) CN="$2"; shift 2;;
--dns) DNS="$2"; shift 2;;
--ips) IPS="$2"; shift 2;;
--ttl) TTL="$2"; shift 2;;
--root-dir) ROOT_DIR_OVERRIDE="$2"; shift 2;;
-h|--help) sed -n '1,200p' "$0"; exit 0;;
*) die "Unknown arg: $1";;
esac
done
# If DNS not provided, default to "<CN>,localhost"
[[ -n "$DNS" ]] || DNS="${CN},localhost"
need(){ command -v "$1" >/dev/null || { die "missing: $1"; }; }
need vault; need jq; need python3; need sudo
CFG_ABS="$(readlink -f "$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"
export VAULT_ADDR
ME_HOME="$(cd ~ && pwd)"
ROOT_DIR="${ROOT_DIR_OVERRIDE:-${ME_HOME}/vault/offline-root/${ENV_NAME}}"
ROOT_CRT="${ROOT_DIR}/root-ca.pem"
[[ -s "$ROOT_CRT" ]] || die "root-ca.pem not found at $ROOT_CRT (run your offline-root step)"
TLSDIR="/home/vault/tls-${ENV_NAME}"
sudo install -d -m 0755 -o vault -g vault "${TLSDIR}"
# ---- Ensure PKI role exists (based on CN base domain) ----
BASE="$(echo "${CN}" | sed 's/^[^.]*\.//')" # e.g. vault.test.privsec.ch -> test.privsec.ch
vault write "${INT_MOUNT}/roles/vault-server" \
key_type="ec" allow_ip_sans=true \
allowed_domains="${BASE}" allow_subdomains=true allow_bare_domains=true \
server_flag=true client_flag=false max_ttl="2160h" >/dev/null 2>&1 || true
# ---- Issue cert ----
ARGS=( "common_name=${CN}" "ttl=${TTL}" )
[[ -n "$DNS" ]] && ARGS+=( "alt_names=${DNS}" )
[[ -n "$IPS" ]] && ARGS+=( "ip_sans=${IPS}" )
RESP="$(vault write -format=json "${INT_MOUNT}/issue/vault-server" "${ARGS[@]}")" \
|| die "vault issue failed"
CERT="$(echo "$RESP" | jq -r '.data.certificate')"
KEY="$(echo "$RESP" | jq -r '.data.private_key')"
[[ -n "$CERT" && -n "$KEY" ]] || die "issue response missing certificate/private_key"
# fetch intermediate public
INT_CRT="$(vault read -field=certificate "${INT_MOUNT}/cert/ca")"
[[ -n "$INT_CRT" ]] || die "failed to fetch intermediate from ${INT_MOUNT}/cert/ca"
# ---- Write files ----
echo "${KEY}" | sudo install -m 0600 -o vault -g vault /dev/stdin "${TLSDIR}/server.key"
echo "${CERT}" | sudo install -m 0644 -o vault -g vault /dev/stdin "${TLSDIR}/server.crt"
{ echo "${CERT}"; echo "${INT_CRT}"; } \
| sudo install -m 0644 -o vault -g vault /dev/stdin "${TLSDIR}/fullchain.crt"
{ echo "${INT_CRT}"; cat "${ROOT_CRT}"; } \
| sudo install -m 0644 -o vault -g vault /dev/stdin "${TLSDIR}/ca_chain.pem"
ok "Wrote:
- ${TLSDIR}/server.key (0600)
- ${TLSDIR}/server.crt (0644)
- ${TLSDIR}/fullchain.crt (server + intermediate)
- ${TLSDIR}/ca_chain.pem (intermediate + root)"