Plugin SDK — secret engines customizados
A partir da v4.5, o CipherVault aceita secret engines customizados
da comunidade sem fork do backend. Implemente em JavaScript/Node.js,
deixe no diretório CV_PLUGINS_DIR, reinicie. File-based discovery
- contrato bem definido.
Casos de uso
- Engine para banco proprietário (Teradata, SAP HANA, Snowflake)
- Engine para sistema interno (LDAP customizado, API de mainframe)
- Engine que combina N steps em um lease (multi-DB, transaction-like)
Configuração
# Backend env var
CV_PLUGINS_DIR=/etc/ciphervault/plugins
CV escaneia o diretório no boot. Cada subdiretório com plugin.json
é tratado como engine.
Estrutura de plugin
/etc/ciphervault/plugins/
└── my-custom-engine/
├── plugin.json
├── index.js
└── package.json (opcional, com deps)
plugin.json
{
"name": "my-custom-engine",
"version": "1.0.0",
"type": "dynamic_secret_engine",
"engine_id": "my_custom",
"description": "Engine para sistema interno X",
"license_min_plan": "professional",
"main": "index.js"
}
index.js
module.exports = {
// Identifier usado em backend.engine
id: 'my_custom',
// Validar config no momento de criar o backend (POST /dynamic-secrets/backends)
validateBackendConfig(config) {
if (!config.host) throw new Error('host obrigatório');
return true;
},
// Testar conectividade (POST /dynamic-secrets/backends/:id/test)
async testConnection(backend) {
// Conecta com creds admin, faz ping
return { ok: true, latency_ms: 42 };
},
// Criar lease (POST /dynamic-secrets/leases)
async createLease({ backend, role, ttl }) {
const username = `cv_${role.name}_${Date.now()}`;
const password = generatePassword();
// Executa o que precisar no sistema externo
await provisionUser(backend, username, password, ttl);
return {
username,
password,
expires_at: new Date(Date.now() + ttl * 1000).toISOString(),
// metadata opcional
metadata: { backend_user_id: 'abc123' },
};
},
// Revogar lease (DELETE /dynamic-secrets/leases/:id ou expiração automática)
async revokeLease({ backend, lease }) {
await deprovisionUser(backend, lease.username);
},
};
Reference plugin
backend/plugins-example/dummy-engine/ no repo do produto é o reference
implementation completo. Use como template — cobre todos os hooks +
testes unitários.
Discovery
# CV log no boot:
[plugin-loader] Found 2 plugins in /etc/ciphervault/plugins
[plugin-loader] Loaded my-custom-engine (engine_id=my_custom)
[plugin-loader] Loaded sap-hana-engine (engine_id=sap_hana)
# Verificar via API
curl https://cv.acme.com.br/dynamic-secrets/engines \
-H "Authorization: Bearer $CV_TOKEN"
# → { "engines": ["postgres", "mysql", ..., "my_custom", "sap_hana"] }
Validação de plugin
Quando você POST cria backend com engine: "my_custom":
- CV verifica se há plugin registrado para
my_custom - Chama
validateBackendConfig(config)do plugin - Persiste backend
testConnectionchamado se?test=truena query
Segurança e isolamento
⚠️ Plugins rodam in-process no backend Node.js. Não há sandbox.
- Confie apenas em plugins auditados. Code review antes de instalar
- NetworkPolicy restritiva — plugin egress só pra hosts esperados
license_min_plannoplugin.jsonhonrado porlib/license.js— plugin pode ser premium-only- Logs sanitizados — não logar valores de secret em código do plugin
Limitações atuais
- JavaScript/Node.js apenas — Go/Python/etc. exigem subprocess wrapper (planejado v5)
- Sem hot reload — adicionar plugin requer restart do backend
- Sem signing/verification do plugin — segurança 100% via filesystem permissions
- Plugin é singleton — uma instância por backend; sem isolamento por tenant
Roadmap
- v5: plugin signing via Sigstore + auto-verification
- v5: hot reload (file watcher)
- v5: WASM runtime para isolamento + linguagem-agnóstico
- v5: plugin registry oficial (
cv plugin install my-org/sap-hana)
Boas práticas
- Versione semver no
plugin.json— facilita debugging - Teste em staging primeiro — plugins têm acesso ao banco interno do CV
- Use
metadatano lease para guardar IDs externos (úteis em revoke) generatePasswordcom 32+ chars[A-Za-z0-9!@#$%^&*]- Idempotência em revoke —
revokeLeasepode ser chamado 2× (reconcile)