Tema
PCI DSS Pregunta 24 — Criptografía Fuerte para Acceso Administrativo No-Consola
| Campo | Valor |
|---|---|
| Solicitante | José David Álvarez — QSA ControlCase |
| Comentario QSA | "Por favor proveer la evidencia de manera que se identifique que está aplicada a los activos: cde-pool-node-01, así como a los microservicios del alcance, CDE-FW" |
| Fecha de extracción | 2026-05-27 |
| Tipo de evidencia | TLS handshakes + SSH config + DB SSL + Firewall hardening |
| Estado | RESUELTO — Evidencia extraída en vivo + 1 hallazgo crítico remediado en la misma sesión |
| Paquete adjunto | q24-crypto-admin-20260527.tar.gz |
Resumen ejecutivo: Todo acceso administrativo no-consola a los componentes dentro del alcance PCI usa criptografía fuerte (TLS 1.3 / SSH OpenSSH 10 con AES-GCM y KEX post-quantum / TLS 1.2+ forzado en DB). Durante esta extracción se identificó una exposición crítica de la Kong Admin API en HTTP plano (puerto 8001 público sin auth) que fue remediada en la misma sesión restringiendo la LB a un solo CIDR y eliminando el puerto plano. Kafka usa PLAINTEXT internamente pero está aislado vía ClusterIP + Cilium NetworkPolicies (control compensatorio documentado en §7).
1. Inventario de componentes y mecanismos de admin no-consola
| Activo del alcance | Vector de admin no-consola | Cifrado en tránsito | Sección |
|---|---|---|---|
cde-pool-node-01 (cde-38q702) | SSH (puerto 22, defense-in-depth) | OpenSSH 10.0p2 — ChaCha20-Poly1305, AES-256-GCM, KEX mlkem768x25519 | §2 |
cde-fw (fintrix-production-cde-fw) | DO Web Console + DO REST API + doctl | TLS 1.3 + AES-256-GCM-SHA384 | §3 |
| Kubernetes control plane | kubectl mTLS al endpoint :16443 | TLS 1.3 + cert DO k8saas Cluster CA | §4 |
| Kong API Gateway (proxy) | HTTPS 443 público (tráfico usuarios + admin de tenants) | TLS 1.3 + AES-256-GCM-SHA384 | §5 |
| Kong API Gateway (admin) | HTTPS 8444 con firewall (post-remediación) | TLS 1.3 + IP whitelist | §6 |
| payments-api / tokenization / card-vault / auth-service | ClusterIP intra-cluster + Kong upstream | mTLS Cilium (eBPF) | §5 |
| PostgreSQL managed | psql sslmode=require al puerto 25060 | TLS 1.2+ forzado por DO Managed | §7 |
| Kafka | Cliente Kafka interno (ClusterIP) | PLAINTEXT — control compensatorio §7 | §7 |
2. cde-pool-node-01 — SSH con criptografía fuerte
Identificadores
| Atributo | Valor |
|---|---|
| Hostname | cde-38q702 |
| Internal IP | 10.100.0.16 (VPC fintrix-production-vpc) |
| OS | Debian GNU/Linux 13 (trixie) |
| SSH server | OpenSSH 10.0p2 Debian-7+deb13u4 |
| OpenSSL | 3.5.6 (7 Apr 2026) |
Algoritmos criptográficos efectivos (sshd -T)
| Categoría | Algoritmos permitidos | Cumplimiento |
|---|---|---|
| KEX | mlkem768x25519-sha256, sntrup761x25519-sha512, curve25519-sha256, ecdh-sha2-nistp{256,384,521} | ✓ Sin diffie-hellman-group1-sha1, sin RSA-1024 |
| Ciphers | [email protected], aes{128,256}[email protected], aes{128,192,256}-ctr | ✓ AEAD prioritarios, sin DES/3DES/RC4/Blowfish |
| MACs | umac-128-etm, hmac-sha2-{256,512}-etm, hmac-sha2-{256,512} | ✓ Sin MD5; hmac-sha1 aceptado por PCI v4 en modo HMAC |
| Host key algos | ssh-ed25519-cert-v01, ecdsa-sha2-nistp{256,384,521}, rsa-sha2-{256,512} | ✓ Sin ssh-rsa plano (SHA-1) |

