Skip to content

OpenShift Compliance Considerations (PCI-DSS + CIS + adjacent)

Scope: What the OpenShift PLATFORM must provide for BRAC Bank to pass PCI-DSS v4.0, CIS OpenShift Benchmark, and adjacent bank-sector audits (ISO 27001, SOC 2 platform controls, SWIFT CSP environmental). This doc does NOT cover application-layer compliance (cardholder data handling, app logging, etc.) — those are workload responsibilities, not platform.

Critical premise: A subset of compliance controls MUST be set at install-time. They cannot be retrofitted without rebuilding the cluster. The Assisted Installer API and its POST /v2/clusters/{id}/manifests endpoint are the vehicles for baking these in.


🚨 MUST be set at INSTALL-TIME (non-negotiable)

These cannot be enabled later without a cluster rebuild.

1. FIPS mode (140-3 validated cryptography)

  • PCI-DSS controls: 3.5.1, 3.6.1, 4.2.1 (strong crypto for stored and transmitted PAN)
  • API payload in POST /v2/clusters: json { "fips": true }
  • Effect:
  • Uses FIPS-validated OpenSSL + Go crypto libraries system-wide
  • RHCOS boots with fips=1 kernel cmdline
  • Container images using non-FIPS crypto will fail — verify workloads first
  • All TLS negotiations restricted to FIPS-approved cipher suites
  • Trade-off: Some third-party operators/images may not be FIPS-compatible (rare for mainstream OCP operators; always verify for custom images)
  • Decision for BRAC POC: Enable. This is a bank POC; FIPS is a strong signal and a PCI hard requirement for new deployments.

