#!/usr/bin/env bash # Migrate All Discovered Secrets to Admin Vault # Migrates all secrets from MASTER_SECRETS_INVENTORY.md to Sankofa Admin Vault set -euo pipefail # Load IP configuration SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)" source "${PROJECT_ROOT}/config/ip-addresses.conf" 2>/dev/null || true # Configuration VAULT_ADDR="${VAULT_ADDR:-http://${IP_SERVICE_200:-${IP_SERVICE_200:-192.168.11.200}}:8200}" VAULT_TOKEN="${VAULT_TOKEN:-${VAULT_ROOT_TOKEN:-}}" ADMIN_VAULT_PATH="${ADMIN_VAULT_PATH:-secret/data/admin/sankofa-admin}" DRY_RUN="${DRY_RUN:-false}" # Colors for output RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' # No Color # Logging functions log_info() { echo -e "${BLUE}[INFO]${NC} $1" } log_success() { echo -e "${GREEN}[SUCCESS]${NC} $1" } log_warn() { echo -e "${YELLOW}[WARN]${NC} $1" } log_error() { echo -e "${RED}[ERROR]${NC} $1" } # Check prerequisites check_prerequisites() { log_info "Checking prerequisites..." if ! command -v vault &> /dev/null && ! command -v curl &> /dev/null; then log_error "Neither 'vault' CLI nor 'curl' is available. Please install one." exit 1 fi if [ -z "$VAULT_TOKEN" ]; then log_error "VAULT_TOKEN or VAULT_ROOT_TOKEN environment variable is required" exit 1 fi # Test Vault connectivity if command -v vault &> /dev/null; then if ! vault status -address="$VAULT_ADDR" &> /dev/null; then log_warn "Vault CLI cannot connect. Will use curl instead." fi fi log_success "Prerequisites check passed" } # Vault write function (works with both vault CLI and curl) vault_write() { local path="$1" local data="$2" if command -v vault &> /dev/null; then vault write -address="$VAULT_ADDR" "$path" "$data" else # Use curl as fallback curl -s -X POST \ -H "X-Vault-Token: $VAULT_TOKEN" \ -H "Content-Type: application/json" \ -d "$data" \ "$VAULT_ADDR/v1/$path" | jq -r '.errors[]? // empty' fi } # Migrate secrets from inventory migrate_secrets() { log_info "Starting secrets migration to admin vault..." local migrated=0 local failed=0 # 1. Blockchain/Web3 Secrets log_info "Migrating Blockchain/Web3 secrets..." # Private Keys (CRITICAL) migrate_secret "blockchain/private-keys/deployer" \ "0x5373d11ee2cad4ed82b9208526a8c358839cbfe325919fb250f062a25153d1c8" \ "Deployer private key" || ((failed++)) migrate_secret "blockchain/private-keys/237-combo" \ "5e72443d6f357af402859433b115f5b7394786b2624a7cd7e670256a2467bd14" \ "237-combo private key" || ((failed++)) migrate_secret "blockchain/addresses/deployer" \ "0x4A666F96fC8764181194447A7dFdb7d471b301C8" \ "Deployer address" || ((failed++)) # Contract Addresses migrate_secret "blockchain/contracts/link-token" \ "0xb7721dD53A8c629d9f1Ba31a5819AFe250002b03" \ "LINK token address" || ((failed++)) migrate_secret "blockchain/contracts/ccip-router" \ "0x8078A09637e47Fa5Ed34F626046Ea2094a5CDE5e" \ "CCIP router address" || ((failed++)) migrate_secret "blockchain/contracts/token-factory" \ "0xEBFb5C60dE5f7C4baae180CA328D3BB39E1a5133" \ "Token factory address" || ((failed++)) migrate_secret "blockchain/contracts/token-registry" \ "0x91Efe92229dbf7C5B38D422621300956B55870Fa" \ "Token registry address" || ((failed++)) # 2. Cloudflare Secrets log_info "Migrating Cloudflare secrets..." migrate_secret "cloudflare/api-tokens/main" \ "CWNCvhFa0EgXsazoUrJyv1CS-ORoiMmgvM0zm47N" \ "Cloudflare API token" || ((failed++)) migrate_secret "cloudflare/api-keys/proxmox" \ "65d8f07ebb3f0454fdc4e854b6ada13fba0f0" \ "Cloudflare API key (proxmox)" || ((failed++)) migrate_secret "cloudflare/api-keys/loc-az-hci" \ "x2Kgfb7OI8OEu7SUeUSyLIgVFmvXFd6zV_5ZwGcW" \ "Cloudflare API key (loc-az-hci)" || ((failed++)) migrate_secret "cloudflare/tunnel-tokens/main" \ "sRwHkwQO5HfD6aK0ZzdV8XHsAyG_DLe_KCjv2bRP" \ "Cloudflare tunnel token" || ((failed++)) migrate_secret "cloudflare/tunnel-tokens/shared" \ "eyJhIjoiNTJhZDU3YTcxNjcxYzVmYzAwOWVkZjA3NDQ2NTgxOTYiLCJ0IjoiMTBhYjIyZGEtOGVhMy00ZTJlLWE4OTYtMjdlY2UyMjExYTA1IiwicyI6IlptRXlOMkkyTVRrdE1EZzFNeTAwTkRBNExXSXhaalF0Wm1KaE5XVmpaVEEzTVdGbCJ9" \ "Cloudflare shared tunnel token" || ((failed++)) migrate_secret "cloudflare/origin-ca-key" \ "v1.0-e7109fbbe03bfeb201570275-231a7ddf5c59799f68b0a0a73a3e17d72177325bb60e4b2c295896f9fe9c296dc32a5881a7d23859934d508b4f41f1d86408e103012b44b0b057bb857b0168554be4dc215923c043bd" \ "Cloudflare Origin CA key" || ((failed++)) migrate_secret "cloudflare/account-id" \ "52ad57a71671c5fc009edf0744658196" \ "Cloudflare account ID" || ((failed++)) migrate_secret "cloudflare/email" \ "pandoramannli@gmail.com" \ "Cloudflare account email" || ((failed++)) # 3. NPM (Nginx Proxy Manager) Secrets log_info "Migrating NPM secrets..." migrate_secret "npm/passwords/hashed" \ "ce8219e321e1cd97bd590fb792d3caeb7e2e3b94ca7e20124acaf253f911ff72" \ "NPM hashed password" || ((failed++)) migrate_secret "npm/passwords/plain" \ "L@ker\$2010" \ "NPM plain password" || ((failed++)) migrate_secret "npm/email" \ "nsatoshi2007@hotmail.com" \ "NPM admin email" || ((failed++)) # 4. Database Credentials log_info "Migrating database secrets..." # Note: Database URLs should be read from actual .env files if [ -f "dbis_core/.env" ]; then local db_url=$(grep "^DATABASE_URL=" dbis_core/.env | cut -d'=' -f2- | tr -d '"' || echo "") if [ -n "$db_url" ]; then migrate_secret "database/dbis-core/url" \ "$db_url" \ "DBIS Core database URL" || ((failed++)) fi fi # 5. UniFi/Omada Secrets log_info "Migrating UniFi/Omada secrets..." migrate_secret "unifi/api-key" \ "_6WXEiH2tMDkrO3jKc54SKa53fHZE-Wg" \ "UniFi API key" || ((failed++)) migrate_secret "unifi/password" \ "L@kers2010\$\$" \ "UniFi password" || ((failed++)) # Summary log_info "Migration complete" log_success "Successfully migrated: $migrated secrets" if [ $failed -gt 0 ]; then log_warn "Failed to migrate: $failed secrets" fi } # Migrate a single secret migrate_secret() { local secret_path="$1" local secret_value="$2" local description="$3" # Vault KV v2 API path format: secret/data/{mount}/{path} # ADMIN_VAULT_PATH is already in format: secret/data/admin/sankofa-admin local full_path="${ADMIN_VAULT_PATH}/${secret_path}" if [ "$DRY_RUN" = "true" ]; then log_info "[DRY RUN] Would migrate: $full_path" log_info " Description: $description" log_info " Value: ${secret_value:0:20}..." return 0 fi log_info "Migrating: $full_path" # Prepare JSON data local json_data=$(jq -n \ --arg value "$secret_value" \ --arg description "$description" \ --arg migrated_at "$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ '{ data: { value: $value, description: $description, migrated_at: $migrated_at, source: "MASTER_SECRETS_INVENTORY" } }') # Write to Vault if command -v vault &> /dev/null; then if vault write -address="$VAULT_ADDR" "$full_path" \ value="$secret_value" \ description="$description" \ migrated_at="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \ source="MASTER_SECRETS_INVENTORY" 2>/dev/null; then log_success "Migrated: $full_path" ((migrated++)) return 0 else log_error "Failed to migrate: $full_path" return 1 fi else # Use curl local response=$(curl -s -w "\n%{http_code}" -X POST \ -H "X-Vault-Token: $VAULT_TOKEN" \ -H "Content-Type: application/json" \ -d "$json_data" \ "$VAULT_ADDR/v1/$full_path") local http_code=$(echo "$response" | tail -n1) local body=$(echo "$response" | head -n-1) if [ "$http_code" = "200" ] || [ "$http_code" = "204" ]; then log_success "Migrated: $full_path" ((migrated++)) return 0 else log_error "Failed to migrate: $full_path (HTTP $http_code)" echo "$body" | jq -r '.errors[]?' 2>/dev/null || echo "$body" return 1 fi fi } # Main execution main() { log_info "=== Secrets Migration to Admin Vault ===" log_info "Vault Address: $VAULT_ADDR" log_info "Admin Vault Path: $ADMIN_VAULT_PATH" log_info "Dry Run: $DRY_RUN" echo "" check_prerequisites echo "" migrate_secrets echo "" log_success "Migration process completed" } # Run main function main "$@"