vault-ops/archiv/setup-vault-agent2.sh
2025-09-22 10:27:22 +02:00

279 lines
8.8 KiB
Bash
Executable file
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env bash
set -euo pipefail
# ======================================================
# Vault Agent One-Shot Provisioner (all inline, no deps)
# ======================================================
# Usage: ./setup-vault-agent.sh <APP_NAME> <TARGET_USER>
# Example: ./setup-vault-agent.sh test test
#
# Creates:
# - Policy pki-issue-<app>
# - AppRole <app>-pki-issue
# - PKI Role nginx-<app> (allowed_domains=<app>.example.com)
# - Agent config + template + post-script in /home/<user>/.vault-agent-<app>
# - systemd user service vault-agent-<app>.service (fallback: system-wide)
# - Writes TLS files to /home/<user>/tls/<app>.key + <app>.fullchain.pem
# ============================
# === Konfiguration ==========
# ============================
export VAULT_ADDR="${VAULT_ADDR:-http://127.0.0.1:22300}"
# !!! Dein Admin/Root Token hier eintragen oder via ENV setzen:
export VAULT_ADMIN_TOKEN="${VAULT_ADMIN_TOKEN:-}"
APP_NAME="${1:-test}" # 1. Argument: App-Name
TARGET_USER="${2:-test}" # 2. Argument: System-User
if [[ -z "$VAULT_ADMIN_TOKEN" ]]; then
echo "[ERROR] VAULT_ADMIN_TOKEN ist leer. Setze es vor dem Start oder trage es oben ein."
exit 2
fi
# Nutze explizit das Admin-Token für alle Vault-Calls:
export VAULT_TOKEN="${VAULT_ADMIN_TOKEN}"
ROLE_NAME="${APP_NAME}-pki-issue"
POLICY_NAME="pki-issue-${APP_NAME}"
AGENT_DIR="/home/${TARGET_USER}/.vault-agent-${APP_NAME}"
SERVICE_FILE="/home/${TARGET_USER}/.config/systemd/user/vault-agent-${APP_NAME}.service"
# PKI Mount/Rolle/Domain
PKI_MOUNT="pki-test"
PKI_ROLE="nginx-${APP_NAME}"
DOMAIN="${APP_NAME}.example.com"
# ============================
# === Helper ================
# ============================
log() { echo -e "\033[1;32m[INFO]\033[0m $*"; }
warn(){ echo -e "\033[1;33m[WARN]\033[0m $*"; }
err() { echo -e "\033[1;31m[ERROR]\033[0m $*" >&2; }
# ============================
# === Dependency-Checks ======
# ============================
for bin in vault jq systemctl; do
if ! command -v "$bin" >/dev/null 2>&1; then
err "Missing dependency: $bin (bitte installieren)"
exit 2
fi
done
# ============================
# === 1. Policy =============
# ============================
log "Erstelle Vault-Policy: ${POLICY_NAME}"
tmp_policy="$(mktemp)"
cat >"$tmp_policy" <<EOF
path "${PKI_MOUNT}/issue/${PKI_ROLE}" {
capabilities = ["create", "update"]
}
path "auth/approle/role/${ROLE_NAME}/role-id" {
capabilities = ["read"]
}
path "auth/approle/role/${ROLE_NAME}/secret-id" {
capabilities = ["create", "update"]
}
path "auth/token/renew-self" {
capabilities = ["update"]
}
EOF
vault policy write "${POLICY_NAME}" "$tmp_policy"
rm -f "$tmp_policy"
# ============================
# === 2. AppRole ============
# ============================
log "Erstelle AppRole: ${ROLE_NAME}"
vault write "auth/approle/role/${ROLE_NAME}" \
policies="${POLICY_NAME}" \
secret_id_ttl=0 \
secret_id_num_uses=0 \
token_ttl=24h \
token_max_ttl=0 \
bind_secret_id=true
# ============================
# === 3. PKI Role ===========
# ============================
log "Erstelle/aktualisiere PKI-Role: ${PKI_ROLE}"
vault write "${PKI_MOUNT}/roles/${PKI_ROLE}" \
allowed_domains="${DOMAIN}" \
allow_subdomains=true \
allow_bare_domains=true \
max_ttl="720h"
# ============================
# === 4. Credentials ========
# ============================
ROLE_ID="$(vault read -field=role_id "auth/approle/role/${ROLE_NAME}/role-id")"
SECRET_ID="$(vault write -f -field=secret_id "auth/approle/role/${ROLE_NAME}/secret-id")"
log "RoleID: ${ROLE_ID}"
log "SecretID: ${SECRET_ID:0:6}********"
# Schreibe sicher ins App-Home
sudo -u "${TARGET_USER}" bash -c "
umask 077
mkdir -p '${AGENT_DIR}/bin'
printf '%s\n' '${ROLE_ID}' > '${AGENT_DIR}/role_id'
printf '%s\n' '${SECRET_ID}' > '${AGENT_DIR}/secret_id'
chmod 600 '${AGENT_DIR}/role_id' '${AGENT_DIR}/secret_id'
mkdir -p '/home/${TARGET_USER}/tls'
"
# ============================
# === 5. Vault-Agent Config =
# ============================
log "Erstelle Vault-Agent-Konfiguration"
sudo -u "${TARGET_USER}" tee "${AGENT_DIR}/vault-agent.hcl" >/dev/null <<EOF
pid_file = "${AGENT_DIR}/pidfile"
auto_auth {
method "approle" {
mount_path = "auth/approle"
config = {
role_id_file_path = "${AGENT_DIR}/role_id"
secret_id_file_path = "${AGENT_DIR}/secret_id"
}
}
sink "file" {
config = {
path = "${AGENT_DIR}/token"
}
}
}
# Template rendert JSON in .issue.json; Post-Skript splittet nach ~/tls/
template {
source = "${AGENT_DIR}/cert.tpl"
destination = "${AGENT_DIR}/.issue.json"
command = ["${AGENT_DIR}/bin/vault-agent-post.sh"]
}
EOF
# ============================
# === 6. Template (JSON) ====
# ============================
log "Erstelle Cert-Template"
# ttl=5m: schnelles Testen der Rotation; für Prod anpassen/entfernen
sudo -u "${TARGET_USER}" tee "${AGENT_DIR}/cert.tpl" >/dev/null <<EOF
{{ with secret "${PKI_MOUNT}/issue/${PKI_ROLE}" "common_name=${DOMAIN}" "ttl=5m" }}
{
"certificate": "{{ .Data.certificate }}",
"issuing_ca": "{{ .Data.issuing_ca }}",
"ca_chain": {{ toJSON .Data.ca_chain }},
"private_key": "{{ .Data.private_key }}"
}
{{ end }}
EOF
# ============================
# === 7. Post-Skript ========
# ============================
log "Erstelle Post-Skript (TLS Files + optional Nginx reload)"
sudo -u "${TARGET_USER}" tee "${AGENT_DIR}/bin/vault-agent-post.sh" >/dev/null <<'EOF'
#!/usr/bin/env bash
set -Eeuo pipefail
# APP_NAME aus HOME ableiten (default); bei Bedarf via ENV überschreiben
APP_NAME="${APP_NAME:-$(basename "$HOME")}"
AGENT_DIR="$HOME/.vault-agent-${APP_NAME}"
JSON="$AGENT_DIR/.issue.json"
OUTDIR="$HOME/tls"
echo "[post] Processing $JSON -> $OUTDIR/${APP_NAME}.*"
mkdir -p "$OUTDIR"
umask 077
tmp="$(mktemp -d "$OUTDIR/.staging.XXXX")"
# Private Key extrahieren
jq -r .private_key "$JSON" > "$tmp/${APP_NAME}.key"
# Certificate + CA Chain sauber zusammenbauen (array/string/fallback)
jq -r '
.certificate,
(if (.ca_chain|type=="array") then (.ca_chain|join("\n"))
else if (.ca_chain|type=="string") then .ca_chain
else .issuing_ca end end)
' "$JSON" > "$tmp/${APP_NAME}.fullchain.pem"
# Sicher installieren
install -m 600 "$tmp/${APP_NAME}.key" "$OUTDIR/${APP_NAME}.key"
install -m 644 "$tmp/${APP_NAME}.fullchain.pem" "$OUTDIR/${APP_NAME}.fullchain.pem"
rm -rf "$tmp"
echo "[post] wrote $OUTDIR/${APP_NAME}.key and ${APP_NAME}.fullchain.pem"
# Optional: Nginx reload (ohne sudo). Falls sudo nötig: sudoers-Regel setzen
if systemctl is-active --quiet nginx; then
systemctl reload nginx || true
echo "[post] nginx reloaded"
fi
EOF
sudo -u "${TARGET_USER}" chmod +x "${AGENT_DIR}/bin/vault-agent-post.sh"
# ============================
# === 8. Systemd Service ====
# ============================
log "Erstelle systemd Service-Datei (user)"
sudo -u "${TARGET_USER}" mkdir -p "/home/${TARGET_USER}/.config/systemd/user"
sudo -u "${TARGET_USER}" tee "${SERVICE_FILE}" >/dev/null <<EOF
[Unit]
Description=Vault Agent (${APP_NAME}) - issue & rotate TLS certs
Wants=network-online.target
After=network-online.target
[Service]
Type=simple
WorkingDirectory=${AGENT_DIR}
Environment=VAULT_ADDR=${VAULT_ADDR}
ExecStart=/usr/bin/vault agent -config=${AGENT_DIR}/vault-agent.hcl
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=default.target
EOF
# ============================
# === 9. Start Service =======
# ============================
log "Aktiviere linger für ${TARGET_USER} (User-Services nach Logout)"
loginctl enable-linger "${TARGET_USER}" >/dev/null 2>&1 || true
log "Starte systemd --user Service"
UID="$(id -u "${TARGET_USER}")"
if sudo -u "${TARGET_USER}" XDG_RUNTIME_DIR="/run/user/${UID}" systemctl --user daemon-reload 2>/dev/null; then
sudo -u "${TARGET_USER}" XDG_RUNTIME_DIR="/run/user/${UID}" systemctl --user enable --now "vault-agent-${APP_NAME}.service"
sudo -u "${TARGET_USER}" XDG_RUNTIME_DIR="/run/user/${UID}" systemctl --user status "vault-agent-${APP_NAME}.service" --no-pager || true
else
warn "systemctl --user nicht verfügbar weiche auf systemweiten Service aus"
SYSTEM_SERVICE="/etc/systemd/system/vault-agent-${APP_NAME}.service"
sudo tee "${SYSTEM_SERVICE}" >/dev/null <<EOF
[Unit]
Description=Vault Agent (${APP_NAME}) - system service
Wants=network-online.target
After=network-online.target
[Service]
User=${TARGET_USER}
WorkingDirectory=${AGENT_DIR}
Environment=VAULT_ADDR=${VAULT_ADDR}
ExecStart=/usr/bin/vault agent -config=${AGENT_DIR}/vault-agent.hcl
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
EOF
sudo systemctl daemon-reload
sudo systemctl enable --now "vault-agent-${APP_NAME}.service"
sudo systemctl status "vault-agent-${APP_NAME}.service" --no-pager || true
fi
log "SUCCESS: Vault Agent für ${APP_NAME} eingerichtet!"
echo
echo "TLS files unter: /home/${TARGET_USER}/tls/${APP_NAME}.key / ${APP_NAME}.fullchain.pem"
echo "Agent-Config unter: ${AGENT_DIR}"