External Secrets Operator (ESO) compat layer
A partir da v4.5, o CipherVault expõe endpoints compatíveis com o External Secrets Operator (ESO) usando o Webhook provider. Isso permite quem já usa ESO em produção adotar CipherVault sem trocar de operator.
Se você está começando do zero em K8s, prefira o Kubernetes Operator nativo ou o Guardian — funcionalidades mais ricas. O ESO compat é para migração suave.
Endpoints
GET /eso/secrets/by-id?id=<secret_id> Por UUID
GET /eso/secrets/by-name?vault=<v>&name=<n> Por nome
GET /eso/vault/<vault_name> Listagem de secrets do vault
Auth via mTLS + DPoP (AppConnection padrão).
Setup — ESO SecretStore (Webhook)
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: ciphervault
namespace: billing
spec:
provider:
webhook:
url: "https://cv.acme.com.br/eso/secrets/by-name?vault=producao&name={{ .remoteRef.key }}"
headers:
X-Client-Id: "{{ .clientCreds.client_id }}"
secrets:
- name: clientCreds
secretRef:
name: cv-app-credentials
result:
jsonPath: "$.value"
caBundle: <PEM da CA do CV>
ExternalSecret
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: stripe-key
namespace: billing
spec:
refreshInterval: 5m
secretStoreRef:
name: ciphervault
kind: SecretStore
target:
name: stripe-credentials
type: Opaque
data:
- secretKey: STRIPE_KEY
remoteRef:
key: api/stripe/secret_key
Result: ESO cria K8s Secret stripe-credentials no namespace
billing, populado do CV, atualizado a cada 5min.
Response format
Endpoint retorna JSON simples:
{
"id": "sec_01HXY...",
"name": "secret_key",
"vault": "producao",
"path": "api/stripe/secret_key",
"type": "api_key",
"value": "sk_live_...",
"version": 7,
"updated_at": "2026-05-12T13:00:00Z"
}
ESO extrai $.value via jsonPath configurado no SecretStore.
Auth via AppConnection
ESO conecta com X-Client-Id + X-Client-Secret no header. Para
mTLS (recomendado), configure ESO com caBundle + cert do client:
spec:
provider:
webhook:
url: "https://cv.acme.com.br/eso/secrets/by-name?..."
tlsConfig:
caCert: ...
clientCert: ...
clientKey: ...
Diferenças vs. Operator nativo
| Capability | ESO compat | K8s Operator | Guardian |
|---|---|---|---|
| Materializar K8s Secret | ✅ | ✅ | ✅ |
| Refresh automático | ✅ | ✅ | ✅ |
| Dynamic Secrets lease | ❌ | ✅ (CipherVaultLease) | ❌ |
| Drift detection | ❌ | ✅ | ✅ |
| Validating webhook | ❌ | ❌ | ✅ |
| Auto-create namespace | ❌ | ✅ (Federation) | ❌ |
| Multi-cluster federation | ❌ | ✅ (Federation) | ✅ (Phase 4) |
| Workload identity (SPIFFE) | ❌ | parcial | ✅ |
Migração ESO → Operator nativo
Quando você quiser sair do ESO:
# 1. Manifests novos com CipherVaultSecret CRDs (Operator nativo)
kubectl apply -f new-crds.yaml
# 2. Esperar Operator materializar (mesma resource name)
kubectl wait --for=condition=Ready CipherVaultSecret/stripe-key -n billing --timeout=5m
# 3. Remover ExternalSecret
kubectl delete externalsecret stripe-key -n billing
# 4. ESO SecretStore pode ser removido quando todos ExternalSecrets foram migrados
helm uninstall external-secrets-operator -n external-secrets-system
Limitações
- Sem
Pushmode — ESO permite pushar K8s Secrets para o backend; compat layer não suporta - Sem multi-secret single-call — ESO
dataFromque busca múltiplos secrets de uma vez não é otimizado; use path aggregator do CV diretamente para isso - Audit log registra cada chamada — alto volume com
refreshIntervalcurto pode encher SIEM. UserefreshInterval >= 5m
Boas práticas
- AppConnection dedicada para ESO — escopo
eso:readapenas refreshIntervalentre 5min e 1h — abaixo disso desperdiça API quota- Migração planejada — se você é greenfield, comece direto com Operator nativo; se brownfield com ESO, use compat layer como ponte