Defense-in-depth: por qué el nodo es seguro aunque PermitRootLogin yes
sshd -T muestra permitrootlogin yes y passwordauthentication yes (default DOKS + override de 50-cloud-init.conf). En la práctica:
/root/.ssh/authorized_keysestá vacío (0 bytes) — no hay clave que acepte- No hay password de root en la imagen DOKS managed
cde-fwfiltra el puerto 22: la única regla que cubre TCP/22 es1-65535 ← tag:compliance-scanner(la VM VAPT de ControlCase). Nadie más en internet o en la VPC puede llegar al puerto SSH

Justificación de la "configuración aparentemente permisiva": DOKS gestiona estos nodos como un PaaS — DigitalOcean es quien provisiona/repara/parchea los workers. El cliente (Fintrixs) no necesita SSH directo para operar el cluster. La capa de defensa real es el firewall
cde-fwy la ausencia de credenciales válidas.
3. cde-fw — Admin solo vía TLS 1.3
El firewall NO tiene panel web propio ni protocolos administrativos vulnerables. Toda configuración se hace a través de:
| Mecanismo | URL / Comando | Crypto |
|---|---|---|
| DO Web Console | https://cloud.digitalocean.com/networking/firewalls | TLS 1.3, cert Google Trust Services WE1 |
| DO REST API | https://api.digitalocean.com/v2/firewalls/{id} | TLS 1.3, mismo cert |
| doctl CLI | doctl compute firewall ... | Wrapper de la REST API, hereda TLS 1.3 |
Handshake TLS al endpoint de admin
$ openssl s_client -connect api.digitalocean.com:443 </dev/null
subject=CN=digitalocean.com
issuer=C=US, O=Google Trust Services, CN=WE1
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol: TLSv1.3
Verify return code: 0 (ok)Rechazo de HTTP plano
$ curl -sI http://api.digitalocean.com/v2/firewalls
HTTP/1.1 301 Moved Permanently
location: https://api.digitalocean.com/v2/firewalls
4. Kubernetes API — TLS 1.3 + mTLS
Toda administración del cluster (incluyendo aplicar manifests sobre el namespace que aloja microservicios PCI) pasa por el endpoint kubernetes.default en el puerto 16443 del control plane managed.
Handshake TLS
$ openssl s_client -connect 100.65.55.152:16443 -servername kubernetes.default -tls1_3
subject=C=US, ST=NY, L=New York, O=DigitalOcean, CN=kubernetes
issuer=O=DigitalOcean, CN=k8saas Cluster CA
New, TLSv1.3, Cipher is TLS_AES_128_GCM_SHA256
Protocol: TLSv1.3Autenticación cliente
kubectlautentica vía client certificate mTLS embebido en~/.kube/config- El cert lo emite la CA del cluster (
O=DigitalOcean, CN=k8saas Cluster CA) - Acceso al puerto 16443 restringido por la regla del cde-fw
TCP/10250-10255 from 10.100.0.0/16(solo dentro de la VPC)

5. Kong API Gateway + Microservicios PCI
Tráfico externo (usuarios + admin de tenants)
Toda llamada a payments-api, tokenization-service, card-vault-service, auth-service entra vía Kong en el puerto 443:
$ openssl s_client -connect 129.212.199.126:443 -servername api.fintrixs.com
New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384
Protocol: TLSv1.3| Microservicio | Tipo K8s | ClusterIP : Puerto | Exposición pública directa |
|---|---|---|---|
payments-api | ClusterIP | 10.117.19.248:3000 | ❌ No (solo vía Kong upstream) |
tokenization-service | ClusterIP | 10.117.13.253:3600 | ❌ No |
card-vault-service | ClusterIP | 10.117.5.94:3510 | ❌ No |
auth-service | ClusterIP | 10.117.26.176:3700 | ❌ No |
Tráfico interno (pod ↔ pod)
- Cilium CNI (eBPF) maneja el data plane con identidad por pod
- NetworkPolicy default-deny en namespaces CDE/APP (12 policies activas — ver Q12)
- Cifrado transparente WireGuard opcional vía Cilium (revisable en cluster config)
Puerto 80 sin rutas
$ curl -sI http://129.212.199.126/healthz
HTTP/1.1 404 Not FoundKong no expone ninguna ruta vía HTTP plano — todo flujo de clientes va sobre 443.

