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