Tema
Procedimiento de Gestión de Claves Criptográficas
Documento: DOC-KEY-MGMT-01 Versión: 1.0 Fecha de aprobación: 2026-07-29 Owner: Security Lead Frecuencia de revisión: Anual + tras cualquier evento de compromiso Referencias PCI DSS: Req 3.6, Req 3.7 completo (3.7.1 a 3.7.9) Cuestionario ControlCase: Pregunta 28
1. Propósito
Definir el procedimiento operativo para el ciclo de vida completo de las claves criptográficas utilizadas para proteger la Información Cubierta.
2. Alcance
Todas las claves listadas en CRYPTO-ARCHITECTURE.md §5.2, incluyendo:
- Master Key de Vault (Shamir shares)
- KEKs de card-vault-service y tokenization-service (transit engine)
- HMAC key para PAN fingerprints
- DEKs generadas per-record
- TLS certificates
- JWT signing keys
3. Generación de claves (Req 3.7.1)
3.1 Master Key (Vault seal)
Cuándo: una vez en la vida del sistema, durante vault operator init. Se regenera solo en re-key ceremony (cada 3 años o compromiso sospechado).
Cómo:
bash
# Ejecutado durante la Ceremonia de Claves (KEY-CEREMONY-RUNBOOK.md)
# Con los 5 custodios físicamente presentes:
vault operator init \
-key-shares=5 \
-key-threshold=3 \
-format=json \
-stored-shares=0 \
> ceremony-output.jsonFuente de entropía: /dev/urandom del kernel Linux del droplet Vault, respaldado por getrandom(2) syscall.
Distribución: cada uno de los 5 shares se entrega inmediatamente al custodio correspondiente en sobre sellado y firmado (ver §4).
Prohibiciones:
- ❌ Nunca imprimir la master key completa
- ❌ Nunca escribir shares a disco fuera del proceso de captura
- ❌ Nunca enviar shares por email/Slack/canal electrónico
3.2 KEKs de servicios
Cuándo: creación inicial del transit engine + rotación anual programada + rotación por compromiso.
Cómo:
bash
# Con custodios que hicieron unseal (mínimo 3 presentes):
vault write -f transit/keys/kek-card-vault \
type=aes256-gcm96 \
exportable=false \
deletion_allowed=false \
derived=false
vault write -f transit/keys/kek-tokenization \
type=aes256-gcm96 \
exportable=false \
deletion_allowed=false \
derived=falsePropiedades enforced:
type=aes256-gcm96— AES-256 con GCM (nonce 96-bit, tag 128-bit)exportable=false— la key NUNCA puede salir de Vaultdeletion_allowed=false— no se puede borrar por accidente (requiere disable → allow_deletion → delete)derived=false— no KDF; usamos convergent encryption solo si necesario
3.3 HMAC key para fingerprint
bash
vault write -f transit/keys/hmac-pan-fpr \
type=hmac \
exportable=false \
deletion_allowed=false3.4 DEKs por registro
Generadas en runtime por Vault cuando el servicio solicita:
bash
# El servicio card-vault-service llama:
vault write -f transit/datakey/plaintext/kek-card-vault
# Vault retorna: { plaintext: <base64_dek>, ciphertext: "vault:v1:..." }
# El servicio usa la DEK en memoria para cifrar el PAN, luego descarta DEK
# Almacena solo el ciphertext en pg3.5 TLS Certificates
Generados automáticamente por cert-manager con Let's Encrypt (letsencrypt-prod ClusterIssuer) para APIs públicas, o Vault PKI engine para mTLS interno.
Rotación: automática cada 60 días (30 antes de expiración de 90 días de LE).
3.6 JWT signing keys
Cuándo: rotación cada 6 meses con graceful rollover 30 días.
bash
# Nueva key generada en Vault kv-v2
vault kv put secret/jwt-signing-keys/2026-h2 \
[email protected] \
[email protected]
# auth-service acepta 2 keys en simultáneo (rotación previa + nueva) durante 30 días4. Distribución segura (Req 3.7.2)
4.1 Shamir shares — ceremonia inicial
- Custodios físicamente presentes en sala segura (no cámaras, no dispositivos electrónicos personales durante la captura)
- Operator ejecuta
vault operator init— output visible en pantalla - Cada custodio anota SU share en formulario impreso pre-numerado
- Formulario doblado + puesto en sobre → sellado con cinta anti-manipulación → firmado por custodio y testigo
- Custodio se lo lleva; escrows D y E van a caja fuerte / notaría
- Formularios de custodios A, B, C se llevan personalmente y se guardan en caja fuerte personal con acceso registrado
Nunca:
- Fotografiar shares
- Transcribir shares a computadora
- Discutir shares fuera de la sala
4.2 KEKs — no se distribuyen
Las KEKs nunca salen del proceso Vault. Los servicios solo obtienen DEKs cifradas o realizan encrypt/decrypt como servicio.
4.3 AppRole credentials
bash
# Generar AppRole para card-vault-service
vault write auth/approle/role/card-vault-service \
token_policies="card-vault-policy" \
token_ttl=1h \
token_max_ttl=4h \
bind_secret_id=true \
secret_id_ttl=24h
# Obtener credenciales (rotables)
vault read -field=role_id auth/approle/role/card-vault-service/role-id
vault write -f -field=secret_id auth/approle/role/card-vault-service/secret-id- Role ID: distribuido a la K8s Deployment via ConfigMap (no sensible)
- Secret ID: rotado diariamente por cronjob, entregado via K8s Secret (encrypted at rest)
5. Almacenamiento seguro (Req 3.7.3)
Ver CRYPTO-ARCHITECTURE.md §5.2 para tabla autoritativa.
Controles adicionales:
| Ubicación | Control físico | Control lógico |
|---|---|---|
| Shamir shares (papel) | Caja fuerte con combinación + biometría (custodios A/B/C personales; escrow D oficina) | Rotación de combinación anual |
| Escrow E (notaría) | Custody legal | Sello notarial + acuerdo escrito |
| Vault Raft storage | Filesystem cifrado (LUKS) en droplet | Barrier encryption por Vault Root Key |
| DO Spaces WORM (audit) | DO datacenter físico (SOC 2 Type II) | Object lock immutable + IAM |
| Postgres (ciphertexts) | K8s cluster DO | AES-256-GCM at-rest (managed by DOKS) + RLS |
6. Rotación al fin del cryptoperiod (Req 3.7.4)
6.1 Rotación programada
Cronjob vault-key-rotation-annual corre 1° de enero cada año:
bash
#!/bin/bash
# Requires 2 admins present (Vault Sentinel policy enforces)
set -euo pipefail
TARGETS=("kek-card-vault" "kek-tokenization" "hmac-pan-fpr")
for k in "${TARGETS[@]}"; do
# Trigger rotation
vault write -f transit/keys/${k}/rotate
# Verificar nueva version
vault read transit/keys/${k} -format=json | jq '.data.latest_version'
# Emit audit event
logger -p auth.info "vault-key-rotation ${k} rotated at $(date -u)"
done
# Trigger re-encryption batch job (SEC-024)
kubectl -n pci-cde create job --from=cronjob/vault-rewrap-datakeys \
rewrap-$(date +%Y%m%d)Re-encryption diferida (rewrap):
Los datos existentes NO se re-cifran inmediatamente (impact perf). Se hace on-read o mediante batch:
typescript
// On-read (lazy migration):
const wrappedDek = await pg.query('SELECT dek_ciphertext FROM stored_cards WHERE id = $1', [cardId])
const rewrappedDek = await vault.write('transit/rewrap/kek-card-vault', {
ciphertext: wrappedDek
})
await pg.query('UPDATE stored_cards SET dek_ciphertext = $1 WHERE id = $2', [rewrappedDek, cardId])Verificación post-rotación:
- Grafana panel
Key Rotation Statusmuestralatest_versionpor key - Alerta si algún DEK sigue wrapped con versión >30 días vieja después de la rotación
6.2 Rotación por compromiso
Runbook completo: INCIDENT-KEY-COMPROMISE.md. Resumen:
- Detección: alerta SIEM o reporte manual → escalar a Security Lead
- Contención (< 1 h):
vault write transit/keys/{name}/config min_decryption_version=<new>— desactiva versiones viejas para decryptvault write transit/keys/{name}/rotate— genera nueva versión
- Erradicación (< 4 h):
- Batch rewrap forzado de TODOS los DEKs a la nueva versión
- Verificación con
SELECT COUNT(*) WHERE dek_ciphertext LIKE 'vault:v<old>:%'→ debe ser 0
- Recuperación (< 24 h):
- Deshabilitar versiones comprometidas:
vault write transit/keys/{name}/config deletion_allowed=true vault delete transit/keys/{name}/versions/<compromised_version>
- Deshabilitar versiones comprometidas:
- Post-mortem obligatorio en 72 h
7. Retirement (Req 3.7.5)
Reglas:
- No se elimina una versión de clave mientras exista al menos 1 registro cifrado con ella
- Se hace
min_decryption_versionupgrade primero para dejar de leerla - Cuando 0 registros la usan, se puede eliminar (requires
deletion_allowed=true) - Toda eliminación se audita
8. Prevención de sustitución no autorizada (Req 3.7.7)
Controles en capas:
Vault Policies (RBAC):
hcl# vault-policies/crypto-admin.hcl path "transit/keys/*" { capabilities = ["read", "update", "delete", "list"] } path "sys/policies/acl/*" { capabilities = ["read"] # No puede modificar policies }Solo la policy
crypto-admin(asignada a 2 admins) puede rotar/eliminar keys.MFA obligatoria para autenticación de admins Vault (Duo / TOTP).
Vault Sentinel policy (Enterprise-only, TODO Q4 2026 con upgrade):
hcl# Requiere aprobación de 2 admins para rotate/delete import "strings" main = rule { any request.headers.approvals.value as approval { approval.approved_by != request.token.entity.name } and length(request.headers.approvals.value) >= 2 }Audit log inmutable en DO Spaces WORM — cualquier intento (autorizado o no) queda registrado con
client_token,remote_address,request_id,timestamp.Alerta SIEM en cualquier
type=updateotype=deletesobretransit/keys/*→ PagerDuty al Security Lead.
9. Acuerdo formal con custodios (Req 3.7.8)
Cada custodio firma KEY-CUSTODIAN-AGREEMENT.pdf. Estructura obligatoria:
- Identificación: nombre completo, cédula, cargo
- Responsabilidades:
- Custodiar la Shamir share entregada
- Presentarse a ceremonias de unseal cuando sea convocado (≤ 24 h)
- NO revelar el contenido de la share bajo ninguna circunstancia
- Reportar inmediatamente cualquier pérdida/robo/compromiso
- Restricciones:
- NO fotografiar/transcribir la share
- NO llevar la share fuera del territorio nacional sin autorización escrita del CTO
- NO permitir a otros ver o copiar la share
- Handoff:
- En caso de renuncia: ceremonia de re-key (rotate) obligatoria antes de baja del custodio
- Se destruye la share del custodio saliente + se genera nueva share para reemplazo
- Consecuencias de violación:
- Cláusula NDA con penalidad económica
- Terminación de contrato laboral con causal
- Acciones legales conforme al Código Penal Colombiano Art. 269A-269H (delitos informáticos)
- Firma: custodio + CTO + testigo notarial
Documento firmado se archiva en: docs/pci-dss/agreements/KEY-CUSTODIAN-{A,B,C,D,E}.pdf (drive legal + escrow notarial).
10. Políticas documentadas (Req 3.7.9)
Los siguientes documentos, en conjunto, cumplen el requerimiento de políticas documentadas:
- CRYPTO-ARCHITECTURE.md — Arquitectura completa
- Este documento — Procedimientos operativos
- KEY-CEREMONY-RUNBOOK.md — Runbook de ceremonias
- DATA-RETENTION-DELETION-PROCEDURE.md — Retención
- Runbooks de incidentes:
INCIDENT-KEY-COMPROMISE.md,INCIDENT-VAULT-UNSEAL-FAILURE.md
Revisión anual obligatoria. Próxima: 2027-07-29.
11. Separación producción vs. pruebas (Req 3.6.1.4)
Regla dura: claves de producción NUNCA se usan en test/staging.
Implementación:
- Cluster Vault separado por ambiente (o Vault namespaces
prod/staging) - CI/CD verifica que los secretos apunten al cluster correcto según branch:
main→ prod Vault namespacestaging→ staging Vault namespacefeature/*→ local Vault dev in-memory
- Static analysis rule rechaza commits que referencien
VAULT_ADDR=vault-proden manifests de staging
12. Compartir claves con clientes (Req 3.7 SP-only)
Estado actual: Fintrixs NO comparte claves criptográficas con clientes merchants.
Si en el futuro se compartieran (ej: para integración API firmada del merchant):
- Se generaría par de keys por merchant (asimétrica RSA-2048 o ECDSA P-256)
- Merchant recibiría la key vía canal cifrado (portal HTTPS con autenticación MFA)
- Se entregaría guía
MERCHANT-KEY-HANDLING-GUIDELINES.pdfcon:- Cómo almacenar la key (HSM/Vault propio, nunca en repo git)
- Cómo rotar la key (endpoint API para trigger de rotación)
- Qué hacer en caso de compromiso (endpoint de revocación inmediata)
13. Métricas de compliance
Dashboard Grafana: Vault & Key Management Compliance
| Métrica | Valor esperado | Alerta |
|---|---|---|
vault_seal_status | unsealed | sealed durante > 5 min |
vault_leader_ready | 1 | 0 durante > 1 min |
vault_barrier_encryption_key_age_days | < 1095 (3 años) | > 900 días (warning), > 1080 (critical) |
transit_key_kek_card_vault_age_days | < 365 | > 340 (warning), > 360 (critical) |
transit_key_hmac_pan_fpr_age_days | < 365 | > 340 (warning), > 360 (critical) |
dek_rewrap_pending_count | 0 post-rotación | > 1000 durante > 7 días post-rotación |
custodian_last_ceremony_participation_days | < 90 | > 180 días sin participación |
14. Aprobaciones
| Rol | Nombre | Firma | Fecha |
|---|---|---|---|
| CTO | [TO_FILL] | ||
| Security Lead | [TO_FILL] | ||
| Legal / Compliance | [TO_FILL] |
