Collection of operational skills for VaultMesh infrastructure including: - backup-sovereign: Backup and recovery operations - btc-anchor: Bitcoin anchoring - cloudflare-tunnel-manager: Cloudflare tunnel management - container-registry: Container registry operations - disaster-recovery: Disaster recovery procedures - dns-sovereign: DNS management - eth-anchor: Ethereum anchoring - gitea-bootstrap: Gitea setup and configuration - hetzner-bootstrap: Hetzner server provisioning - merkle-forest: Merkle tree operations - node-hardening: Node security hardening - operator-bootstrap: Operator initialization - proof-verifier: Cryptographic proof verification - rfc3161-anchor: RFC3161 timestamping - secrets-vault: Secrets management 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
166 lines
4.8 KiB
Bash
Executable File
166 lines
4.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
# === METADATA ===
|
|
SCRIPT_NAME="$(basename "$0")"
|
|
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
SKILL_ROOT="$(dirname "$SCRIPT_DIR")"
|
|
|
|
# === CONFIGURATION ===
|
|
: "${OPERATOR_EMAIL:?OPERATOR_EMAIL required}"
|
|
: "${NODE_NAME:=node-a}"
|
|
: "${OUTPUT_DIR:=$SKILL_ROOT/outputs}"
|
|
|
|
# === FUNCTIONS ===
|
|
log_info() { echo "[INFO] $(date -Iseconds) $*"; }
|
|
log_warn() { echo "[WARN] $(date -Iseconds) $*" >&2; }
|
|
log_error() { echo "[ERROR] $(date -Iseconds) $*" >&2; }
|
|
|
|
preflight() {
|
|
[[ -d "$OUTPUT_DIR" ]] || mkdir -p "$OUTPUT_DIR"
|
|
}
|
|
|
|
guide_pass_init() {
|
|
echo ""
|
|
echo "============================================"
|
|
echo " SECRETS ENROLLMENT - GUIDED SETUP"
|
|
echo " This is an INTERACTIVE process"
|
|
echo "============================================"
|
|
echo ""
|
|
|
|
# Check if pass is already initialized
|
|
if [[ -d "$HOME/.password-store" ]] && [[ -f "$HOME/.password-store/.gpg-id" ]]; then
|
|
log_info "Pass store already initialized"
|
|
local existing_gpg
|
|
existing_gpg=$(cat "$HOME/.password-store/.gpg-id")
|
|
echo " Current GPG ID: $existing_gpg"
|
|
echo ""
|
|
read -p "Re-initialize with $OPERATOR_EMAIL? (y/N): " reinit
|
|
if [[ "$reinit" != "y" && "$reinit" != "Y" ]]; then
|
|
log_info "Keeping existing pass store"
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
echo "=== Step 1: Initialize Pass Store ==="
|
|
echo ""
|
|
echo "Run the following command to initialize pass with your GPG key:"
|
|
echo ""
|
|
echo " pass init \"$OPERATOR_EMAIL\""
|
|
echo ""
|
|
read -p "Press Enter when you have completed this step..."
|
|
|
|
# Verify
|
|
if [[ ! -d "$HOME/.password-store" ]]; then
|
|
log_warn "Pass store not detected at ~/.password-store"
|
|
log_warn "Please verify initialization before continuing"
|
|
else
|
|
log_info "Pass store detected at $HOME/.password-store"
|
|
fi
|
|
}
|
|
|
|
guide_structure_creation() {
|
|
echo ""
|
|
echo "=== Step 2: Create Password Structure ==="
|
|
echo ""
|
|
echo "Create the following password hierarchy for infrastructure secrets:"
|
|
echo ""
|
|
echo " infrastructure/"
|
|
echo " +-- cloudflare/"
|
|
echo " | +-- api-token"
|
|
echo " | +-- tunnel-secret"
|
|
echo " +-- ssh/"
|
|
echo " | +-- passphrase"
|
|
echo " +-- services/"
|
|
echo " +-- (future services)"
|
|
echo ""
|
|
echo "Commands to run (replace with your actual secrets):"
|
|
echo ""
|
|
echo " pass insert infrastructure/cloudflare/api-token"
|
|
echo " pass insert infrastructure/cloudflare/tunnel-secret"
|
|
echo ""
|
|
echo "Note: You'll be prompted to enter each secret value."
|
|
echo ""
|
|
read -p "Press Enter when you have stored the critical secrets..."
|
|
}
|
|
|
|
guide_verify() {
|
|
echo ""
|
|
echo "=== Step 3: Verify Encryption/Decryption ==="
|
|
echo ""
|
|
echo "Test that you can retrieve a secret:"
|
|
echo ""
|
|
echo " pass infrastructure/cloudflare/api-token"
|
|
echo ""
|
|
echo "This should display your API token (confirm it matches what you entered)."
|
|
echo ""
|
|
read -p "Press Enter when you have verified decryption works..."
|
|
|
|
# Attempt to list pass contents
|
|
if command -v pass &>/dev/null; then
|
|
echo ""
|
|
echo "=== Current Pass Store Contents ==="
|
|
pass ls 2>/dev/null || log_warn "Could not list pass store"
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
guide_git_init() {
|
|
echo ""
|
|
echo "=== Step 4: Initialize Git for Pass Store (Optional) ==="
|
|
echo ""
|
|
echo "For version control of your encrypted passwords:"
|
|
echo ""
|
|
echo " pass git init"
|
|
echo ""
|
|
echo "This enables automatic commits when passwords change."
|
|
echo ""
|
|
read -p "Press Enter to continue (skip if you prefer not to use git)..."
|
|
}
|
|
|
|
generate_manifest() {
|
|
local manifest="$OUTPUT_DIR/secrets_manifest.json"
|
|
|
|
cat > "$manifest" <<EOF
|
|
{
|
|
"timestamp": "$(date -Iseconds)",
|
|
"node": "$NODE_NAME",
|
|
"pass_store": "$HOME/.password-store",
|
|
"gpg_id": "$OPERATOR_EMAIL",
|
|
"guided_enrollment": true,
|
|
"structure": [
|
|
"infrastructure/cloudflare/api-token",
|
|
"infrastructure/cloudflare/tunnel-secret",
|
|
"infrastructure/ssh/passphrase",
|
|
"infrastructure/services/"
|
|
],
|
|
"note": "Secrets are encrypted with GPG. Never store this manifest with actual secret values."
|
|
}
|
|
EOF
|
|
log_info "Secrets manifest written to $manifest"
|
|
}
|
|
|
|
main() {
|
|
preflight
|
|
log_info "Starting $SCRIPT_NAME (INTERACTIVE GUIDED SETUP)..."
|
|
|
|
guide_pass_init
|
|
guide_structure_creation
|
|
guide_verify
|
|
guide_git_init
|
|
generate_manifest
|
|
|
|
echo ""
|
|
echo "============================================"
|
|
echo " SECRETS ENROLLMENT COMPLETE"
|
|
echo "============================================"
|
|
echo ""
|
|
echo "Your pass store is now configured."
|
|
echo "Secrets are encrypted with your GPG key: $OPERATOR_EMAIL"
|
|
echo ""
|
|
|
|
log_info "Completed $SCRIPT_NAME"
|
|
}
|
|
|
|
[[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@"
|