99 lines
3.7 KiB
Bash
Executable file
99 lines
3.7 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 also 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 /home/<deinUser>/vault/config/apps.yaml \
|
|
# --cn vault.int.privsec.ch \
|
|
# --dns vault.int.privsec.ch,localhost,host.containers.internal \
|
|
# --ips 127.0.0.1,::1 \
|
|
# --ttl 720h
|
|
#
|
|
# IMPORTANT:
|
|
# Provide offline root path with --root-dir if you put it somewhere else.
|
|
|
|
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}"
|
|
CFG="./config/apps.yaml"; ENV_NAME="test"; CN="vault.local"; DNS="localhost"; IPS="127.0.0.1,::1"; TTL="720h"
|
|
ROOT_DIR_OVERRIDE=""
|
|
|
|
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
|
|
|
|
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 script #02)"
|
|
|
|
TLSDIR="/home/vault/tls-${ENV_NAME}"
|
|
sudo install -d -m 0755 -o vault -g vault "${TLSDIR}"
|
|
|
|
# Ensure PKI role exists (liberal domains based on CN base)
|
|
BASE="$(echo "${CN}" | sed 's/^[^.]*\.//')"
|
|
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
|
|
|
|
ARGS=( "common_name=${CN}" "format=pem_bundle" "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[@]}")"
|
|
|
|
CERT="$(echo "$RESP" | jq -r .data.certificate)"
|
|
KEY="$(echo "$RESP" | jq -r .data.private_key)"
|
|
|
|
# fetch intermediate (public) from mount and compose chains
|
|
INT_CRT="$(vault read -field=certificate "${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)"
|
|
|