CuanDeOro
Vault Migration · Plan ejecutable

Plan ejecutable · Vault migration · 7 días sin downtime

FASE 1-2 ejecutadas y verificadas contra estado real · FASE 3-5 checklist con comandos exactos + rollback

FASE 1 · Validación de hallazgos (ejecutada)

F-02
Keypair Solana hardcoded en bridge.mjs
grep -n 'KEYPAIR' /srv/cuandeoro_bridge/bridge.mjs
Línea 10: const KEYPAIR_PATH = '/home/administrator/.velocityquant_secrets/dallas_hot_keypair.json';
Líneas 16-17: fs.readFileSync(KEYPAIR_PATH) → Keypair.fromSecretKey(...)
Archivo existe (227 bytes, mode 600, owner administrator).
Verificado
F-03
Seed BIP-39 deployer en TOML
grep -n 'TOML\|seed' /srv/cuandeoro_bridge/finish.mjs
Línea 11: const TOML_PATH = '/home/administrator/.velocityquant_secrets/cuandeoro_deployer_mainnet.toml';
Líneas 25-28: lee TOML, regex seed_phrase = "...", deriva con StellarHDWallet.fromMnemonic().
Mismo patrón en open_trustline.mjs:7. Archivo TOML existe (179 bytes, mode 600).
Además: cat .velocityquant_secrets/cuandeoro_deployer_mainnet.toml revela seed plaintext "dragon burden enemy skin...".
Verificado
F-08
Soroban admin sin time-lock/multisig
grep -n 'upgrade\|update_current_contract_wasm' /srv/cuandeoro_soroban/contracts/cuandeoro-atomic/src/lib.rs0 matches.
El contrato NO tiene función upgrade, NO usa env.deployer().update_current_contract_wasm(), NO tiene set_admin.
Admin solo puede: bloquear países (RTO-1), marcar notarial verification, NO puede reemplazar el contrato.
Línea 100 comenta: "multisig Cuandeoro (Marco + Fran + abogado)" — el admin Address SE ESPERA sea un contrato multisig externo (Soroban admite Address ser contrato).
El riesgo descrito por el modelo ("upgrade malicioso instantáneo") NO APLICA porque no hay upgrade function. El riesgo residual es: si admin key se compromete, atacante puede bloquear países o marcar notarial — operacional, no drenaje.
Falso positivo
F-09
KYC sin audit log de lecturas
cat /srv/cuandeoro_kyc/schema.sql
Tabla kyc_audit_log EXISTE (líneas 71-83) pero solo registra operaciones: 'create', 'update', 'revoke', 'rotate_dek', 'gdpr_purge'.
NO existe trigger AFTER SELECT, NO existe wrapper de lectura, NO se hace REVOKE SELECT sobre kyc_records.
Atacante con grant SELECT puede ejecutar SELECT * FROM kyc_records y exfiltrar PII cifrado sin rastro en audit log.
Verificado
F-10
gdpr_purge_kyc_record editable
cat /srv/cuandeoro_kyc/schema.sql
Función definida línea 102 con CREATE OR REPLACE FUNCTION ... LANGUAGE plpgsql;
NO declara SECURITY DEFINER → ejecuta con permisos del invocador (SECURITY INVOKER por defecto).
NO hay REVOKE ni GRANT EXECUTE explícito en el schema → cualquier role con CREATE FUNCTION puede ejecutar CREATE OR REPLACE y modificarla.
El INSERT al audit log es eliminable modificando la función.
Verificado
Resultado FASE 1: 4/5 VERIFICADOS · 1/5 FALSO POSITIVO (F-08). El plan se enfoca solo en los 4 verificados + secretos descubiertos en FASE 2.

FASE 2 · Inventario de secretos (ejecutado)