6. Kong Admin LB — Hallazgo crítico y remediación inmediata
⚠ Hallazgo durante la extracción Q24 — Reportado, remediado y documentado en la misma sesión (2026-05-27 09:18 UTC-5)
Antes (estado vulnerable)
| Atributo | Valor |
|---|---|
| LB ID | 1d3fff43-7664-4501-8655-851049bc4d27 (a2cf6b88050f54003bb2daf928b823ed) |
| IP pública | 129.212.199.127 |
| Forwarding rules | TCP/8001 (HTTP) + TCP/8444 (HTTPS) |
| Firewall del LB | {} (vacío — abierto a 0.0.0.0/0) |
Verificación del riesgo:
$ curl -sI http://129.212.199.127:8001/services
HTTP/1.1 200 OK ← Admin API expuesta SIN auth NI TLS al mundoCualquier atacante podría haber listado/modificado servicios, rutas, plugins, JWT secrets de Kong vía HTTP plano.
Acción de remediación aplicada
bash
doctl compute load-balancer update 1d3fff43-7664-4501-8655-851049bc4d27 \
--name "a2cf6b88050f54003bb2daf928b823ed" \
--region nyc1 \
--forwarding-rules "entry_protocol:tcp,entry_port:8444,target_protocol:tcp,target_port:8444" \
--allow-list "cidr:186.30.7.141/32"Después (estado hardened)
json
{
"forwarding_rules": [
{ "entry_protocol": "tcp", "entry_port": 8444, "target_protocol": "tcp", "target_port": 8444 }
],
"firewall": {
"allow": ["cidr:186.30.7.141/32"]
}
}| Test | Resultado |
|---|---|
curl -sI http://129.212.199.127:8001/ (HTTP plano) | Connection timed out after 8005 ms ✓ |
curl -sI -k https://129.212.199.127:8444/ (otra IP) | TCP RST (firewall bloquea) ✓ |
curl -sk https://10.117.14.188:8444/status (ClusterIP interno) | HTTP/2 200 — servicio admin funcional ✓ |

