Skip to content

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.json

Fuente 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=false

Propiedades enforced:

  • type=aes256-gcm96 — AES-256 con GCM (nonce 96-bit, tag 128-bit)
  • exportable=false — la key NUNCA puede salir de Vault
  • deletion_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=false

3.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 pg

3.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ías

4. Distribución segura (Req 3.7.2) ​

4.1 Shamir shares — ceremonia inicial ​

  1. Custodios físicamente presentes en sala segura (no cámaras, no dispositivos electrónicos personales durante la captura)
  2. Operator ejecuta vault operator init — output visible en pantalla
  3. Cada custodio anota SU share en formulario impreso pre-numerado
  4. Formulario doblado + puesto en sobre → sellado con cinta anti-manipulación → firmado por custodio y testigo
  5. Custodio se lo lleva; escrows D y E van a caja fuerte / notaría
  6. 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ónControl físicoControl 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 legalSello notarial + acuerdo escrito
Vault Raft storageFilesystem cifrado (LUKS) en dropletBarrier 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 DOAES-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 Status muestra latest_version por 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:

  1. Detección: alerta SIEM o reporte manual → escalar a Security Lead
  2. Contención (< 1 h):
    • vault write transit/keys/{name}/config min_decryption_version=<new> — desactiva versiones viejas para decrypt
    • vault write transit/keys/{name}/rotate — genera nueva versión
  3. 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
  4. Recuperación (< 24 h):
    • Deshabilitar versiones comprometidas: vault write transit/keys/{name}/config deletion_allowed=true
    • vault delete transit/keys/{name}/versions/<compromised_version>
  5. 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_version upgrade 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:

  1. 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.

  2. MFA obligatoria para autenticación de admins Vault (Duo / TOTP).

  3. 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
    }
  4. Audit log inmutable en DO Spaces WORM — cualquier intento (autorizado o no) queda registrado con client_token, remote_address, request_id, timestamp.

  5. Alerta SIEM en cualquier type=update o type=delete sobre transit/keys/* → PagerDuty al Security Lead.

9. Acuerdo formal con custodios (Req 3.7.8) ​

Cada custodio firma KEY-CUSTODIAN-AGREEMENT.pdf. Estructura obligatoria:

  1. Identificación: nombre completo, cédula, cargo
  2. 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
  3. 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
  4. 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
  5. 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)
  6. 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:

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 namespace
    • staging → staging Vault namespace
    • feature/* → local Vault dev in-memory
  • Static analysis rule rechaza commits que referencien VAULT_ADDR=vault-prod en 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):

  1. Se generaría par de keys por merchant (asimétrica RSA-2048 o ECDSA P-256)
  2. Merchant recibiría la key vía canal cifrado (portal HTTPS con autenticación MFA)
  3. Se entregaría guía MERCHANT-KEY-HANDLING-GUIDELINES.pdf con:
    • 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étricaValor esperadoAlerta
vault_seal_statusunsealedsealed durante > 5 min
vault_leader_ready10 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_count0 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 ​

RolNombreFirmaFecha
CTO[TO_FILL]
Security Lead[TO_FILL]
Legal / Compliance[TO_FILL]

Documentación Confidencial — Solo para uso interno y auditoría PCI DSS