VaultTest/vault-bootstrap.sh
Murat ÖZDEMİR bf81b6ebee feat: initialize vault transit auto-unseal documentation and configs
- Added comprehensive step-by-step guide in README.md for Vault Transit auto-unseal setup.
- Included Docker Swarm stack definition (docker-stack-vault.yml).
- Added Vault configuration templates and bootstrap scripts.
- Configured Gitea workflows for the VaultTest environment.
2026-05-27 01:48:30 +03:00

223 lines
11 KiB
Bash
Executable File

#!/bin/bash
# vault-bootstrap.sh — Full Vault HA cluster bootstrap
# iklim-app-03 (transit node + manager) uzerinde calistirilir. SSH gerektirmez.
set -euo pipefail
# ─── Configuration ───────────────────────────────────────────────────
STACK_NAME="iklimco"
STACK_FILE="$(cd "$(dirname "$0")" && pwd)/docker-stack-vault.yml"
TRANSIT_NODE="iklim-app-03"
OUT_DIR="/tmp/vault-bootstrap"
# ─────────────────────────────────────────────────────────────────────
mkdir -p "$OUT_DIR"
TRANSIT_INIT_FILE="$OUT_DIR/transit-init.txt"
MAIN_INIT_FILE="$OUT_DIR/main-vault-init.txt"
AUTOUNSEAL_TOKEN_FILE="$OUT_DIR/autounseal-token.txt"
# ─── Logging ─────────────────────────────────────────────────────────
step() { echo; echo "════════════════════════════════════════════════"; echo " [$(date '+%H:%M:%S')] $*"; echo "════════════════════════════════════════════════"; }
ok() { echo " [OK] $*"; }
info() { echo " --> $*"; }
fail() { echo; echo " [HATA] $*" >&2; exit 1; }
trap 'echo; echo " [HATA] Script satir $LINENO'"'"'de beklenmedik sekilde sonlandi" >&2' ERR
# ─────────────────────────────────────────────────────────────────────
# ─── Helpers ─────────────────────────────────────────────────────────
transit_id() {
docker ps -q -f "name=${STACK_NAME}_vault-transit" | head -1
}
transit_vault() {
local cid
cid=$(transit_id) || fail "Transit container bulunamadi"
[ -n "$cid" ] || fail "Transit container bulunamadi"
docker exec "$cid" sh -c "VAULT_ADDR=http://127.0.0.1:8200 $*"
}
secret_exists() {
docker secret ls --format '{{.Name}}' | grep -q "^$1$"
}
transit_is_sealed() {
! transit_vault "vault status 2>/dev/null" | grep -q "Sealed.*false"
}
wait_service_running() {
local svc="$1" expected="$2" timeout="${3:-180}" elapsed=0
info "Bekleniyor: $svc ($expected running task)..."
while [ "$elapsed" -lt "$timeout" ]; do
running=$(docker service ps "$svc" \
--filter "desired-state=running" \
--format '{{.CurrentState}}' 2>/dev/null \
| grep -c "^Running" || true)
if [ "$running" -ge "$expected" ]; then
ok "$svc hazir: $running/$expected"
return 0
fi
sleep 5; elapsed=$((elapsed+5))
echo " ${elapsed}s/${timeout}s — running: $running/$expected"
done
fail "$svc $timeout saniye icinde hazir olmadi"
}
# ─────────────────────────────────────────────────────────────────────
# ━━━ ADIM 0 — On kosullar ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
step "ADIM 0 — On kosullar kontrol ediliyor"
docker node ls &>/dev/null || fail "Swarm manager node gerekli"
[ -f "$STACK_FILE" ] || fail "Stack dosyasi bulunamadi: $STACK_FILE"
ok "On kosullar tamam"
# ━━━ ADIM 1 — Placeholder secrets ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
step "ADIM 1 — Placeholder secrets olusturuluyor"
if secret_exists vault_transit_unseal_key; then
info "vault_transit_unseal_key zaten var, atlaniyor"
else
echo "bootstrap" | docker secret create vault_transit_unseal_key - >/dev/null
ok "vault_transit_unseal_key olusturuldu"
fi
if secret_exists transit_master_token; then
info "transit_master_token zaten var, atlaniyor"
else
echo "bootstrap" | docker secret create transit_master_token - >/dev/null
ok "transit_master_token olusturuldu"
fi
# ━━━ ADIM 2 — Node label ve stack deploy ━━━━━━━━━━━━━━━━━━━━━━━━━━━
step "ADIM 2 — Transit node etiketleniyor ve stack deploy ediliyor"
docker node update --label-add vault_transit=true "$TRANSIT_NODE" >/dev/null
ok "Node etiketi eklendi: $TRANSIT_NODE"
docker stack deploy --with-registry-auth -c "$STACK_FILE" "$STACK_NAME"
ok "Stack deploy edildi (ana vault node'lari transit hazir olana kadar crash loop'ta — beklenen)"
# ━━━ ADIM 3 — Transit vault initialize ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
step "ADIM 3 — Transit vault bekleniyor ve initialize ediliyor"
wait_service_running "${STACK_NAME}_vault-transit" 1 120
sleep 10
if transit_vault "vault status 2>/dev/null" | grep -q "Initialized.*true"; then
info "Transit zaten initialize edilmis"
[ -f "$TRANSIT_INIT_FILE" ] && grep -q "Initial Root Token" "$TRANSIT_INIT_FILE" \
|| fail "Transit initialize edilmis ama init dosyasi eksik — Unseal Key ve Root Token'i manuel olarak $TRANSIT_INIT_FILE dosyasina kaydedin"
else
info "Transit vault initialize ediliyor..."
rm -f "$TRANSIT_INIT_FILE"
transit_vault "vault operator init -key-shares=1 -key-threshold=1" | tee "$TRANSIT_INIT_FILE"
ok "Transit init tamamlandi — cikti: $TRANSIT_INIT_FILE"
fi
# ━━━ ADIM 4 — Transit unseal ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
step "ADIM 4 — Transit vault unseal ediliyor"
if transit_is_sealed; then
UNSEAL_KEY=$(awk '/Unseal Key 1:/{print $NF}' "$TRANSIT_INIT_FILE")
[ -n "$UNSEAL_KEY" ] || fail "Unseal key '$TRANSIT_INIT_FILE' dosyasinda bulunamadi"
transit_vault "vault operator unseal $UNSEAL_KEY" >/dev/null
ok "Transit unsealed"
else
ok "Transit zaten unsealed"
fi
# ━━━ ADIM 5 — Transit engine kurulumu ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
step "ADIM 5 — Transit secrets engine kuruluyor"
ROOT_TOKEN=$(awk '/Initial Root Token:/{print $NF}' "$TRANSIT_INIT_FILE")
[ -n "$ROOT_TOKEN" ] || fail "Root token '$TRANSIT_INIT_FILE' dosyasinda bulunamadi"
# Policy dosyasini direkt container icine yaz
docker exec "$(transit_id)" sh -c 'cat > /tmp/autounseal-policy.hcl << '"'"'EOF'"'"'
path "transit/encrypt/autounseal" { capabilities = ["update"] }
path "transit/decrypt/autounseal" { capabilities = ["update"] }
EOF'
ok "Policy dosyasi container icine yazildi"
transit_vault "vault login $ROOT_TOKEN" >/dev/null
ok "Transit root login OK"
if transit_vault "vault secrets list 2>/dev/null" | grep -q "^transit/"; then
info "Transit engine zaten etkin, atlaniyor"
else
transit_vault "vault secrets enable transit" >/dev/null
ok "Transit engine etkinlestirildi"
fi
if transit_vault "vault read transit/keys/autounseal 2>/dev/null" | grep -q "autounseal"; then
info "Autounseal key zaten var, atlaniyor"
else
transit_vault "vault write -f transit/keys/autounseal" >/dev/null
ok "Autounseal key olusturuldu"
fi
transit_vault "vault policy write autounseal /tmp/autounseal-policy.hcl" >/dev/null
ok "Autounseal policy yazildi"
info "Autounseal policy token olusturuluyor..."
AUTOUNSEAL_TOKEN=$(transit_vault "vault token create -policy=autounseal -period=768h -orphan -format=json" \
| grep '"client_token"' | awk -F'"' '{print $4}')
[ -n "$AUTOUNSEAL_TOKEN" ] || fail "Autounseal token alinamadi"
echo "$AUTOUNSEAL_TOKEN" > "$AUTOUNSEAL_TOKEN_FILE"
ok "Autounseal token olusturuldu: ${AUTOUNSEAL_TOKEN:0:20}..."
# ━━━ ADIM 6 — Secrets guncelle ━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
step "ADIM 6 — Docker secrets gercek degerlerle guncelleniyor"
UNSEAL_KEY=$(awk '/Unseal Key 1:/{print $NF}' "$TRANSIT_INIT_FILE")
# 6a — vault_transit_unseal_key
info "vault_transit_unseal_key guncelleniyor..."
docker service update --secret-rm vault_transit_unseal_key "${STACK_NAME}_vault-transit" >/dev/null
docker secret rm vault_transit_unseal_key
echo "$UNSEAL_KEY" | docker secret create vault_transit_unseal_key - >/dev/null
docker service update --secret-add vault_transit_unseal_key "${STACK_NAME}_vault-transit" >/dev/null
ok "vault_transit_unseal_key guncellendi"
# 6b — transit auto-unseal dogrula
info "Transit restart sonrasi unseal durumu bekleniyor (15s)..."
sleep 15
if transit_is_sealed; then
info "Transit hala sealed, manuel unseal yapiliyor..."
transit_vault "vault operator unseal $UNSEAL_KEY" >/dev/null
ok "Transit manuel unsealed"
else
ok "Transit auto-unseal basarili"
fi
# 6c — transit_master_token atomic swap (her calistirmada fresh token)
info "transit_master_token atomic swap yapiliyor..."
# Vault servisinde simdi hangi secret transit_master_token olarak mount edilmis?
CURRENT_TOKEN_SECRET=$(docker service inspect "${STACK_NAME}_vault" \
--format '{{range .Spec.TaskTemplate.ContainerSpec.Secrets}}{{if eq .File.Name "transit_master_token"}}{{.SecretName}}{{end}}{{end}}' \
2>/dev/null)
[ -n "$CURRENT_TOKEN_SECRET" ] || CURRENT_TOKEN_SECRET="transit_master_token"
info "Mevcut token secret: $CURRENT_TOKEN_SECRET"
# Her calistirmada benzersiz isimli fresh secret olustur
NEW_TOKEN_SECRET="transit_master_token_$(date +%s)"
echo "$AUTOUNSEAL_TOKEN" | docker secret create "$NEW_TOKEN_SECRET" - >/dev/null
ok "$NEW_TOKEN_SECRET olusturuldu"
# Atomic swap: eski cikart, yenicisi ekle — tek komutta (vault hic token'siz restart olmaz)
docker service update \
--secret-rm "$CURRENT_TOKEN_SECRET" \
--secret-add "source=${NEW_TOKEN_SECRET},target=transit_master_token" \
"${STACK_NAME}_vault" >/dev/null
ok "Atomic swap tamamlandi: $CURRENT_TOKEN_SECRET -> $NEW_TOKEN_SECRET"
# ━━━ ADIM 7 — Ana vault cluster initialize ━━━━━━━━━━━━━━━━━━━━━━━━━
step "ADIM 7 — Ana vault cluster bekleniyor ve initialize ediliyor"
info "Vault node'larinin stabil olmasi bekleniyor..."
wait_service_running "${STACK_NAME}_vault" 3 300
info "Ana vault cluster initialize ediliyor (lokal vault container)..."
LOCAL_VAULT_ID=$(docker ps -q -f "name=${STACK_NAME}_vault\." | head -1)
[ -n "$LOCAL_VAULT_ID" ] || fail "Lokal vault container bulunamadi — vault servisi bu node'da calismiyor olmali"
docker exec "$LOCAL_VAULT_ID" vault operator init | tee "$MAIN_INIT_FILE"
echo
echo "════════════════════════════════════════════════"
echo " BOOTSTRAP TAMAMLANDI"
echo " Transit init : $TRANSIT_INIT_FILE"
echo " Ana vault init: $MAIN_INIT_FILE"
echo " ONEMLI: Bu dosyalari guvenli yere yedekle!"
echo "════════════════════════════════════════════════"