Files
vm-skills/operator-bootstrap/scripts/02_identity_apply.sh
Vault Sovereign eac77ef7b4 Initial commit: VaultMesh Skills collection
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>
2025-12-27 00:25:00 +00:00

156 lines
4.0 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_NAME:?OPERATOR_NAME required}"
: "${OPERATOR_EMAIL:?OPERATOR_EMAIL required}"
: "${NODE_NAME:=node-a}"
: "${SSH_KEY_COMMENT:=$NODE_NAME-operator}"
: "${GPG_KEY_SIZE:=4096}"
: "${GPG_KEY_EXPIRE:=2y}"
: "${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; }
die() { log_error "$@"; exit 1; }
preflight() {
[[ -d "$OUTPUT_DIR" ]] || mkdir -p "$OUTPUT_DIR"
[[ -d "$HOME/.ssh" ]] || { mkdir -p "$HOME/.ssh" && chmod 700 "$HOME/.ssh"; }
}
create_gpg_key() {
if gpg --list-keys "$OPERATOR_EMAIL" &>/dev/null 2>&1; then
log_info "GPG key for $OPERATOR_EMAIL already exists - skipping"
return 0
fi
log_info "Generating GPG key (you will be prompted for passphrase)..."
# Create key generation parameters
local params_file
params_file=$(mktemp)
cat > "$params_file" <<EOF
%echo Generating GPG key for $OPERATOR_NAME
Key-Type: RSA
Key-Length: $GPG_KEY_SIZE
Subkey-Type: RSA
Subkey-Length: $GPG_KEY_SIZE
Name-Real: $OPERATOR_NAME
Name-Email: $OPERATOR_EMAIL
Expire-Date: $GPG_KEY_EXPIRE
%ask-passphrase
%commit
%echo Done
EOF
gpg --batch --gen-key "$params_file"
rm -f "$params_file"
log_info "GPG key created for $OPERATOR_EMAIL"
}
create_ssh_keys() {
local ed_key="$HOME/.ssh/id_ed25519_${NODE_NAME}"
local rsa_key="$HOME/.ssh/id_rsa_${NODE_NAME}"
# Ed25519 key
if [[ -f "$ed_key" ]]; then
log_info "Ed25519 key already exists at $ed_key - skipping"
else
log_info "Generating Ed25519 SSH key..."
ssh-keygen -t ed25519 -f "$ed_key" -C "$SSH_KEY_COMMENT" -N ""
log_info "Ed25519 key created: $ed_key"
fi
# RSA fallback key
if [[ -f "$rsa_key" ]]; then
log_info "RSA key already exists at $rsa_key - skipping"
else
log_info "Generating RSA fallback SSH key..."
ssh-keygen -t rsa -b 4096 -f "$rsa_key" -C "$SSH_KEY_COMMENT-rsa" -N ""
log_info "RSA key created: $rsa_key"
fi
}
update_ssh_config() {
local config="$HOME/.ssh/config"
local backup="$HOME/.ssh/config.bak.$(date +%Y%m%d%H%M%S)"
# Create config if it doesn't exist
if [[ ! -f "$config" ]]; then
touch "$config"
chmod 600 "$config"
fi
# Backup existing config
cp "$config" "$backup"
log_info "SSH config backed up to $backup"
# Check if entry already exists
if grep -q "Host $NODE_NAME\$" "$config" 2>/dev/null; then
log_info "SSH config entry for $NODE_NAME already exists - skipping"
return 0
fi
# Append new entry
cat >> "$config" <<EOF
# Added by operator-bootstrap $(date -Iseconds)
Host $NODE_NAME
IdentityFile ~/.ssh/id_ed25519_${NODE_NAME}
IdentitiesOnly yes
EOF
chmod 600 "$config"
log_info "SSH config updated with $NODE_NAME entry"
}
generate_manifest() {
local manifest="$OUTPUT_DIR/identity_manifest.json"
local gpg_fingerprint
gpg_fingerprint=$(gpg --list-keys --with-colons "$OPERATOR_EMAIL" 2>/dev/null | grep fpr | head -1 | cut -d: -f10 || echo "unknown")
cat > "$manifest" <<EOF
{
"timestamp": "$(date -Iseconds)",
"node": "$NODE_NAME",
"operator": {
"name": "$OPERATOR_NAME",
"email": "$OPERATOR_EMAIL"
},
"gpg": {
"fingerprint": "$gpg_fingerprint",
"key_size": $GPG_KEY_SIZE,
"expires": "$GPG_KEY_EXPIRE"
},
"ssh": {
"ed25519": "$HOME/.ssh/id_ed25519_${NODE_NAME}",
"rsa": "$HOME/.ssh/id_rsa_${NODE_NAME}"
}
}
EOF
log_info "Identity manifest written to $manifest"
}
main() {
preflight
log_info "Starting $SCRIPT_NAME..."
create_gpg_key
create_ssh_keys
update_ssh_config
generate_manifest
log_info "Completed $SCRIPT_NAME"
}
[[ "${BASH_SOURCE[0]}" == "$0" ]] && main "$@"