CipherVault 1.5 — Self-rotation cloud, attach-secret e demo-app refatorado
Release com rotação self-managed das credenciais que o CipherVault usa para acessar cloud integrations, demo-app transformado em validador multi-suite, enumeration hardening (UUID externo) e melhorias UX/segurança no fluxo Secrets/Fortress. ~20 commits desde 1.4.1.
✨ Novidades
Self-rotation de credenciais — cloud integrations
Padrão "create → test → delete": cria nova cred, valida que funciona, persiste, só então deleta a antiga. Se qualquer etapa antes do persist falhar, a cred atual continua intacta.
| Provider | Mecanismo |
|---|---|
| AWS | IAM Access Keys via @aws-sdk/client-iam |
| GCP | Service Account Keys via IAM REST |
| IBM | IAM API Keys via /v1/apikeys |
- Manual:
POST /cloud-integrations/:id/rotate-credentials+ botão "Rotacionar credenciais" no card - Auto: opt-in via toggle
auto_rotate. Rotação imediata após primeiro sync (queima a cred copy-paste-able) + scheduler 24h com leader lock + retry 1h em failure - UI: badge no card mostra "auto-rotate · próxima DD/MM HH:mm", "rotação falhou" (com tooltip do reason), ou "pendente"
- Schema:
auto_rotate,last_credentials_rotated_at,next_rotation_at,rotation_failed_at,rotation_failure_reasonemcloud_integrations+ index parcial - Auditoria:
integration_credentials_rotated(manual) e_rotated_auto/_rotation_failed(scheduler)
Não suportado (paradigmas diferentes): Azure, OCI, Huawei (lookups distintos / RSA keypairs); PAMs por design (são rotacionadores, não rotacionados).
Vault attach-secret (referência, não cópia)
POST /vaults/:id/attach-secret { secret_id, kind, promote? }
Atribui secret/fortress existente a outro cofre por referência (mesmo id em N cofres). Rotação reflete em todos. Idempotente.
- Validações:
requireVaultAccess('write')no destino +canAccessSecretna origem + env consistency (vault PRD exigepromote=truepra absorver dev) - UI: dialog reutilizável "Adicionar a outro cofre" no card de Secret e Fortress
- Decisão de design: rejeitar duplicação por valor evita rotation drift (dois secrets divergem após uma rotacionar e a outra não)
Custom rotation script (Secrets + Fortress)
Nova platform custom_script no RotationModal com selector de linguagem:
- Shell / Python 3 / JavaScript (Node) / Java (JBang)
Textarea com placeholder contextual por linguagem; variáveis disponíveis:
{{new_password}} no template + $NEW_SECRET no env. Sensor é
responsável pela execução.
users.public_id UUID externo (anti-enumeration)
IDs sequenciais em URL vazam contagem de users. Solução:
- Migration:
users.public_id UUID NOT NULL DEFAULT gen_random_uuid() UNIQUE+ backfill + extensionpgcrypto GET/PUT/DELETE /users/:idaceita ambos os formatos (helperuserIdClausediscrimina por regex v4)- Frontend (
IAMSettings) preferepublic_idem update/delete (fallback pro id int)
Aviso Fortress no SecretForm
Banner violeta no topo do form (modo criação) direciona credenciais críticas
pra Fortress; reposiciona Secrets como "staging para sync com cloud/PAM".
Internal continua disponível como destino válido.
🧪 Demo-app — refatorado completo
Era single-purpose mTLS demo (~220 linhas); agora é validador multi-tab de toda a superfície pública do CipherVault (~1500 linhas):
- 7 suites de smoke test: AppConnection (mTLS+DPoP), Auth (PAT lifecycle), Secrets CRUD, Fortress, Vaults RBAC, Audit + License, OIDC Federation (com mock issuer in-memory)
- OIDC mock issuer: keypair RSA-2048 in-memory, expõe
.well-known/openid-configuration+jwks.json+ endpoint utilitário/issue?sub=.... Auto-setup via PAT cria a cloud_integrationoidc_custom - Trace HTTP por teste: cada teste captura todas as requests com método/URL/status/ms + headers (Authorization sanitizado) + bodies (truncados em 5KB), renderiza em
<details>expansível - Run all: botão na home agrega pass/fail das 7 suites
- Seed: cria 50–100 (configurável) de cada entidade — vaults, secrets, fortress, integrations, app_connections, paths, users
- Cleanup: deleta tudo que o seed criou (match por prefixo
seed-), ordem reversa de FKs - Perf test: spawn N workers concorrentes por D segundos, gera relatório com p50/p95/p99 + latências por quarto da janela + detecção automática de degradação (p95(Q4) > 1.5×p95(Q1) ou error rate > 1%)
🐛 Correções
risk_scores.secret_idFK semON DELETE: bloqueava qualquer DELETE de secret com score (UI inteira). Migrado praON DELETE SET NULL(alinhado comleak_findings)- Demo-app trace interceptor: callback retornava
undefined, fazia testes 200/201 aparecerem como FAIL. Fix: success interceptor agora retornares - OIDC
PROVIDER_NOT_FOUND: setup manual era passo gargalo; agora o teste de Setup auto-cria a cloud_integration via API - Fortress rotate: test referenciava
r.active_versionmas endpoint retornar.new_version— aceita ambos
🧪 Testes
186 cases passando em 17 suites.
Migrations
users.public_id UUID+ index único + extensionpgcryptocloud_integrations.auto_rotate / last_credentials_rotated_at / next_rotation_at / rotation_failed_at / rotation_failure_reason+ partial indexrisk_scores.secret_id_fkeyrecreate comON DELETE SET NULL(DO block idempotente)
Breaking
Nada. Tudo opt-in: auto_rotate default OFF, attach-secret é endpoint novo,
public_id complementa o id sem substituir.