SecretoUbicaciónUsado porRiesgoVault
dallas_hot_keypair.json~/.velocityquant_secrets/cuandeoro_bridge/bridge.mjs:10HOT wallet Solana operativo · 2.2 SOL + 302 USDC
cuandeoro_deployer_mainnet.toml~/.velocityquant_secrets/finish.mjs:11 + open_trustline.mjs:7Seed BIP-39 Stellar deployer · control wallet GBL4...HVVA
rosalba_admin_key1.toml~/.velocityquant_secrets/ + ~/.config/stellar/identity/Multisig Cuandeoro admin (Soroban)Seed multisig admin 1/3
rosalba_admin_key2.toml~/.velocityquant_secrets/ + ~/.config/stellar/identity/Multisig Cuandeoro admin (Soroban)Seed multisig admin 2/3
rosalba_admin_key3.toml~/.velocityquant_secrets/ + ~/.config/stellar/identity/Multisig Cuandeoro admin (Soroban)Seed multisig admin 3/3
master_rotated_20260511.json~/.velocityquant_secrets/VelocityQuant treasury (cold)2.84 SOL + 1310 USDC + 1119 USDTCOLD
hot200_keypair.json~/.velocityquant_secrets/VelocityQuant legacy (DRAINED)0 SOL + 0 USDC (vacío)descartable
keypair_5bbEM626.json~/.config/solana_keypairs/R195 ephemeral wallet (terminada)0.02 SOL + 81 USDC (PnL session)archivable
keypair_r211_burnin_H93R4b4F.json~/.config/solana_keypairs/R211 burn-in v2 (pendiente)0.05 SOL + 80 USDC (pre-fondeo)
audit_dashboard_shared_secret.txt~/.velocityquant_secrets/Audit dashboard HMACCompromiso → forge auth tokens
coinglass.env (COINGLASS_API_KEY)~/.velocityquant_secrets/VelocityQuant botsAPI rate quota abuse
pumpdump.env (PUMPDUMP_API_KEY)~/.velocityquant_secrets/VelocityQuant botsAPI quota abuse
ARCHIVOS_USER + ARCHIVOS_PASS/srv/archivos_cuandeoro/.envarchivos_cuandeoro/server.pyAcceso al servicio archivos · viola R90-KMS
internal_ledger.json~/.velocityquant_secrets/VelocityQuant accountingBalances internos · no secreto críticoqueda local
musculo.env.aws_backup~/.velocityquant_secrets/AWS legacy (instancias stopped)Backup histórico, sin usodescartable
Vault HashiCorp comprobado: VAULT_ADDR=http://127.0.0.1:8200 vault status → Initialized=true, Sealed=false, Shamir 5/3, Storage=raft, HA active. Listo para alojar la estructura nueva.

FASE 3 · Estructura Vault (comandos ejecutar como root)

Requisito: necesitas VAULT_TOKEN con permisos sys/mounts y sys/policies. Si tienes root token de la ceremonia, úsalo aquí (temporal, no exportar a env permanente).

3.1 · Habilitar KV v2 montado en cuandeoro/

export VAULT_ADDR=http://127.0.0.1:8200
read -rs -p "VAULT_TOKEN root: " VAULT_TOKEN; export VAULT_TOKEN; echo
vault secrets enable -path=cuandeoro -version=2 kv
vault secrets list | grep cuandeoro
Rollback: vault secrets disable cuandeoro (los datos quedan en raft hasta GC, pero quedan inaccesibles via mount).

3.2 · Crear estructura jerárquica (paths vacíos)

vault kv put cuandeoro/stellar/deployer placeholder=init
vault kv put cuandeoro/stellar/rosalba_admin_1 placeholder=init
vault kv put cuandeoro/stellar/rosalba_admin_2 placeholder=init
vault kv put cuandeoro/stellar/rosalba_admin_3 placeholder=init
vault kv put cuandeoro/solana/dallas_hot placeholder=init
vault kv put cuandeoro/solana/r211_burnin placeholder=init
vault kv put cuandeoro/smtp/cuandeoro_ie placeholder=init
vault kv put cuandeoro/cloudflare/api_token placeholder=init
vault kv put cuandeoro/postgres/kyc_app placeholder=init
vault kv put cuandeoro/postgres/kyc_auditor placeholder=init
vault kv put cuandeoro/services/archivos_pass placeholder=init
vault kv put cuandeoro/services/audit_dashboard_hmac placeholder=init
vault kv put cuandeoro/services/coinglass_api placeholder=init
vault kv put cuandeoro/services/pumpdump_api placeholder=init

3.3 · Políticas mínimo privilegio (lectura solo, por servicio)

# Política bridge: solo lee dallas_hot + deployer
cat <<EOF | vault policy write cuandeoro-bridge -
path "cuandeoro/data/solana/dallas_hot"   { capabilities = ["read"] }
path "cuandeoro/data/stellar/deployer"    { capabilities = ["read"] }
path "cuandeoro/metadata/solana/dallas_hot" { capabilities = ["read"] }
path "cuandeoro/metadata/stellar/deployer"  { capabilities = ["read"] }
EOF

