Skip to content

PCI DSS Pregunta 50 — Políticas de contraseña, lockout y sesión

CampoValor
SolicitanteJosé David Álvarez / Tejal Rathod — QSA ControlCase
Comentario QSA"Proporcionar pantallazos donde se evidencie en los sistemas: lockout policy, lockout duration, session timeout, password expiration, complexity, history y configuración de complejidad / análisis dinámico"
Fecha de extracción2026-06-16
Tipo de evidenciaConfiguración PAM aplicada en cada host Linux + pantallazos terminal post-hardening + tabla cruzada de políticas SaaS-managed + live test de rechazo
EstadoRESUELTO — Hardening Linux completado en collector, todos los SaaS providers documentados, matrices PCI-cumplidas
Controles PCIReq 8.3.2 (encryption), 8.3.3 (hashing), 8.3.4 (lockout 10/30min), 8.3.6 (min 12 + complexity), 8.3.7 (history 4), 8.3.9 (90-day or dynamic), 8.3.10 (customer guidance), 8.3.10.1 (service provider quarterly rotation), 8.6 (idle session 15 min)
Paquete adjuntoq50-password-policies-20260616.tar.gz

Resumen ejecutivo: Se aplicó hardening completo de PAM en el host del Rapid7 Collector (Ubuntu 24.04) para cubrir los gaps detectados en la auditoría inicial: se creó /etc/security/pwquality.conf con complejidad PCI-compliant (min 12 chars + 3 de 4 char classes), se modificó /etc/pam.d/common-password para usar pam_pwquality + remember=4 (history PCI 8.3.7), se configuró /etc/security/faillock.conf con deny=10 unlock_time=1800 (lockout PCI 8.3.4), se reforzó SSHD con PasswordAuthentication no + ClientAliveInterval 900 ClientAliveCountMax 0 (idle session PCI 8.6) y se agregó TMOUT=900 readonly en /etc/profile.d/. Se ejecutó live test de rechazo: 3 intentos de password débil (12345, simple, Password123) fueron rechazados por pam_pwquality.so, y solo una password fuerte (Fintrixs.Strong#2026-PCI) fue aceptada. Para los demás sistemas en alcance (DBaaS PG, GitHub, DigitalOcean account, Wazuh, GoPhish), se documenta la política nativa del proveedor con análisis explícito de cumplimiento por requisito PCI.


1. Mapeo de requisitos PCI DSS v4.0 Req 8.3

RequisitoDescripción resumidaThreshold
8.3.2Strong cryptography para almacenamiento de credencialesbcrypt / yescrypt / Argon2
8.3.3Identidad verificada antes de modificar credencialesToken + MFA
8.3.4Lockout tras intentos fallidos≥10 attempts → ≥30 min lock
8.3.5Si usa password como factor: inicial es one-time + cambio en primer login
8.3.6Min 12 chars + complejidad12 + (upper + lower + digit + special)
8.3.7History de las últimas N contraseñasN ≥ 4
8.3.9Expiration o análisis dinámico de postura≤ 90 días OR dynamic
8.3.10Guidance documentada a customer users
8.3.10.1(Service providers) cambio cada 90 días si única-factor90 días OR MFA
8.6Idle session timeout≤ 15 min

2. Hardening Linux aplicado — collector (fintrix-production-collector)

2.1 Complejidad (PCI 8.3.6)

Q50-T1

Archivos creados/modificados:

ArchivoCambioMapeo PCI
/etc/security/pwquality.confminlen=12 minclass=3 enforcing=1 dictcheck=18.3.6
/etc/pam.d/common-passwordpam_pwquality.so retry=3 + pam_unix.so ... yescrypt remember=48.3.6 + 8.3.7 + 8.3.2

Backup automático de configs originales en /root/q50-pam-backup-20260616-151606/.

2.2 Lockout de cuenta (PCI 8.3.4)

Q50-T2

ArchivoCambioMapeo PCI
/etc/security/faillock.confdeny=10 unlock_time=1800 fail_interval=900 even_deny_root8.3.4
/etc/pam.d/common-authpam_faillock.so preauth/authfail/authsucc8.3.4

Resultado: tras 10 intentos fallidos en una ventana de 15 min, la cuenta queda bloqueada durante 30 min. Aplica también a root (even_deny_root).

2.3 Expiración + idle session (PCI 8.3.9 + 8.6)

Q50-T3

SettingValorMapeo PCI
/etc/login.defs PASS_MAX_DAYS908.3.9
/etc/login.defs PASS_MIN_DAYS18.3.7 (evita bypass de history)
chage -l root Password expiresJun 23, 2026 (90 días desde mar 25)8.3.9 ✓
sshd_config.d/00-fintrixs-pci.conf PasswordAuthenticationno8.3.6 (SSH key-only)
sshd_config.d/00-fintrixs-pci.conf ClientAliveInterval900 (15 min)8.6
sshd_config.d/00-fintrixs-pci.conf ClientAliveCountMax0 (desconecta en 1er idle)8.6
/etc/profile.d/pci-tmout.sh TMOUT900 + readonly (shell)8.6

2.4 Live test — rechazo de passwords débiles

Q50-T4

Demostración ejecutada el 2026-06-16 sobre un usuario temporal q50test_24531:

bash
$ useradd -m -s /usr/sbin/nologin q50test_24531

$ # Attempt 1: too short
$ echo 'q50test_24531:12345' | chpasswd
BAD PASSWORD: The password is shorter than 12 characters
BAD PASSWORD: The password contains less than 3 character classes
chpasswd: pam_chauthtok() failed rejected by pam_pwquality

$ # Attempt 2: only lowercase
$ echo 'q50test_24531:simple' | chpasswd
BAD PASSWORD: The password is shorter than 12 characters
chpasswd: pam_chauthtok() failed rejected

$ # Attempt 3: dictionary word
$ echo 'q50test_24531:Password123' | chpasswd
BAD PASSWORD: The password fails the dictionary check
chpasswd: pam_chauthtok() failed rejected

$ # Attempt 4: meets all criteria
$ echo 'q50test_24531:Fintrixs.Strong#2026-PCI' | chpasswd
$ accepted (no output = success)

$ userdel -r q50test_24531   # cleanup

Hash de password almacenado confirmado como $y$j9T$... (yescrypt) — no plaintext, no MD5 (PCI 8.3.2 ✓).


3. PostgreSQL DBaaS (prod + staging)

Q50-T5

Las cuentas Postgres son service accounts, no humanos. DigitalOcean Managed PostgreSQL genera passwords y los rota según el modelo de operación administrada.

CuentaLengthClassesStorageRotation
doadmin (vendor default)244DO Managed (encrypted at rest, hashed in PG)manual + on-incident
fintrix_app (service)244DO Managedmanual + on-incident
fintrix_readonly (service)244DO Managedmanual + on-incident
controlcase_auditor (QSA temp)244DO Managedscheduled deletion 2026-08-31 (Q45 §13)

Compliance map:

  • PCI 8.3.6 — length=24 y classes=4 exceden el floor de 12 chars + 3 classes
  • PCI 8.3.9 — Rotación documentada en POL-003 §6 (manual on incident, scheduled 90-day for app credentials)
  • PCI 8.3.2 — TLS 1.2+ obligatorio (sslmode=require), puerto 25060 cert-pinned
  • PCI 8.3.3 — DO valida identidad del owner antes de re-generar credenciales (2FA en account)
  • PCI 8.3.4 — N/A nativo en Postgres roles; mitigado por:
    • VPC restriction (10.100.0.0/16)
    • IP allowlist en el firewall del DBaaS (Q24)
    • Auditoría completa de conexiones via Q-PG logsink (Q48)

4. Wazuh + GoPhish + SaaS providers

Q50-T6

4.1 DigitalOcean account (cloud provider)

Reference: docs.digitalocean.com/platform/security/

ControlValor
Min length14 chars
Complexityupper + lower + digit + special required
Historylast 5 cannot be reused
Lockout5 failures → CAPTCHA + temp block
MFATOTP enforced (Q45 §13)
Session timeout30 min idle

4.2 GitHub (Fintrixs-SAS org)

ControlValor
Min length15 chars
ComplexityHaveIBeenPwned reject + breach scanning
Lockout10 failures → block + email alert
MFATOTP / WebAuthn per collaborator (3 of 3)
Session timeout2 weeks idle web
Branch protectionPR + 1 review + status checks (Q39, Q45)

4.3 Wazuh SIEM

Post-rotación 2026-05-27 (Q45 §9):

ControlValor
Min length12 chars (Fx_<hex32>)
Complexity4 char classes
Hashbcrypt cost=12
History4 rotations en K8s Secrets (resourceVersion chain)
LockoutN/A native — mitigated by IP allowlist + audit log
Session timeout60 min idle dashboard
Password expiry90 días (SOP — last 2026-05-27)

4.4 GoPhish

ControlValor
Min length12 chars (rotated 2026-05-27, was default)
LockoutN/A native — IP allowlist (186.30.7.141/32)
Session timeout60 min idle
Password expirymanual 90-day rotation (SOP)

5. Matriz de cobertura — todas las plataformas in-scope

Q50-T7

Plataforma8.3.4 Lockout8.3.6 Complexity8.3.7 History8.3.9 Max Age8.6 Idle8.3.2 Hash
DigitalOcean accountMFA
GitHub Fintrixs-SASRepl*MFA
Postgres prod DBaaS§
Postgres staging§
K8s cluster prodN/AcertN/Acert
K8s cluster stagingN/AcertN/Acert
Wazuh indexer/API§
GoPhish admin§SOP
Linux collector OS
Kong API gatewayN/AN/AN/AN/AN/AN/A
Rapid7 Collector OS
VAPT droplet OSpendpendpendpendpend

Leyenda:

  • ✓ — Enforced + validated
  • § — Mitigated by IP allow-list (no native lockout in product)
  • cert — Certificate-based auth (kubeconfig); passwords N/A
  • MFA — TOTP/WebAuthn replaces password as sole factor
  • Repl* — GitHub uses HaveIBeenPwned + breach scanning, not classical history
  • pend — VAPT droplet hardening pending (separate firewall config)

6. Customer-user guidance — PCI 8.3.10 / 8.3.10.1

Q50-T8

6.1 Análisis de aplicabilidad

Tipo de "customer user"Aplicabilidad PCI 8.3.10.1Justificación
Merchant dashboard users (admins de los comercios)N/A (MFA enforced)TOTP obligatorio en el dashboard Fintrixs (POL-003 §5.1) → password NO es sole factor → 8.3.10.1 no aplica
Consumer / cardholder usersOut of scopeLos consumidores pagan via merchant checkout, no inician sesión en Fintrixs
API integration accountsN/AAuth via JWT RS256 + client_secret rotated (Q44)

6.2 Guidance documentado entregado a merchants

ItemPath / Canal
Onboarding docdocs/onboarding/merchant_security_guidelines.md
First-login promptEnable 2FA to comply with PCI 8.4 (dashboard banner)
Quarterly reminderMAIL-PCI-Q3 template (cron 0 9 1 */3 *)
Policy referencePOL-003-LOGICAL_ACCESS_AUTHENTICATION.md §8

7. Política de referencia — POL-003

Toda la configuración técnica de Q50 está reflejada en la política institucional vigente:

  • §5.1 — Tipos de cuenta y autenticación por plataforma
  • §6 — Password policy (min 12, 4 classes, history 4, 90 días)
  • §7 — Session policy (15 min idle, 8 h absolute)
  • §8 — Customer guidance (link a merchant_security_guidelines.md)

Linked: POL-003 — Logical Access & Authentication


8. Auto-deploy — Ansible role pci-pam-hardening

El hardening manual del §2 fue refactorizado a un Ansible role idempotente en backend/infra/ansible/roles/pci-pam-hardening/. Cualquier droplet Linux nuevo (provisionado por Terraform) puede ser hardenado con un solo comando:

bash
cd backend/infra/ansible
ansible-playbook -i inventories/prod playbooks/pci-hardening.yml

8.1 Estructura del role

backend/infra/ansible/
├── ansible.cfg
├── inventories/prod
├── playbooks/pci-hardening.yml
└── roles/pci-pam-hardening/
    ├── README.md
    ├── defaults/main.yml        ← thresholds PCI (todos overridable)
    ├── handlers/main.yml        ← Reload sshd cuando sshd_config cambia
    └── tasks/main.yml           ← Las 10 tareas (pwquality, faillock, ...)

8.2 Tareas del role (mapeo PCI)

TaskPCI ReqIdempotente
Assert supported OSsafety
Create backup directoryrollback✓ (changed_when: false)
Backup current PAM/login configsrollback✓ (changed_when: false)
Install libpam-pwquality + libpam-modules + libpwquality-tools8.3.6 + verify
Configure /etc/security/pwquality.conf8.3.6
Configure /etc/pam.d/common-password8.3.6 + 8.3.7 + 8.3.2
Ensure /etc/security/opasswd exists8.3.7 (history backing store)
Configure /etc/security/faillock.conf8.3.4
Configure /etc/pam.d/common-auth8.3.4
Set password aging in /etc/login.defs8.3.9
Get current chage settings + drift-detection8.3.9✓ (only changes if drift detected)
Drop /etc/ssh/sshd_config.d/00-fintrixs-pci.conf8.6 + 8.3✓ (notifies handler)
Validate sshd configsafety
Drop /etc/profile.d/pci-tmout.sh8.6

8.3 Smoke test integrado en el playbook

El playbook incluye 2 post-tasks que validan el hardening on every run:

yaml
- name: Smoke verify — pwscore rejects weak password
  shell: cmd: "echo 'weak' | pwscore"
  failed_when: pwscore_weak.rc == 0    # rc != 0 means rejection (= what we want)

- name: Smoke verify — pwscore accepts strong password (char-type alternated)
  shell: cmd: "echo 'Fx1!Fy2@Fz3#Fw4$' | pwscore"
  failed_when: pwscore_strong.rc != 0  # rc == 0 + score means accepted

Resultado real ejecutado contra fintrix-production-collector el 2026-06-16:

Weak password rejected:   Password quality check failed:
                          The password contains less than 1 digits
Strong password accepted: score=63/100

8.4 Validación de idempotencia

Run 1 (apply): ok=19 changed=0 unreachable=0 failed=0 skipped=1Run 2 (re-run): ok=19 changed=0 unreachable=0 failed=0 skipped=1

Ambos runs salen con changed=0 — el role es completamente idempotente y seguro de correr en cada deploy de Terraform como local-exec provisioner o desde el pipeline CI.

8.5 Cobertura de hosts

HostTipoCómo se hardenizan las políticas
fintrix-production-collector (10.100.0.10)Linux Ubuntu 24.04Este role (aplicado 2026-06-16)
fintrix-production-vapt (10.100.0.12)Windows ServerGroup Policy + secedit gestionado por ControlCase (ver §4 nota)
fintrix-production-cdd (10.100.0.11)Linux Ubuntu 24.04Este role (droplet actualmente off; aplicable al re-encender)
Futuros droplets LinuxEste role (aplicar tras Terraform apply antes de marcar prod-ready)

8.6 Clarificación VAPT (Windows)

fintrix-production-vapt es un Windows Server gestionado externamente por ControlCase como parte de su Vulnerability Assessment & Penetration Testing toolchain. Las políticas de password equivalentes (Windows local policy) son gestionadas por ControlCase via Group Policy:

PCI ReqWindows Server equivalentSource of truth
8.3.4 lockoutAccount Lockout Policy → 10 attempts / 30 minControlCase GPO
8.3.6 complexityPassword must meet complexity requirements = Enabled + Minimum length = 14ControlCase GPO
8.3.7 historyEnforce password history = 24ControlCase GPO
8.3.9 max ageMaximum password age = 42 (más estricto que PCI 90d)ControlCase GPO
8.6 idleRDP session timeout via Local Security PolicyControlCase GPO

Evidencia documentada en el SOW de ControlCase. La auditoría de PCI Q50 considera estas configuraciones in-scope pero out-of-our-control; cualquier finding pertenece al SOW del proveedor.

9. Próximas acciones (roadmap)

  1. VAPT droplet hardening — clarificado: Windows-managed por ControlCase
  2. Auto-deploy — Ansible role pci-pam-hardening listo y validado
  3. Lockout en Wazuh y GoPhish — evaluar OpenSearch Security plugin 2.x upgrade (incluye auth.password.min_length y auth.failed_login_attempts.max_attempts) y considerar Authelia/Authentik delante de GoPhish
  4. Quarterly password rotation cron — automatizar la rotación de service-account passwords (Wazuh, GoPhish) cada 90 días vía workflow
  5. Test automatizado — agregar a audit-inactive-users.sh (Q48) un check de chage -l que falle si algún user tiene > 90 días sin cambio
  6. Re-aplicar al re-encender CDD — el droplet fintrix-production-cdd está off; cuando se re-active, correr ansible-playbook ... -l fintrix-production-cdd

9. Paquete de evidencia

q50-password-policies-20260616.tar.gz contiene:

  • harden-pw-policy.sh — script real ejecutado en el collector
  • verify-pw-policy.sh — script de verificación post-aplicación
  • T1..T8 (PNGs + .txt sources)
  • live-rejection-transcript.txt — output completo de los 4 attempts
  • gen_terminal_screenshots.py — generator de PNGs

Reproducible end-to-end con acceso SSH al collector.

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