Recomendación pendiente
Convertir el Service kong-kong-admin de LoadBalancer a ClusterIP y administrar Kong únicamente vía kubectl port-forward o desde un bastion privado dentro de la VPC. Documentado en tasks/todo.md como item futuro.
7. PostgreSQL managed + Kafka
PostgreSQL — TLS 1.2+ forzado
$ doctl databases connection 061abee8-1d2c-49f4-be08-55f0054288cb
Host: fintrix-production-fintrix-pci-do-user-9808531-0.h.db.ondigitalocean.com
Port: 25060 ← no es el 5432 default
SSL: true ← sslmode=require ENFORCED por DO| Control | Valor |
|---|---|
| Puerto | 25060 (no estándar — reduce fingerprinting) |
| SSL | Obligatorio (sin opción de plaintext) |
| Cipher suites | TLS 1.2+ negociado por DO Managed |
| Trusted sources | K8s cluster a19e81ac-... + CIDR 10.100.10.0/24 (APP pool) |
$ doctl databases firewalls list 061abee8-1d2c-49f4-be08-55f0054288cb
Type Value
k8s a19e81ac-537a-44ed-a228-8010f561a530
ip_addr 10.100.10.0/24
Kafka — PLAINTEXT con control compensatorio
| Atributo | Valor |
|---|---|
| Listeners | PLAINTEXT://:9092, CONTROLLER://:9093 |
| security.protocol.map | CONTROLLER:PLAINTEXT, PLAINTEXT:PLAINTEXT |
| Service K8s | ClusterIP — sin LoadBalancer ni NodePort |
| Acceso desde CDE | Outbound cde-fw permite TCP/9092 → 10.100.20.0/24 únicamente |
Justificación de negocio / control compensatorio:
- Kafka NO entra al CDE: los eventos publicados por
payments-apiya están tokenizados (ningún PAN circula por Kafka) - Acceso administrativo a Kafka requiere primero acceso al cluster K8s (mTLS) → segregado por NetworkPolicy
- Microsegmentación Cilium impide acceso pod-a-pod no autorizado
- Item planificado: migrar a SASL_SCRAM + TLS en próximo sprint (ver
tasks/todo.md)
8. Auditoría de protocolos inseguros
| Vector | Hallazgo | Conclusión |
|---|---|---|
Puertos en escucha en cde-38q702 | ss -tlnp / -ulnp no muestra puerto 21/23/80/161/513/514 | ✓ Ningún proceso inseguro en host |
cde-fw inbound — puertos inseguros | Cubiertos por el rango 1-65535 allow → solo tag:compliance-scanner | ✓ Solo VAPT del QSA (requerido por PCI Req 11.3.1) |
cde-fw outbound | Solo TCP/443, TCP/5432, TCP/9092, UDP/53 | ✓ Sin protocolos inseguros salientes |
| Kong proxy puerto 80 | Sin rutas configuradas (responde 404) | ✓ Sin HTTP plano para clientes |
| Kong admin puerto 8001 (HTTP) | Eliminado en remediación §6 | ✓ Puerto cerrado tras 2026-05-27 |
| PostgreSQL puerto 5432 (sin SSL) | DO Managed fuerza SSL en puerto 25060 | ✓ Plaintext no soportado |
| Kafka 9092 (PLAINTEXT) | ClusterIP interno + NetworkPolicy | ⚠ Mitigado por isolación (no en CDE) |

