Files
proxmox/scripts/archive/consolidated/deploy/deploy-phoenix-vault-cluster.sh
defiQUG fbda1b4beb
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
docs: Ledger Live integration, contract deploy learnings, NEXT_STEPS updates
- ADD_CHAIN138_TO_LEDGER_LIVE: Ledger form done; public code review repo bis-innovations/LedgerLive; init/push commands
- CONTRACT_DEPLOYMENT_RUNBOOK: Chain 138 gas price 1 gwei, 36-addr check, TransactionMirror workaround
- CONTRACT_*: AddressMapper, MirrorManager deployed 2026-02-12; 36-address on-chain check
- NEXT_STEPS_FOR_YOU: Ledger done; steps completable now (no LAN); run-completable-tasks-from-anywhere
- MASTER_INDEX, OPERATOR_OPTIONAL, SMART_CONTRACTS_INVENTORY_SIMPLE: updates
- LEDGER_BLOCKCHAIN_INTEGRATION_COMPLETE: bis-innovations/LedgerLive reference

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-02-12 15:46:57 -08:00

408 lines
15 KiB
Bash
Executable File

#!/bin/bash
# Deploy Sankofa Phoenix Vault Cluster with Full Redundancy
# Creates 3-node HA Vault cluster on VLAN 160
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
# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'
log_info() { echo -e "${BLUE}[INFO]${NC} $1"; }
log_success() { echo -e "${GREEN}[✓]${NC} $1"; }
log_warn() { echo -e "${YELLOW}[⚠]${NC} $1"; }
log_error() { echo -e "${RED}[✗]${NC} $1"; }
# Configuration
PROXMOX_HOST_1="${PROXMOX_HOST_1:-192.168.11.11}" # r630-01
PROXMOX_HOST_2="${PROXMOX_HOST_2:-192.168.11.12}" # r630-02
VAULT_NODE_1_VMID=8640
VAULT_NODE_2_VMID=8641
VAULT_NODE_3_VMID=8642
VAULT_NODE_1_IP="10.160.0.40"
VAULT_NODE_2_IP="10.160.0.41"
VAULT_NODE_3_IP="10.160.0.42"
VLAN_ID=160
DRY_RUN="${DRY_RUN:-false}"
echo "═══════════════════════════════════════════════════════════"
echo " Sankofa Phoenix Vault Cluster Deployment"
echo "═══════════════════════════════════════════════════════════"
echo ""
log_info "Mode: $([ "$DRY_RUN" = "true" ] && echo "DRY RUN" || echo "LIVE")"
log_info "Cluster: 3-node HA Vault cluster"
log_info "Network: VLAN $VLAN_ID (10.160.0.0/22)"
echo ""
# Function to create container
create_vault_node() {
local vmid=$1
local hostname=$2
local ip=$3
local proxmox_host=$4
local storage="${5:-local-lvm}" # Default storage, can be overridden
log_info "Creating Vault node: $hostname (VMID $vmid)"
if [ "$DRY_RUN" = "true" ]; then
log_info " Would create container on $proxmox_host"
log_info " IP: $ip"
log_info " Hostname: $hostname"
log_info " Storage: $storage"
return 0
fi
# Check if container already exists
if ssh root@"$proxmox_host" "pct list | grep -q '^$vmid'"; then
log_warn "Container $vmid already exists on $proxmox_host"
log_info "Stopping and removing existing container..."
ssh root@"$proxmox_host" "pct stop $vmid 2>/dev/null || true"
ssh root@"$proxmox_host" "pct destroy $vmid 2>/dev/null || true"
sleep 2
fi
ssh root@"$proxmox_host" "pct create $vmid local:vztmpl/ubuntu-22.04-standard_22.04-1_amd64.tar.zst \
--hostname $hostname \
--cores 2 --memory 4096 --swap 2048 \
--storage $storage --rootfs $storage:50 \
--net0 name=eth0,bridge=vmbr0,tag=$VLAN_ID,ip=$ip/22,gw=10.160.0.1 \
--onboot 1 --unprivileged 0 \
--features nesting=1" || {
log_error "Failed to create container $vmid"
return 1
}
log_success "Container $vmid created"
# Start container
log_info "Starting container $vmid..."
ssh root@"$proxmox_host" "pct start $vmid" || {
log_error "Failed to start container $vmid"
return 1
}
# Wait for container to be ready
sleep 5
log_success "Container $vmid started"
return 0
}
# Function to install Vault
install_vault() {
local vmid=$1
local proxmox_host=$2
log_info "Installing Vault on VMID $vmid..."
if [ "$DRY_RUN" = "true" ]; then
log_info " Would install Vault via apt"
return 0
fi
ssh root@"$proxmox_host" "pct exec $vmid -- bash" << 'INSTALL_EOF'
set -e
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y curl unzip wget gnupg software-properties-common jq lsb-release
# Add HashiCorp GPG key
curl -fsSL https://apt.releases.hashicorp.com/gpg | apt-key add -
# Add HashiCorp repository
apt-add-repository "deb [arch=amd64] https://apt.releases.hashicorp.com $(lsb_release -cs) main"
# Install Vault
apt-get update
apt-get install -y vault
# Verify installation
vault version
INSTALL_EOF
log_success "Vault installed on VMID $vmid"
}
# Function to configure Vault node
configure_vault_node() {
local vmid=$1
local node_id=$2
local ip=$3
local proxmox_host=$4
log_info "Configuring Vault node $node_id (VMID $vmid)..."
if [ "$DRY_RUN" = "true" ]; then
log_info " Would create vault.hcl configuration"
return 0
fi
ssh root@"$proxmox_host" "pct exec $vmid -- bash" << CONFIG_EOF
set -e
# Create vault user
useradd --system --home /opt/vault --shell /bin/false vault 2>/dev/null || true
# Create directories
mkdir -p /opt/vault/data
mkdir -p /etc/vault.d
mkdir -p /var/log/vault
chown -R vault:vault /opt/vault
chown -R vault:vault /var/log/vault
# Create vault.hcl
cat > /etc/vault.d/vault.hcl << VAULT_CONFIG
ui = true
disable_mlock = true
listener "tcp" {
address = "0.0.0.0:8200"
cluster_address = "$ip:8201"
tls_disable = 1
}
storage "raft" {
path = "/opt/vault/data"
node_id = "$node_id"
retry_join {
leader_api_addr = "http://10.160.0.40:8200"
}
retry_join {
leader_api_addr = "http://10.160.0.41:8200"
}
retry_join {
leader_api_addr = "http://10.160.0.42:8200"
}
}
api_addr = "http://$ip:8200"
cluster_addr = "http://$ip:8201"
log_level = "INFO"
log_file = "/var/log/vault/vault.log"
log_rotate_duration = "24h"
log_rotate_max_files = 30
VAULT_CONFIG
# Create systemd service
cat > /etc/systemd/system/vault.service << 'SERVICE_EOF'
[Unit]
Description=HashiCorp Vault - A tool for managing secrets
Documentation=https://www.vaultproject.io/docs/
After=network-online.target
Wants=network-online.target
ConditionFileNotEmpty=/etc/vault.d/vault.hcl
[Service]
Type=notify
User=vault
Group=vault
ProtectSystem=full
ProtectHome=read-only
PrivateTmp=yes
PrivateDevices=yes
SecureBits=keep-caps
AmbientCapabilities=CAP_IPC_LOCK
CapabilityBoundingSet=CAP_SYSLOG CAP_IPC_LOCK
NoNewPrivileges=yes
ExecStart=/usr/bin/vault server -config=/etc/vault.d/vault.hcl
ExecReload=/bin/kill --signal HUP \$MAINPID
KillMode=process
Restart=on-failure
RestartSec=5
TimeoutStopSec=30
StartLimitInterval=200
StartLimitBurst=5
LimitNOFILE=65536
LimitMEMLOCK=infinity
[Install]
WantedBy=multi-user.target
SERVICE_EOF
# Enable service
systemctl daemon-reload
systemctl enable vault
CONFIG_EOF
log_success "Vault configured on VMID $vmid"
}
# Phase 1: Create containers
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Phase 1: Creating Containers"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
# Use appropriate storage for each host
# r630-01: local-lvm or thin1
# r630-02: thin3, thin4, thin5, or thin6 (empty pools)
create_vault_node $VAULT_NODE_1_VMID "vault-phoenix-1" $VAULT_NODE_1_IP $PROXMOX_HOST_1 "local-lvm"
create_vault_node $VAULT_NODE_2_VMID "vault-phoenix-2" $VAULT_NODE_2_IP $PROXMOX_HOST_2 "thin3"
create_vault_node $VAULT_NODE_3_VMID "vault-phoenix-3" $VAULT_NODE_3_IP $PROXMOX_HOST_1 "local-lvm"
echo ""
# Phase 2: Install Vault
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Phase 2: Installing Vault"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
install_vault $VAULT_NODE_1_VMID $PROXMOX_HOST_1
install_vault $VAULT_NODE_2_VMID $PROXMOX_HOST_2
install_vault $VAULT_NODE_3_VMID $PROXMOX_HOST_1
echo ""
# Phase 3: Configure Vault
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Phase 3: Configuring Vault Nodes"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
configure_vault_node $VAULT_NODE_1_VMID "vault-phoenix-1" $VAULT_NODE_1_IP $PROXMOX_HOST_1
configure_vault_node $VAULT_NODE_2_VMID "vault-phoenix-2" $VAULT_NODE_2_IP $PROXMOX_HOST_2
configure_vault_node $VAULT_NODE_3_VMID "vault-phoenix-3" $VAULT_NODE_3_IP $PROXMOX_HOST_1
echo ""
# Phase 4: Initialize Cluster
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo "Phase 4: Cluster Initialization"
echo "━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━"
echo ""
if [ "$DRY_RUN" = "true" ]; then
log_warn "DRY RUN - Skipping cluster initialization"
log_info "To initialize cluster, run manually:"
log_info " 1. Start Vault on Node 1: ssh root@$PROXMOX_HOST_1 'pct exec $VAULT_NODE_1_VMID -- systemctl start vault'"
log_info " 2. Initialize: ssh root@$PROXMOX_HOST_1 'pct exec $VAULT_NODE_1_VMID -- vault operator init'"
log_info " 3. Unseal Node 1 with 3 unseal keys"
log_info " 4. Start Vault on Nodes 2 and 3"
log_info " 5. Verify cluster: vault operator raft list-peers"
else
log_info "Starting Vault on Node 1..."
ssh root@"$PROXMOX_HOST_1" "pct exec $VAULT_NODE_1_VMID -- systemctl start vault" || {
log_error "Failed to start Vault on Node 1"
exit 1
}
# Wait for Vault to be ready
log_info "Waiting for Vault to be ready..."
sleep 10
# Check if already initialized
INIT_STATUS=$(ssh root@"$PROXMOX_HOST_1" "pct exec $VAULT_NODE_1_VMID -- vault status -format=json 2>/dev/null | jq -r '.initialized' 2>/dev/null || echo 'false'")
if [ "$INIT_STATUS" = "true" ]; then
log_warn "Vault cluster already initialized"
log_info "To reinitialize, you must first remove existing data"
log_info "Skipping initialization. Use existing unseal keys."
else
log_info "Initializing Vault cluster..."
log_warn "This will generate unseal keys and root token"
log_warn "Save these securely!"
INIT_OUTPUT=$(ssh root@"$PROXMOX_HOST_1" "pct exec $VAULT_NODE_1_VMID -- vault operator init -key-shares=5 -key-threshold=3 -recovery-shares=5 -recovery-threshold=3 -format=json 2>&1")
if echo "$INIT_OUTPUT" | grep -q "error"; then
log_error "Failed to initialize Vault:"
echo "$INIT_OUTPUT"
exit 1
fi
echo "$INIT_OUTPUT" > /tmp/vault-phoenix-init.json
log_success "Initialization complete. Keys saved to /tmp/vault-phoenix-init.json"
log_info "Extracting unseal keys..."
UNSEAL_KEYS=$(echo "$INIT_OUTPUT" | jq -r '.unseal_keys_b64[]' 2>/dev/null || echo "")
ROOT_TOKEN=$(echo "$INIT_OUTPUT" | jq -r '.root_token' 2>/dev/null || echo "")
if [ -z "$UNSEAL_KEYS" ]; then
log_error "Failed to extract unseal keys from initialization output"
log_info "Initialization output:"
echo "$INIT_OUTPUT"
exit 1
fi
log_warn "═══════════════════════════════════════════════════════════"
log_warn " UNSEAL KEYS (SAVE SECURELY):"
log_warn "═══════════════════════════════════════════════════════════"
echo "$UNSEAL_KEYS" | nl -v1
echo ""
log_warn "═══════════════════════════════════════════════════════════"
log_warn " ROOT TOKEN (SAVE SECURELY):"
log_warn "═══════════════════════════════════════════════════════════"
echo "$ROOT_TOKEN"
echo ""
log_info "Unsealing Node 1 (requires 3 keys)..."
KEY1=$(echo "$UNSEAL_KEYS" | sed -n '1p')
KEY2=$(echo "$UNSEAL_KEYS" | sed -n '2p')
KEY3=$(echo "$UNSEAL_KEYS" | sed -n '3p')
ssh root@"$PROXMOX_HOST_1" "pct exec $VAULT_NODE_1_VMID -- vault operator unseal $KEY1" || log_warn "Unseal key 1 may have failed"
ssh root@"$PROXMOX_HOST_1" "pct exec $VAULT_NODE_1_VMID -- vault operator unseal $KEY2" || log_warn "Unseal key 2 may have failed"
ssh root@"$PROXMOX_HOST_1" "pct exec $VAULT_NODE_1_VMID -- vault operator unseal $KEY3" || log_warn "Unseal key 3 may have failed"
# Verify unsealed
sleep 2
SEALED=$(ssh root@"$PROXMOX_HOST_1" "pct exec $VAULT_NODE_1_VMID -- vault status -format=json 2>/dev/null | jq -r '.sealed' 2>/dev/null || echo 'true'")
if [ "$SEALED" = "false" ]; then
log_success "Node 1 unsealed successfully"
else
log_warn "Node 1 may still be sealed. Check manually: vault status"
fi
fi
log_info "Starting Vault on Nodes 2 and 3..."
ssh root@"$PROXMOX_HOST_2" "pct exec $VAULT_NODE_2_VMID -- systemctl start vault" || log_warn "Failed to start Vault on Node 2"
ssh root@"$PROXMOX_HOST_1" "pct exec $VAULT_NODE_3_VMID -- systemctl start vault" || log_warn "Failed to start Vault on Node 3"
sleep 10
log_info "Verifying cluster..."
ssh root@"$PROXMOX_HOST_1" "pct exec $VAULT_NODE_1_VMID -- vault operator raft list-peers 2>/dev/null || echo 'Cluster not ready yet'"
fi
echo ""
echo "═══════════════════════════════════════════════════════════"
echo " Deployment Summary"
echo "═══════════════════════════════════════════════════════════"
echo ""
log_success "Vault Cluster Nodes:"
log_info " Node 1: VMID $VAULT_NODE_1_VMID - $VAULT_NODE_1_IP (vault-phoenix-1)"
log_info " Node 2: VMID $VAULT_NODE_2_VMID - $VAULT_NODE_2_IP (vault-phoenix-2)"
log_info " Node 3: VMID $VAULT_NODE_3_VMID - $VAULT_NODE_3_IP (vault-phoenix-3)"
echo ""
log_info "Next Steps:"
log_info " 1. Verify cluster health: vault status"
log_info " 2. List cluster peers: vault operator raft list-peers"
log_info " 3. Configure authentication methods"
log_info " 4. Create policies and secret paths"
log_info " 5. Update Phoenix services to use new Vault cluster"
if [ "$DRY_RUN" = "false" ] && [ -f "/tmp/vault-phoenix-init.json" ]; then
log_warn "IMPORTANT: Save unseal keys and root token securely!"
log_info "Keys saved to: /tmp/vault-phoenix-init.json"
log_info "Move this file to secure location and delete from /tmp"
fi
echo ""