2. Disk Encryption (LUKS at rest, Tang-bound)

  • PCI-DSS controls: 3.5.1 (render stored data unreadable), 3.6.1 (protect crypto keys)
  • API payload: json "disk_encryption": { "enable_on": "all", "mode": "tang", "tang_servers": "[{\"url\":\"http://26.26.199.110:7500\",\"thumbprint\":\"<THUMBPRINT>\"}]" }
  • Already locked (Decision #011). Tang pins ensure keys are network-escrow, not stored on VM disks.

3. Base domain + pull secret + SSH keys

  • PCI-DSS controls: 8.2 (unique user IDs), 2.2.2 (default credentials)
  • Don't reuse a shared ocm pull secret across unrelated clusters (audit traceability).
  • SSH public keys: inject ONLY the authorized ops keys (engineer workstation + hosting-platform admin + brac-ops-runner). Do NOT inject team-wide keys — each node uses core user with no password.
  • Kubeadmin user is temporary — plan to remove before go-live (see day-2 section).

4. Release image pinning

  • PCI-DSS control: 6.3 (develop secure systems — reproducible deployments)
  • API payload: json "openshift_version": "4.21.9", // PATCH-level pin, not just "4.19" "ocp_release_image": "quay.io/openshift-release-dev/ocp-release:4.21.9-x86_64"
  • Pin the exact z-stream; avoids silent drift during re-runs. Update deliberately, not automatically.

5. Cluster / Service / Machine networks (no overlap, no revert)

  • PCI-DSS control: 1.x (network segmentation)
  • Non-default values set at install are permanent. Defaults work for BRAC POC:
  • clusterNetwork: 10.128.0.0/14 (pod IPs)
  • serviceNetwork: 172.30.0.0/16 (services)
  • machineNetwork: 26.26.0.0/16 (nodes)
  • Verified non-overlap with host-infrastructure networks.

6. Audit-profile seed via custom manifests

  • PCI-DSS controls: 10.2 (audit trail), 10.3 (audit record content)
  • OCP default audit profile is Default (logs metadata only). We need WriteRequestBodies to capture who-wrote-what.
  • Apply via POST /v2/clusters/{id}/manifests BEFORE install — include an APIServer CR patch: yaml apiVersion: config.openshift.io/v1 kind: APIServer metadata: name: cluster spec: audit: profile: WriteRequestBodies
  • Can be patched post-install, but it's cleaner to bake in — audit gaps between install and patching should be avoided.

✳️ SHOULD be set at install via POST /v2/clusters/{id}/manifests

These are technically day-2, but much easier to apply before the cluster is handed off. The Assisted Installer lets you upload extra manifests that get merged into the cluster-bootstrap artifacts.

7. Chrony/NTP authenticated time source

  • PCI-DSS control: 10.6 (time synchronization)
  • Audit logs across nodes must share accurate time. NTP must be authenticated (public NTP is fine for POC; production uses chrony with NTS or authenticated source).
  • Apply a MachineConfig for control-plane + workers pointing to a bank-controlled NTP server (or authenticated public pool during POC).
  • For POC: use time.google.com (NTS-capable). Real deployment: BRAC's internal chrony.

8. Kernel/sysctl hardening

  • CIS OpenShift 5.x: Kernel-level controls
  • MachineConfig with /etc/sysctl.d/99-brac-hardening.conf:
  • net.ipv4.conf.all.send_redirects = 0
  • net.ipv4.conf.all.accept_redirects = 0
  • net.ipv4.conf.all.rp_filter = 1
  • kernel.randomize_va_space = 2
  • fs.protected_symlinks = 1, fs.protected_hardlinks = 1
  • Apply before first node boot; reduces post-install remediation noise.

9. auditd rules on RHCOS

  • PCI-DSS controls: 10.2, 10.3
  • Default RHCOS auditd has generic rules. Add bank-specific ones via MachineConfig:
  • Log all setuid/setgid syscall use
  • Log privileged-command exec
  • Log /etc/shadow, /etc/sudoers changes
  • Red Hat ships a reference ruleset for PCI-DSS — reuse via the Compliance Operator's remediation CRs (can be pre-staged as manifests).

10. Default deny-all NetworkPolicy per non-system namespace

  • PCI-DSS controls: 1.2, 1.3 (segmentation)
  • Each workload namespace should have a default deny-all NetworkPolicy; apps opt-in to allowed flows.
  • Bake in a NamespaceClass or manifests that create this on any new namespace. (In OCP 4.14+, AdminNetworkPolicy can enforce this cluster-wide.)

11. Ingress cipher suite restrictions

  • PCI-DSS control: 4.2.1 (strong transit crypto)
  • IngressController CR: disable TLS 1.0/1.1, set explicit cipher list for TLS 1.2, allow TLS 1.3. yaml spec: tlsSecurityProfile: type: Custom custom: minTLSVersion: VersionTLS12 ciphers: - ECDHE-ECDSA-AES256-GCM-SHA384 - ECDHE-RSA-AES256-GCM-SHA384 - ECDHE-ECDSA-CHACHA20-POLY1305 - ECDHE-RSA-CHACHA20-POLY1305
  • Apply as a day-2 patch OR as an install manifest.

12. Pod Security Admission default = restricted

  • PCI-DSS control: 2.2 (system hardening)
  • OCP 4.14+ ships PSA. Set cluster-wide default via APIServer CR OR namespace labels: yaml # Each application namespace: labels: pod-security.kubernetes.io/enforce: restricted pod-security.kubernetes.io/enforce-version: latest
  • SCCs (SecurityContextConstraints) also remain — ensure no wide anyuid / privileged bindings for applications.

13. Image registry policies

  • PCI-DSS control: 6.3.2 (only approved code/images)
  • Deploy ImageDigestMirrorSet + ImageContentSourcePolicy pointing at Nexus (Issue #10 in our plan).
  • Restrict registrySources.allowedRegistries via Image config CR — block Docker Hub if not needed.

📅 POST-install / Day-2 compliance work (not in install scripts)

These become separate POC issues. Cannot all land in 6 days, but cluster should be set up to accept them.

14. Remove kubeadmin, integrate real IdP

  • PCI-DSS control: 8.2.1, 8.3 (strong auth, MFA)
  • Options for BRAC POC:
  • OIDC via Google (simple, MFA delegated to Google workspace)
  • htpasswd (POC only, with password complexity)
  • LDAP (most bank-like, but needs LDAP server) — Phase 2
  • Delete kubeadmin Secret as final step before BRAC demo.

15. etcd encryption at rest

  • PCI-DSS control: 3.5.1 (data at rest)
  • Already-present Secrets in etcd are NOT encrypted by default.
  • Enable via APIServer CR: spec.encryption.type: aescbc (or aesgcm in newer versions).
  • Automatic re-encryption of all Secrets + ConfigMaps.
  • Complements disk LUKS — defense in depth.

16. Compliance Operator (Issue #5)

  • PCI-DSS control: "show your work" — evidence of scanning
  • Operator installs from OperatorHub.
  • Apply ScanSettingBinding with pci-dss profile against nodes.
  • Scans run on schedule; generate ComplianceRemediation CRs for any FAIL.
  • Evidence artifact for BRAC: PDF/HTML export of scan results.

17. Advanced Cluster Security (Issue #5, stretch)

  • PCI-DSS control: 6.2 (vuln mgmt), 6.3 (secure dev)
  • Stackrox operator; runtime + build-time policies.
  • Policy: block deploy of images with Critical CVEs (PCI-DSS 6.3.3).
  • In 6 days, we install + configure baseline policies; full ACS tuning is Phase 2.

18. Cluster Logging + SIEM forward (Issue #6)

  • PCI-DSS control: 10.5 (protect audit trail), 10.5.4 (retention ≥1 year)
  • cluster-logging-operator → OTel → (for POC) local SigNoz / ClickHouse.
  • For real: forward to BRAC's SIEM (Splunk, Sentinel). Out of scope for POC.
  • Retention: set ClickHouse TTL = 2 days hot + archive to MinIO for ≥1 year (per DECISION-LOG #001).

19. Certificate management

  • PCI-DSS control: 4.2 (transit crypto validity)
  • Ingress uses *.apps.brac-poc.comptech-lab.com via cert-manager + Cloudflare DNS-01.
  • API server cert: replace self-signed with real cert via APIServer.spec.servingCerts post-install.
  • Automated rotation. Short lifetimes (90 days).

20. Backup / DR

  • PCI-DSS control: 12.10 (incident response), adjacent to DR
  • etcd backup: OpenShift backup-master-etcd-pods.sh run daily via CronJob to MinIO.
  • Full DR is out of POC scope; backup + documented restore procedure is sufficient for POC evidence.

21. Patch / update cadence

  • PCI-DSS control: 6.3.3 (security patches within 30 days of critical)
  • Subscribe to stable-4.21 channel via ClusterVersion (default after install).
  • Document patch-window process; for POC just show the channel is correct.

📋 Install-time manifest inventory (what scripts/ocp/cluster-create.sh uploads via POST /v2/clusters/{id}/manifests)

These get applied during install, before the cluster reaches "completed" state:

File Purpose PCI-DSS control
99-api-server-audit-profile.yaml APIServer CR with audit.profile: WriteRequestBodies 10.2, 10.3
99-ingress-tls-profile.yaml IngressController TLS 1.2+ + approved ciphers 4.2.1
99-image-config-registries.yaml Image CR with allowedRegistries pinned 6.3.2
99-chrony-machineconfig.yaml MachineConfig with time.google.com + NTS fallback 10.6
99-sysctl-hardening-machineconfig.yaml sysctl hardening per CIS 5.x CIS 5
99-auditd-rules-machineconfig.yaml auditd bank-specific rules 10.2, 10.3
99-default-deny-namespace-template.yaml AdminNetworkPolicy default-deny 1.2, 1.3
99-pod-security-cluster-default.yaml PSA: restricted as default 2.2

All are small YAML files. Store in scripts/ocp/manifests/ on the feature branch. The cluster-create.sh or a dedicated manifests-upload.sh (maybe 03b in our sequence) uploads each via the API.


⚠️ Honest gaps for a 6-day POC

These are things a real PCI-DSS audit would check that a 6-day POC cannot fully deliver:

Gap Why it's hard in 6 days Mitigation for the demo
1-year log retention (10.5.4) No real SIEM, no cold-archive scaling Document retention policy + show MinIO archive structure
MFA for all admin access (8.3) Needs real IdP with MFA (Okta/AzureAD) Use Google OIDC with mandatory 2FA; acceptable for POC
Quarterly pen testing (11.3) Out of scope Document the process BRAC will follow
Full change management (6.5) Out of scope GitOps via ArgoCD + GitHub PR process demonstrates the pattern
Dedicated DMZ for cardholder data (1.3) Single-cluster POC Network Policy + namespace separation demonstrates capability
HSM for key management (3.6) No physical HSM in POC Tang serves as key-escrow proxy; document HSM migration path
SOC 24/7 monitoring (10.6) No ops team Document alerting via Prometheus AlertManager

The POC CANNOT pass a full PCI-DSS QSA audit (no real environment does that in 6 days from scratch). The POC can show: - Compliance Operator report with PCI-DSS profile — most controls PASS, documented plan for the FAILs - ACS policies blocking vulnerable images (live demo) - Evidence of install-time hardening (FIPS, LUKS, audit profile, TLS restrictions) - GitOps audit trail via ArgoCD + Git


🎯 Impact on the execution plan

The following OCP install scripts change based on this:

  • 03-cluster-create.sh: payload gains fips: true, pinned openshift_version+ocp_release_image.
  • 03b-manifests-upload.sh (NEW): uploads the 8 install-time manifests listed above via POST /v2/clusters/{id}/manifests. Must run BEFORE 05-iso-download.sh (manifests only accepted while cluster is in pending-for-input state).
  • Day-2 workstream: separate GitHub issues for items 14–21 (many already exist as #5, #6, #9, #11 in our plan — refine them with the PCI-DSS mapping).

✅ Decisions (all locked 2026-04-24)

  1. FIPS mode: ✅ Enabled (fips: true at install) — Decision #015
  2. Audit profile: WriteRequestBodies — Decision #016
  3. IdP: Keycloak (deployed on the host infrastructure, outside the OCP cluster), realm brac-poc, client openshift-brac, MFA required — Decision #017.
  4. allowedRegistries: [quay.io, registry.redhat.io, registry.connect.redhat.com, ghcr.io, <nexus-internal>] — Decision #018. Docker Hub explicitly NOT included.
  5. Compliance scans: pci-dss-4 + ocp4-cis running in parallel via two ScanSettingBindings — Decision #019

📚 References / reading


Status: Drafted 2026-04-24. Pending decisions #1–#5 above. Once locked, Assisted Installer scripts gain install-time manifests; this doc is referenced by Issue #1 (OCP provisioning) and Issue #5 (Compliance Operator).