# Política archivos: solo password propio
cat <<EOF | vault policy write cuandeoro-archivos -
path "cuandeoro/data/services/archivos_pass" { capabilities = ["read"] }
EOF

# Política kyc-app: lee credencial app + función SECURITY DEFINER hace el log
cat <<EOF | vault policy write cuandeoro-kyc-app -
path "cuandeoro/data/postgres/kyc_app" { capabilities = ["read"] }
EOF

# Política admin (solo Marco) - lectura total
cat <<EOF | vault policy write cuandeoro-admin -
path "cuandeoro/*" { capabilities = ["create","read","update","delete","list"] }
EOF

vault policy list | grep cuandeoro

3.4 · AppRoles por servicio (token rotables)

vault auth enable -path=approle approle 2>/dev/null || echo "approle ya montado"

# Bridge
vault write auth/approle/role/cuandeoro-bridge \
    token_policies="cuandeoro-bridge" token_ttl=4h token_max_ttl=24h \
    secret_id_ttl=720h

# Archivos
vault write auth/approle/role/cuandeoro-archivos \
    token_policies="cuandeoro-archivos" token_ttl=4h token_max_ttl=24h

# KYC app
vault write auth/approle/role/cuandeoro-kyc-app \
    token_policies="cuandeoro-kyc-app" token_ttl=4h token_max_ttl=24h
Rollback FASE 3: vault policy delete cuandeoro-{bridge,archivos,kyc-app,admin} + vault auth disable approle (si fue creado aquí) + vault secrets disable cuandeoro.

FASE 4 · Migración segura (POR SECRETO con rollback)

Regla absoluta: en ningún caso eliminar el archivo plaintext hasta haber validado el servicio leyendo desde Vault y mantenerlo funcionando >1h sin errores. shred solo en FASE 5.

S-01 · ARCHIVOS_PASS (más simple, hacer primero para validar pipeline)

Rollback S-01: sudo cp /srv/archivos_cuandeoro/.env.bak-XXX /srv/archivos_cuandeoro/.env + reiniciar servicio. Tiempo: 30 segundos.

S-02 · dallas_hot_keypair.json (Solana bridge)

Rollback S-02: cp /srv/cuandeoro_bridge/bridge.mjs.bak-XXX /srv/cuandeoro_bridge/bridge.mjs. El archivo plaintext sigue intacto (Vault es copia adicional, no reemplazo aún).

S-03 · cuandeoro_deployer_mainnet.toml (Stellar seed)

Rollback S-03: restaurar finish.mjs y open_trustline.mjs desde backup. TOML sigue intacto (no se borra hasta FASE 5).

S-04 · rosalba_admin_key{1,2,3}.toml (multisig Soroban admin)

Rollback S-04: ninguno necesario, no se modifica código. Las keys se quedan accesibles ambos lados.

S-05 · master_rotated_20260511.json (cold treasury VelocityQuant)

N/A · decisión scope

S-06 · audit_dashboard_shared_secret + 2 API keys (coinglass, pumpdump)

FASE 5 · Retirada controlada (solo si todo FASE 4 OK >48h)

Pre-requisito: 48 horas sin errores en logs · bridge.mjs ejecutó al menos 1 tx real desde Vault · archivos_cuandeoro ha tenido al menos 1 login con la nueva password. Si NO se cumple → NO ejecutar FASE 5.
Rollback FASE 5 si algo falla: sudo tar -xzf /sda-disk/cuandeoro_secrets_pre_purge_*.tgz -C / restaura todos los plaintext. La tarball NUNCA se borra.

Resumen estado de hallazgos no cubiertos por este plan

HallazgoEstadoAcción
F-08 Soroban admin time-lockFalso positivo (verificado)Ninguna · no hay función upgrade en el contrato
F-09 KYC sin audit log lecturaVerificadoSesión SQL separada · qwen-coder genera kyc_read() SECURITY DEFINER + REVOKE SELECT
F-10 gdpr_purge editableVerificadoSesión SQL separada · ALTER OWNER + REVOKE ALTER + SECURITY DEFINER
Resumen final del plan: 4 hallazgos verificados → 6 migraciones de secretos (S-01 a S-06) → retirada en FASE 5. Tiempo estimado 7 días si haces 1 migración/día con validación 24h cada una. Cada paso es reversible hasta FASE 5. F-09 y F-10 son SQL puro y los abordamos en sesión separada con qwen-coder.