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=1kernel 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
coreuser 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 needWriteRequestBodiesto capture who-wrote-what. - Apply via
POST /v2/clusters/{id}/manifestsBEFORE install — include anAPIServerCR 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
NTSor authenticated source). - Apply a
MachineConfigfor 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
MachineConfigwith/etc/sysctl.d/99-brac-hardening.conf:net.ipv4.conf.all.send_redirects = 0net.ipv4.conf.all.accept_redirects = 0net.ipv4.conf.all.rp_filter = 1kernel.randomize_va_space = 2fs.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/setgidsyscall use - Log privileged-command exec
- Log
/etc/shadow,/etc/sudoerschanges - 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-allNetworkPolicy; apps opt-in to allowed flows. - Bake in a
NamespaceClassor manifests that create this on any new namespace. (In OCP 4.14+,AdminNetworkPolicycan enforce this cluster-wide.)
11. Ingress cipher suite restrictions¶
- PCI-DSS control: 4.2.1 (strong transit crypto)
IngressControllerCR: 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
APIServerCR 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/privilegedbindings for applications.
13. Image registry policies¶
- PCI-DSS control: 6.3.2 (only approved code/images)
- Deploy
ImageDigestMirrorSet+ImageContentSourcePolicypointing at Nexus (Issue #10 in our plan). - Restrict
registrySources.allowedRegistriesviaImageconfig 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
kubeadminSecret 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
APIServerCR:spec.encryption.type: aescbc(oraesgcmin 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
ScanSettingBindingwithpci-dssprofile against nodes. - Scans run on schedule; generate
ComplianceRemediationCRs 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.comvia cert-manager + Cloudflare DNS-01. - API server cert: replace self-signed with real cert via
APIServer.spec.servingCertspost-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.shrun 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.21channel viaClusterVersion(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 gainsfips: true, pinnedopenshift_version+ocp_release_image.03b-manifests-upload.sh(NEW): uploads the 8 install-time manifests listed above viaPOST /v2/clusters/{id}/manifests. Must run BEFORE05-iso-download.sh(manifests only accepted while cluster is inpending-for-inputstate).- 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)¶
- FIPS mode: ✅ Enabled (
fips: trueat install) — Decision #015 - Audit profile:
WriteRequestBodies— Decision #016 - IdP: Keycloak (deployed on the host infrastructure, outside the OCP cluster), realm
brac-poc, clientopenshift-brac, MFA required — Decision #017. allowedRegistries:[quay.io, registry.redhat.io, registry.connect.redhat.com, ghcr.io, <nexus-internal>]— Decision #018. Docker Hub explicitly NOT included.- Compliance scans:
pci-dss-4+ocp4-cisrunning in parallel via two ScanSettingBindings — Decision #019
📚 References / reading¶
- Red Hat: "Securing OpenShift Container Platform 4 for PCI-DSS" — Red Hat official guide
- CIS OpenShift Container Platform Benchmark v1.5
- PCI-DSS v4.0.1 standard
- OpenShift Compliance Operator docs
- OpenShift File Integrity Operator (PCI-DSS 11.5 file integrity monitoring)
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).