diff --git a/scripts/bootstrap/bootstrap-local.sh b/scripts/bootstrap/bootstrap-local.sh index 2da566d7f..75b311ad1 100755 --- a/scripts/bootstrap/bootstrap-local.sh +++ b/scripts/bootstrap/bootstrap-local.sh @@ -51,6 +51,89 @@ VAULT_PASS="$REPO_ROOT/infra/ansible/.vault-pass" TALAS_STATE_DIR="$REPO_ROOT/.git/talas-bootstrap" TALAS_STATE_FILE="$TALAS_STATE_DIR/local.state" +# ============================================================================ +# Vault autofill helpers (used by phase 2) +# ============================================================================ + +# Generate a URL-safe random string (no /=+ which break sed and yaml). +_rand_token() { + local len=${1:-32} + openssl rand -base64 $((len * 2)) 2>/dev/null | tr -dc 'A-Za-z0-9' | head -c "$len" +} + +# Replace a single `vault_: ""` line with a generated value. +# Idempotent : if the line is already non-TODO, no-op. +_autofill_field() { + local file=$1 key=$2 value=$3 + # Escape sed delimiters in value (we use | as delimiter, so escape any |) + local esc=${value//|/\\|} + sed -i "s|^${key}: \". +_autogen_jwt_keys() { + local file=$1 + if ! grep -q '' "$file"; then + return 0 + fi + info "generating RS256 JWT keypair" + local priv pub + priv=$(openssl genrsa 4096 2>/dev/null) || die "openssl genrsa failed" + pub=$(echo "$priv" | openssl rsa -pubout 2>/dev/null) || die "openssl rsa -pubout failed" + local priv_b64 pub_b64 + priv_b64=$(echo "$priv" | base64 -w0) + pub_b64=$(echo "$pub" | base64 -w0) + _autofill_field "$file" vault_jwt_signing_key_b64 "$priv_b64" + _autofill_field "$file" vault_jwt_public_key_b64 "$pub_b64" + ok "JWT keys generated and inserted" +} + +# Autofill all the vault fields whose value can be safely random-generated. +# Optional / external fields (smtp, hyperswitch, stripe, oauth_clients, +# sentry) are left as for the operator to either fill or skip. +_autofill_vault_secrets() { + local file=$1 + local filled=() + + # Strong passwords (32 alphanumeric chars). + local pw_fields=( + vault_postgres_password + vault_postgres_replication_password + vault_redis_password + vault_rabbitmq_password + vault_minio_root_password + vault_chat_jwt_secret + vault_oauth_encryption_key + vault_stream_internal_api_key + ) + for k in "${pw_fields[@]}"; do + if grep -q "^${k}: \" 0 )); then + ok "auto-generated ${#filled[@]} secret(s) : ${filled[*]}" + fi +} + # ============================================================================ # Phase 1 — preflight # ============================================================================ @@ -113,28 +196,32 @@ phase_2_vault() { if [[ -f "$VAULT_YML" ]] && head -1 "$VAULT_YML" 2>/dev/null | grep -q '^\$ANSIBLE_VAULT'; then info "vault.yml already encrypted — verifying password works" [[ -f "$VAULT_PASS" ]] || die "vault.yml encrypted but $VAULT_PASS missing — re-create it manually" - elif [[ -f "$VAULT_YML" ]]; then - warn "vault.yml exists in PLAINTEXT — will encrypt now" else - info "rendering vault.yml from example" - cp "$VAULT_EXAMPLE" "$VAULT_YML" - warn "edit $VAULT_YML now to fill in placeholders" - warn "(JWT keys are auto-generated below if you leave their values)" - prompt_value _ "Press Enter when done editing" - # Auto-fill JWT keys if user left the TODO placeholders - if grep -q '' "$VAULT_YML"; then - info "generating RS256 JWT keypair" - local jwt_priv jwt_pub - jwt_priv=$(openssl genrsa 4096 2>/dev/null | base64 -w0) - jwt_pub=$(echo "$jwt_priv" | base64 -d | openssl rsa -pubout 2>/dev/null | base64 -w0) - sed -i "s||$jwt_priv|" "$VAULT_YML" - sed -i "s||$jwt_pub|" "$VAULT_YML" - ok "JWT keys generated and inserted" + if [[ -f "$VAULT_YML" ]]; then + warn "vault.yml exists in PLAINTEXT — will autofill remaining + encrypt" + else + info "rendering vault.yml from example" + cp "$VAULT_EXAMPLE" "$VAULT_YML" fi - if grep -qE ' placeholders still in $VAULT_YML — fill them and rerun PHASE=2 ./bootstrap-local.sh" + + _autogen_jwt_keys "$VAULT_YML" + _autofill_vault_secrets "$VAULT_YML" + + local remaining + remaining=$(grep -cE ' 0 )); then + warn "$remaining placeholders left (optional fields ; safe to leave or fill later)" + grep -n '&2 + local cont + prompt_value cont "blank these out and continue ? (y/n)" "y" + if [[ "${cont,,}" == "y" ]]; then + # Replace any line whose value still has