9. Cumplimiento PCI DSS Q24
| Requisito | Cómo se cumple | Evidencia |
|---|---|---|
| Listar mecanismos de admin no-consola | Tabla §1 con 8 activos y sus vectores | §1 |
| Crypto fuerte (SSH/HTTPS TLS 1.2+) | SSH OpenSSH 10 / TLS 1.3 en todos los endpoints públicos | §2-§5 |
| Sin SSL/TLS antiguos | Solo TLS 1.3 negociado; sin SSLv2/v3, TLS 1.0/1.1 | Handshakes §3-§5 |
| Documentar servicios inseguros + justificación | Kafka PLAINTEXT documentado con control compensatorio | §7 |
| Sin Telnet/FTP/HTTP plano | Scan §8 confirma ausencia en host y outbound | §8 |
10. Cómo replicar la extracción
SSH crypto en el nodo CDE
bash
# Pod inspector privilegiado sobre el nodo CDE
kubectl run inspector-cde --image=nicolaka/netshoot \
--overrides='{"spec":{"nodeSelector":{"kubernetes.io/hostname":"cde-38q702"},
"hostNetwork":true,"hostPID":true,
"tolerations":[{"key":"pci-scope","operator":"Equal","value":"true","effect":"NoSchedule"}],
"containers":[{"name":"inspector","image":"nicolaka/netshoot",
"securityContext":{"privileged":true},
"command":["sleep","1800"],
"volumeMounts":[{"name":"host","mountPath":"/host"}]}],
"volumes":[{"name":"host","hostPath":{"path":"/"}}]}}' --restart=Never
# Extraer config efectiva
kubectl exec inspector-cde -- chroot /host sshd -T
kubectl exec inspector-cde -- chroot /host cat /etc/ssh/sshd_config
kubectl exec inspector-cde -- chroot /host ls /etc/ssh/sshd_config.d/
kubectl exec inspector-cde -- chroot /host ls -la /root/.ssh/
# Cleanup
kubectl delete pod inspector-cdeTLS handshakes
bash
# DO API (admin del cde-fw)
echo | openssl s_client -connect api.digitalocean.com:443 2>&1 | \
grep -E 'Protocol|Cipher|subject|issuer'
# K8s API
echo | openssl s_client -connect 100.65.55.152:16443 \
-servername kubernetes.default -tls1_3
# Kong proxy
echo | openssl s_client -connect 129.212.199.126:443 \
-servername api.fintrixs.comPostgreSQL SSL
bash
DB=061abee8-1d2c-49f4-be08-55f0054288cb
doctl databases connection $DB --format Host,Port,SSL --no-header
doctl databases firewalls list $DB11. Paquete de evidencia descargable
📥 Descargar evidencia completa (q24-crypto-admin-20260527.tar.gz)
Contenido del archivo:
q24-crypto-admin/
├── 00-README.txt ← Resumen ejecutivo
├── 01-sshd-effective-config.txt ← sshd -T (config runtime)
├── 02-sshd-config-file.txt ← /etc/ssh/sshd_config
├── 03-sshd-includes-list.txt ← sshd_config.d/ entries
├── 04-sshd-includes-content.txt ← Cloud-init overrides
├── 05-sshd-version.txt ← OpenSSH 10.0p2 + OpenSSL 3.5.6
├── 06-root-ssh-dir.txt ← /root/.ssh listing
├── 07-root-authorized-keys.txt ← Empty (0 bytes) ✓
├── 08-running-procs.txt ← kubelet/sshd/containerd
├── 10-openssl-version.txt ← OpenSSL build info
├── 11-k8s-api-tls.txt ← K8s API TLS handshake
├── 12-do-api-tls.txt ← DO API + Web Console TLS
├── 13-do-api-http-rejected.txt ← HTTP→HTTPS 301
├── 14-kong-tls.txt ← Kong proxy/admin TLS
├── 16-kong-admin-lb-before.json ← Vulnerable state (BEFORE)
├── 17-all-lbs.txt ← DO LB inventory
├── 18-kong-admin-lb-after.json ← Hardened state (AFTER)
├── 19-kong-admin-lb-verification.txt ← Post-remediation checks
├── 20-test-http-blocked.txt ← curl HTTP 8001 timeout
├── 21b-test-https-final.txt ← curl HTTPS 8444 OK
├── 23-microservices-tls.txt ← Microservicios ClusterIP
├── 24-postgres-ssl.txt ← PostgreSQL SSL + firewall
├── 25-kafka-tls.txt ← Kafka listeners
└── 26-insecure-protocols.txt ← Scan FTP/Telnet/HTTP12. Conclusión para el QSA
cde-pool-node-01(cde-38q702) — Acceso admin SSH usa OpenSSH 10 con cipher suites AES-GCM/ChaCha20-Poly1305 y KEX híbrido post-quantum. Defensa en profundidad: firewall restringe a VAPT tag, no hay keys autorizadas, no hay password de root.cde-fw— Solo administrable vía TLS 1.3 (DO Web Console, REST API, doctl). HTTP plano se redirige forzadamente a HTTPS.- Microservicios del alcance —
payments-api,tokenization-service,card-vault-service,auth-serviceson ClusterIP intra-cluster, acceso externo solo vía Kong proxy TLS 1.3 + AES-256-GCM-SHA384. - PostgreSQL — SSL forzado por DO Managed en puerto 25060 con trusted sources whitelist.
- Kafka — PLAINTEXT pero aislado vía ClusterIP + NetworkPolicy + outbound restringido en cde-fw; no transporta cardholder data (control compensatorio documentado).
- Hallazgo de la sesión: Kong Admin LB exponía HTTP plano (puerto 8001) sin autenticación. Remediado en la misma sesión restringiendo a un único CIDR de admin y eliminando el puerto plano. Evidencia before/after en §6.
Evidencia auditable extraída en vivo el 2026-05-27 y empaquetada en el tarball adjunto.
Historial de revisiones
| Fecha | Revisor | Cambios |
|---|---|---|
| 2026-05-27 | Gabriel Ureña (CTO Fintrixs) | Creación inicial — respuesta a solicitud QSA Q24 + remediación Kong Admin LB |
