← Back to Index

Compliance Operator Usage Guide

OpenShift 4 includes a powerful Compliance Operator that helps organizations monitor and enforce security compliance policies across the cluster. This operator implements industry-standard security benchmarks and provides mechanisms to assess your cluster’s compliance status and remediate issues.

While the Compliance Operator offers robust functionality, it can be challenging to use effectively due to its complex configuration requirements and the technical nature of compliance standards. This guide aims to simplify the process and provide clear instructions for implementing compliance scanning in your OpenShift environment.

Video Explanation:

Understanding the Compliance Operator Architecture (AIGC)

The Compliance Operator works with several custom resources that interact to provide a complete compliance solution:

  1. ProfileBundle: Contains compliance content from security standards (like CIS, NIST, STIG)
  2. Profile: Represents a specific security standard implementation (e.g., ocp4-cis)
  3. Rule: Individual compliance checks that are evaluated during scans
  4. Variable: Customizable parameters that can be adjusted to meet specific requirements
  5. ScanSetting: Defines how scans should be executed (schedule, storage, etc.)
  6. ScanSettingBinding: Links profiles to scan settings to create a compliance suite
  7. TailoredProfile: A customized version of a standard profile with specific rule or variable adjustments

When a scan runs, it creates runtime resources:

  1. ComplianceSuite: Collection of scans created from a ScanSettingBinding
  2. ComplianceScan: Individual scan execution for a specific profile
  3. ComplianceCheckResult: Results of individual rule evaluations (pass/fail)
  4. ComplianceRemediation: Auto-fix options for failed checks

The diagram below illustrates how these components interact:

graph TD
            %% Main Component
            CO[Compliance Operator] 
            
            %% Configuration Components - Vertical Layout
            subgraph "Configuration Components"
                direction TB
                PB[ProfileBundle<br>Pre-defined compliance content] --> P[Profile<br>Security standard implementation]
                P --> R[Rule<br>Individual compliance check]
                P --> V[Variable<br>Customizable parameters]
                V --> TP[TailoredProfile<br>Customized profile]
                P --> TP
                SS[ScanSetting<br>Scan configuration] --> SSB[ScanSettingBinding<br>Links profiles to settings]
            end
            
            %% Runtime Components - Vertical Layout
            subgraph "Runtime Components"
                direction TB
                CS[ComplianceSuite<br>Collection of scans] --> CScan[ComplianceScan<br>Individual scan execution]
                CScan --> CCR[ComplianceCheckResult<br>Pass/Fail results]
                CCR --> CR[ComplianceRemediation<br>Auto-fix options]
            end
            
            %% Relationships - Configuration
            CO --> PB
            CO --> SS
            
            %% Relationships - Binding
            SSB --> P
            SSB --> TP
            SSB --> SS
            
            %% Relationships - Runtime
            SSB --> |"Creates"| CS
            
            
            %% ProfileBundle Types - Vertical Layout
            subgraph "ProfileBundle Types"
                %% direction TB
                PB1[rhcos4<br>Node compliance]
                PB2[ocp4<br>Platform compliance]
                %% PB1 -- invisible link --> PB2
                %% style "invisible link" fill:none,stroke:none
            end
            
            PB --> PB1
            PB --> PB2
            
            %% ScanSetting Types - Vertical Layout
            subgraph "ScanSetting Examples"
                direction TB
                SS1[default<br>Manual remediation]
                SS2[default-auto-apply<br>Automatic remediation]
            end
            
            SS --> SS1
            SS --> SS2
            
            %% Workflow
            User[User] --> |"Creates"| SSB
            CR --> |"Can be applied to"| Cluster[OpenShift Cluster]
            CCR --> |"Exported as"| Report[HTML Report]
            
            %% Styling
            classDef operator fill:#dae8fc,stroke:#6c8ebf,stroke-width:2px;
            classDef config fill:#e1d5e7,stroke:#9673a6,stroke-width:1px;
            classDef runtime fill:#d5e8d4,stroke:#82b366,stroke-width:1px;
            classDef examples fill:#fff2cc,stroke:#d6b656,stroke-width:1px;
            classDef user fill:#f8cecc,stroke:#b85450,stroke-width:1px;
            
            class CO operator;
            class PB,P,R,V,SS,SSB,TP config;
            class CS,CScan,CCR,CR runtime;
            class P1,P2,P3,P4,PB1,PB2,SS1,SS2 examples;
            class User,Cluster,Report user;

deploy compliance-operator

Select the compliance operator from the list of available operators and click on it to deploy it.

Accept the default settings and click on Install to start the installation process.

Continue with the installation until it is complete.

After the installation is complete, you can access the operator dashboard. In the all instances section, you can see a list of all the instances that have been deployed. We filter out profile bundle and scan setting, and we can see there are 2 instances each of them deployed.

Understanding the Default ProfileBundles

The Compliance Operator automatically creates two ProfileBundles:

  1. rhcos4: Contains compliance content for Red Hat CoreOS nodes
  2. ocp4: Contains compliance content for the OpenShift Container Platform

Let’s examine the rhcos4 ProfileBundle:

apiVersion: compliance.openshift.io/v1alpha1
        kind: ProfileBundle
        metadata:
          finalizers:
            - profilebundle.finalizers.compliance.openshift.io
          name: rhcos4
          namespace: openshift-compliance
        spec:
          contentFile: ssg-rhcos4-ds.xml
          contentImage: 'registry.redhat.io/compliance/openshift-compliance-content-rhel8@sha256:b286929357b82f8ff3845f535bab23382bf06f075ff2379063e2456f1a93e809'
        status:
          conditions:
            - lastTransitionTime: '2025-03-11T15:54:42Z'
              message: Profile bundle successfully parsed
              reason: Valid
              status: 'True'
              type: Ready
          dataStreamStatus: VALID

profile bundle definition for ocp4:

apiVersion: compliance.openshift.io/v1alpha1
        kind: ProfileBundle
        metadata:
          finalizers:
            - profilebundle.finalizers.compliance.openshift.io
          name: ocp4
          namespace: openshift-compliance
        spec:
          contentFile: ssg-ocp4-ds.xml
          contentImage: 'registry.redhat.io/compliance/openshift-compliance-content-rhel8@sha256:b286929357b82f8ff3845f535bab23382bf06f075ff2379063e2456f1a93e809'
        status:
          conditions:
            - lastTransitionTime: '2025-03-11T15:53:55Z'
              message: Profile bundle successfully parsed
              reason: Valid
              status: 'True'
              type: Ready
          dataStreamStatus: VALID

Understanding the Default ScanSettings

The Compliance Operator creates two default ScanSettings:

  1. default: Configures scans with manual remediation (you must apply remediations yourself)
  2. default-auto-apply: Configures scans with automatic remediation (remediations are applied automatically)

Let’s examine the default ScanSetting:

timeout: 30m
        strictNodeScan: true
        metadata:
          name: default
          namespace: openshift-compliance
        kind: ScanSetting
        showNotApplicable: false
        rawResultStorage:
          nodeSelector:
            node-role.kubernetes.io/master: ''
          pvAccessModes:
            - ReadWriteOnce
          rotation: 3
          size: 1Gi
          tolerations:
            - effect: NoSchedule
              key: node-role.kubernetes.io/master
              operator: Exists
            - effect: NoExecute
              key: node.kubernetes.io/not-ready
              operator: Exists
              tolerationSeconds: 300
            - effect: NoExecute
              key: node.kubernetes.io/unreachable
              operator: Exists
              tolerationSeconds: 300
            - effect: NoSchedule
              key: node.kubernetes.io/memory-pressure
              operator: Exists
        schedule: 0 1 * * *
        suspend: false
        roles:
          - master
          - worker
        apiVersion: compliance.openshift.io/v1alpha1
        maxRetryOnTimeout: 3
        scanTolerations:
          - operator: Exists

scan setting definition for default-auto-apply:

timeout: 30m
        autoUpdateRemediations: true
        strictNodeScan: true
        autoApplyRemediations: true
        metadata:
          name: default-auto-apply
          namespace: openshift-compliance
        kind: ScanSetting
        showNotApplicable: false
        rawResultStorage:
          nodeSelector:
            node-role.kubernetes.io/master: ''
          pvAccessModes:
            - ReadWriteOnce
          rotation: 3
          size: 1Gi
          tolerations:
            - effect: NoSchedule
              key: node-role.kubernetes.io/master
              operator: Exists
            - effect: NoExecute
              key: node.kubernetes.io/not-ready
              operator: Exists
              tolerationSeconds: 300
            - effect: NoExecute
              key: node.kubernetes.io/unreachable
              operator: Exists
              tolerationSeconds: 300
            - effect: NoSchedule
              key: node.kubernetes.io/memory-pressure
              operator: Exists
        schedule: 0 1 * * *
        suspend: false
        roles:
          - master
          - worker
        apiVersion: compliance.openshift.io/v1alpha1
        maxRetryOnTimeout: 3
        scanTolerations:
          - operator: Exists

There are many other kind of resources predefined.

Understanding Compliance Profiles

The Compliance Operator provides numerous pre-defined profiles that implement various security standards. These profiles are categorized by:

  1. Standard type: CIS, NIST, PCI-DSS, STIG, etc.
  2. Target: Platform (ocp4-) or Node (rhcos4-)
  3. Security level: moderate, high, etc.

Let’s examine the available profiles:

oc get Profile -A
        
        # NAMESPACE              NAME                       AGE   VERSION
        
        # openshift-compliance   ocp4-cis                   10h   1.5.0
        
        # openshift-compliance   ocp4-cis-1-4               10h   1.4.0
        
        # openshift-compliance   ocp4-cis-1-5               10h   1.5.0
        
        # openshift-compliance   ocp4-cis-node              10h   1.5.0
        
        # openshift-compliance   ocp4-cis-node-1-4          10h   1.4.0
        
        # openshift-compliance   ocp4-cis-node-1-5          10h   1.5.0
        
        # openshift-compliance   ocp4-e8                    10h
        
        # openshift-compliance   ocp4-high                  10h   Revision 4
        
        # openshift-compliance   ocp4-high-node             10h   Revision 4
        
        # openshift-compliance   ocp4-high-node-rev-4       10h   Revision 4
        
        # openshift-compliance   ocp4-high-rev-4            10h   Revision 4
        
        # openshift-compliance   ocp4-moderate              10h   Revision 4
        
        # openshift-compliance   ocp4-moderate-node         10h   Revision 4
        
        # openshift-compliance   ocp4-moderate-node-rev-4   10h   Revision 4
        
        # openshift-compliance   ocp4-moderate-rev-4        10h   Revision 4
        
        # openshift-compliance   ocp4-nerc-cip              10h
        
        # openshift-compliance   ocp4-nerc-cip-node         10h
        
        # openshift-compliance   ocp4-pci-dss               10h   3.2.1
        
        # openshift-compliance   ocp4-pci-dss-3-2           10h   3.2.1
        
        # openshift-compliance   ocp4-pci-dss-4-0           10h   4.0.0
        
        # openshift-compliance   ocp4-pci-dss-node          10h   3.2.1
        
        # openshift-compliance   ocp4-pci-dss-node-3-2      10h   3.2.1
        
        # openshift-compliance   ocp4-pci-dss-node-4-0      10h   4.0.0
        
        # openshift-compliance   ocp4-stig                  10h   V2R1
        
        # openshift-compliance   ocp4-stig-node             10h   V2R1
        
        # openshift-compliance   ocp4-stig-node-v1r1        10h   V1R1
        
        # openshift-compliance   ocp4-stig-node-v2r1        10h   V2R1
        
        # openshift-compliance   ocp4-stig-v1r1             10h   V1R1
        
        # openshift-compliance   ocp4-stig-v2r1             10h   V2R1
        
        # openshift-compliance   rhcos4-e8                  10h
        
        # openshift-compliance   rhcos4-high                10h   Revision 4
        
        # openshift-compliance   rhcos4-high-rev-4          10h   Revision 4
        
        # openshift-compliance   rhcos4-moderate            10h   Revision 4
        
        # openshift-compliance   rhcos4-moderate-rev-4      10h   Revision 4
        
        # openshift-compliance   rhcos4-nerc-cip            10h
        
        # openshift-compliance   rhcos4-stig                10h   V2R1
        
        # openshift-compliance   rhcos4-stig-v1r1           10h   V1R1
        
        # openshift-compliance   rhcos4-stig-v2r1           10h   V2R1

And the detail of an profile of ocp4-cis, we can see it references to many rules.

apiVersion: compliance.openshift.io/v1alpha1
        description: 'This profile defines a baseline that aligns to the Center for Internet Security® Red Hat OpenShift Container Platform 4 Benchmark™, V1.5. This profile includes Center for Internet Security® Red Hat OpenShift Container Platform 4 CIS Benchmarks™ content. Note that this part of the profile is meant to run on the Platform that Red Hat OpenShift Container Platform 4 runs on top of. This profile is applicable to OpenShift versions 4.12 and greater.'
        id: xccdf_org.ssgproject.content_profile_cis
        kind: Profile
        metadata:
          annotations:
            compliance.openshift.io/image-digest: pb-ocp4m2njf
            compliance.openshift.io/product: redhat_openshift_container_platform_4.1
            compliance.openshift.io/product-type: Platform
          name: ocp4-cis
          namespace: openshift-compliance
          labels:
            compliance.openshift.io/profile-bundle: ocp4
            compliance.openshift.io/profile-guid: a230315d-3e4a-5b58-b00f-f96f1553e036
        rules:
          - ocp4-accounts-restrict-service-account-tokens
          - ocp4-accounts-unique-service-account
          - ocp4-api-server-admission-control-plugin-alwaysadmit
          - ocp4-api-server-admission-control-plugin-alwayspullimages
          - ocp4-api-server-admission-control-plugin-namespacelifecycle
          - ocp4-api-server-admission-control-plugin-noderestriction
          - ocp4-api-server-admission-control-plugin-scc
          - ocp4-api-server-admission-control-plugin-service-account
          - ocp4-api-server-anonymous-auth
          - ocp4-api-server-audit-log-maxbackup
          - ocp4-api-server-audit-log-maxsize
          - ocp4-api-server-audit-log-path
          - ocp4-api-server-auth-mode-no-aa
          - ocp4-api-server-auth-mode-rbac
          - ocp4-api-server-basic-auth
          - ocp4-api-server-bind-address
          - ocp4-api-server-client-ca
          - ocp4-api-server-encryption-provider-cipher
          - ocp4-api-server-etcd-ca
          - ocp4-api-server-etcd-cert
          - ocp4-api-server-etcd-key
          - ocp4-api-server-https-for-kubelet-conn
          - ocp4-api-server-insecure-bind-address
          - ocp4-api-server-kubelet-certificate-authority
          - ocp4-api-server-kubelet-client-cert
          - ocp4-api-server-kubelet-client-cert-pre-4-9
          - ocp4-api-server-kubelet-client-key
          - ocp4-api-server-kubelet-client-key-pre-4-9
          - ocp4-api-server-oauth-https-serving-cert
          - ocp4-api-server-openshift-https-serving-cert
          - ocp4-api-server-profiling-protected-by-rbac
          - ocp4-api-server-request-timeout
          - ocp4-api-server-service-account-lookup
          - ocp4-api-server-service-account-public-key
          - ocp4-api-server-tls-cert
          - ocp4-api-server-tls-cipher-suites
          - ocp4-api-server-tls-private-key
          - ocp4-api-server-token-auth
          - ocp4-audit-log-forwarding-enabled
          - ocp4-audit-log-forwarding-webhook
          - ocp4-audit-logging-enabled
          - ocp4-audit-profile-set
          - ocp4-configure-network-policies
          - ocp4-configure-network-policies-hypershift-hosted
          - ocp4-configure-network-policies-namespaces
          - ocp4-controller-insecure-port-disabled
          - ocp4-controller-secure-port
          - ocp4-controller-service-account-ca
          - ocp4-controller-service-account-private-key
          - ocp4-controller-use-service-account
          - ocp4-etcd-auto-tls
          - ocp4-etcd-cert-file
          - ocp4-etcd-client-cert-auth
          - ocp4-etcd-key-file
          - ocp4-etcd-peer-auto-tls
          - ocp4-etcd-peer-cert-file
          - ocp4-etcd-peer-client-cert-auth
          - ocp4-etcd-peer-key-file
          - ocp4-file-groupowner-proxy-kubeconfig
          - ocp4-file-owner-proxy-kubeconfig
          - ocp4-file-permissions-proxy-kubeconfig
          - ocp4-general-apply-scc
          - ocp4-general-default-namespace-use
          - ocp4-general-default-seccomp-profile
          - ocp4-general-namespaces-in-use
          - ocp4-idp-is-configured
          - ocp4-kubeadmin-removed
          - ocp4-kubelet-configure-tls-cert
          - ocp4-kubelet-configure-tls-cipher-suites-ingresscontroller
          - ocp4-kubelet-configure-tls-key
          - ocp4-kubelet-disable-readonly-port
          - ocp4-ocp-allowed-registries
          - ocp4-ocp-allowed-registries-for-import
          - ocp4-ocp-api-server-audit-log-maxbackup
          - ocp4-ocp-api-server-audit-log-maxsize
          - ocp4-ocp-insecure-allowed-registries-for-import
          - ocp4-ocp-insecure-registries
          - ocp4-openshift-api-server-audit-log-path
          - ocp4-rbac-debug-role-protects-pprof
          - ocp4-rbac-least-privilege
          - ocp4-rbac-limit-cluster-admin
          - ocp4-rbac-limit-secrets-access
          - ocp4-rbac-pod-creation-access
          - ocp4-rbac-wildcard-use
          - ocp4-scc-drop-container-capabilities
          - ocp4-scc-limit-container-allowed-capabilities
          - ocp4-scc-limit-ipc-namespace
          - ocp4-scc-limit-net-raw-capability
          - ocp4-scc-limit-network-namespace
          - ocp4-scc-limit-privilege-escalation
          - ocp4-scc-limit-privileged-containers
          - ocp4-scc-limit-process-id-namespace
          - ocp4-scc-limit-root-containers
          - ocp4-scheduler-profiling-protected-by-rbac
          - ocp4-scheduler-service-protected-by-rbac
          - ocp4-secrets-consider-external-storage
          - ocp4-secrets-no-environment-variables
          - ocp4-version-detect-in-hypershift
          - ocp4-version-detect-in-ocp
        title: CIS Red Hat OpenShift Container Platform 4 Benchmark
        version: 1.5.0

There are many rule predefined.

The total number of rule is around 1082.

oc get Rule -A | wc -l
        
        # 1082

Let’s see an example of rule: ocp4-kubeadmin-removed

checkType: Platform
        instructions: |-
          To verify that the kubeadmin secret has been deleted, make sure
          that oc get secrets kubeadmin -n kube-system
          returns a NotFound error.
          Is it the case that the kubeadmin secret has not been deleted?
        metadata:
          annotations:
            policies.open-cluster-management.io/standards: 'NERC-CIP,NIST-800-53,PCI-DSS,STIG,CIS-OCP,PCI-DSS-4-0'
            control.compliance.openshift.io/PCI-DSS-4-0: 2.2.1;2.2.2;2.2;8.2.2;8.2;8.3
            compliance.openshift.io/profiles: 'ocp4-stig,ocp4-moderate-rev-4,ocp4-cis-1-5,ocp4-pci-dss,ocp4-cis,ocp4-stig-v1r1,ocp4-pci-dss-4-0,ocp4-nerc-cip,ocp4-pci-dss-3-2,ocp4-high,ocp4-stig-v2r1,ocp4-cis-1-4,ocp4-high-rev-4,ocp4-moderate'
            control.compliance.openshift.io/CIS-OCP: 3.1.1;5.1.1
            policies.open-cluster-management.io/controls: 'CIP-004-6 R2.2.2,CIP-004-6 R2.2.3,CIP-007-3 R.1.3,CIP-007-3 R2,CIP-007-3 R5,CIP-007-3 R5.1.1,CIP-007-3 R5.1.3,CIP-007-3 R5.2.1,CIP-007-3 R5.2.3,CIP-007-3 R6.1,CIP-007-3 R6.2,CIP-007-3 R6.3,CIP-007-3 R6.4,AC-2(2),AC-2(7),AC-2(9),AC-2(10),AC-12(1),IA-2(5),MA-4,SC-12(1),Req-2.1,SRG-APP-000023-CTR-000055,3.1.1,5.1.1,2.2.1,2.2.2,2.2,8.2.2,8.2,8.3,CNTR-OS-000030,CNTR-OS-000040,CNTR-OS-000440'
            control.compliance.openshift.io/STIG: SRG-APP-000023-CTR-000055;CNTR-OS-000030;CNTR-OS-000040;CNTR-OS-000440
            control.compliance.openshift.io/NIST-800-53: AC-2(2);AC-2(7);AC-2(9);AC-2(10);AC-12(1);IA-2(5);MA-4;SC-12(1)
            control.compliance.openshift.io/NERC-CIP: CIP-004-6 R2.2.2;CIP-004-6 R2.2.3;CIP-007-3 R.1.3;CIP-007-3 R2;CIP-007-3 R5;CIP-007-3 R5.1.1;CIP-007-3 R5.1.3;CIP-007-3 R5.2.1;CIP-007-3 R5.2.3;CIP-007-3 R6.1;CIP-007-3 R6.2;CIP-007-3 R6.3;CIP-007-3 R6.4
            compliance.openshift.io/image-digest: pb-ocp4m2njf
            control.compliance.openshift.io/PCI-DSS: Req-2.1
            compliance.openshift.io/rule: kubeadmin-removed
          name: ocp4-kubeadmin-removed
          namespace: openshift-compliance
          ownerReferences:
            - apiVersion: compliance.openshift.io/v1alpha1
              blockOwnerDeletion: true
              controller: true
              kind: ProfileBundle
              name: ocp4
              uid: a7e06c24-12d2-4f21-97bd-a59b5d158f3b
          labels:
            compliance.openshift.io/profile-bundle: ocp4
        kind: Rule
        rationale: |-
          The kubeadmin user has an auto-generated password and a self-signed certificate, and has effectively
        
          cluster-admin
        
          permissions; therefore, it's considered a security liability.
        title: Ensure that the kubeadmin secret has been removed
        id: xccdf_org.ssgproject.content_rule_kubeadmin_removed
        description: |-
          The kubeadmin user is meant to be a temporary user used for bootstrapping purposes. It is preferable to assign system administrators whose users are backed by an Identity Provider.
        
          Make sure to remove the user as described in the documentation ( https://docs.openshift.com/container-platform/latest/authentication/remove-kubeadmin.html )
        severity: medium
        apiVersion: compliance.openshift.io/v1alpha1

There are also many variables defined.

And the total number of variables is around 153.

oc get Variables -A | wc -l
        
        # 153

Let’s look at the Variables: rhcos4-sshd-idle-timeout-value in detail. The variables is used with TailoredProfiles to customize the behavior of the profile. For example, the rhcos4-sshd-idle-timeout-value variable is used to set the idle timeout for SSH connections on Red Hat Enterprise Linux CoreOS (RHCOS) 4.

selections:
          - description: 10_minutes
            value: '600'
          - description: 120_minutes
            value: '7200'
          - description: 14_minutes
            value: '840'
          - description: 15_minutes
            value: '900'
          - description: 30_minutes
            value: '1800'
          - description: 5_minutes
            value: '300'
          - description: 60_minutes
            value: '3600'
        metadata:
          annotations:
            compliance.openshift.io/image-digest: pb-rhcos4s7b7g
          name: rhcos4-sshd-idle-timeout-value
          namespace: openshift-compliance
          ownerReferences:
            - apiVersion: compliance.openshift.io/v1alpha1
              blockOwnerDeletion: true
              controller: true
              kind: ProfileBundle
              name: rhcos4
              uid: 648c319d-7378-4474-9f0c-6f1a5f536bfb
          labels:
            compliance.openshift.io/profile-bundle: rhcos4
        value: '300'
        kind: Variable
        title: SSH session Idle time
        type: number
        id: xccdf_org.ssgproject.content_value_sshd_idle_timeout_value
        description: Specify duration of allowed idle time.
        apiVersion: compliance.openshift.io/v1alpha1

Running Compliance Scans

Now that we understand the components of the Compliance Operator, let’s run a scan to assess our cluster’s compliance status. The process involves creating a ScanSettingBinding that connects profiles to scan settings.

Creating a ScanSettingBinding

To run a scan, we need to create a ScanSettingBinding that specifies:

  1. Which profiles to scan against (in this case, we’ll use CIS benchmarks)
  2. Which scan settings to use (we’ll use the default settings for manual remediation)

Here’s an example ScanSettingBinding that will scan both the OpenShift platform and nodes against CIS benchmarks:

apiVersion: compliance.openshift.io/v1alpha1
        kind: ScanSettingBinding
        metadata:
          name: cis-compliance
          namespace: openshift-compliance
        profiles:
          - name: ocp4-cis-node
            kind: Profile
            apiGroup: compliance.openshift.io/v1alpha1
          - name: ocp4-cis
            kind: Profile
            apiGroup: compliance.openshift.io/v1alpha1
        settingsRef:
          name: default
          kind: ScanSetting
          apiGroup: compliance.openshift.io/v1alpha1

Navigate to scan setting binding section and click on the Add Scan Setting Binding button.

Past the example scan setting binding yaml file.

After the scan setting binding is created, we can see there are many pods created to carry out the scan.

Understanding Scan Results

After creating the ScanSettingBinding, the Compliance Operator will:

  1. Create a ComplianceSuite resource
  2. Create ComplianceScan resources for each profile
  3. Deploy scan pods to evaluate compliance rules
  4. Store results as ComplianceCheckResult resources
  5. Generate ComplianceRemediation resources for failed checks

Wait a moment for the scan to complete. You’ll see the scan pods running and then completing:

Once complete, the results are created in the format of Custom Resources (CRs):

Let’s examine these results in detail by filtering for specific resource types:

First is ComplianceSuite, it tells which nodes are part of the scan and what kind of profile to use, and the compliance scan result.

apiVersion: compliance.openshift.io/v1alpha1
        kind: ComplianceSuite
        metadata:
          name: cis-compliance
          namespace: openshift-compliance
          ownerReferences:
            - apiVersion: compliance.openshift.io/v1alpha1
              blockOwnerDeletion: true
              controller: true
              kind: ScanSettingBinding
              name: cis-compliance
              uid: 34099038-7d08-4ed1-b981-95f8a67be73b
          finalizers:
            - suite.finalizers.compliance.openshift.io
        spec:
          scans:
            - nodeSelector:
                node-role.kubernetes.io/master: ''
              timeout: 30m
              contentImage: 'registry.redhat.io/compliance/openshift-compliance-content-rhel8@sha256:b286929357b82f8ff3845f535bab23382bf06f075ff2379063e2456f1a93e809'
              strictNodeScan: true
              profile: xccdf_org.ssgproject.content_profile_cis-node
              name: ocp4-cis-node-master
              showNotApplicable: false
              rawResultStorage:
                nodeSelector:
                  node-role.kubernetes.io/master: ''
                pvAccessModes:
                  - ReadWriteOnce
                rotation: 3
                size: 1Gi
                tolerations:
                  - effect: NoSchedule
                    key: node-role.kubernetes.io/master
                    operator: Exists
                  - effect: NoExecute
                    key: node.kubernetes.io/not-ready
                    operator: Exists
                    tolerationSeconds: 300
                  - effect: NoExecute
                    key: node.kubernetes.io/unreachable
                    operator: Exists
                    tolerationSeconds: 300
                  - effect: NoSchedule
                    key: node.kubernetes.io/memory-pressure
                    operator: Exists
              scanType: Node
              content: ssg-ocp4-ds.xml
              maxRetryOnTimeout: 3
              scanTolerations:
                - operator: Exists
            - nodeSelector:
                node-role.kubernetes.io/worker: ''
              timeout: 30m
              contentImage: 'registry.redhat.io/compliance/openshift-compliance-content-rhel8@sha256:b286929357b82f8ff3845f535bab23382bf06f075ff2379063e2456f1a93e809'
              strictNodeScan: true
              profile: xccdf_org.ssgproject.content_profile_cis-node
              name: ocp4-cis-node-worker
              showNotApplicable: false
              rawResultStorage:
                nodeSelector:
                  node-role.kubernetes.io/master: ''
                pvAccessModes:
                  - ReadWriteOnce
                rotation: 3
                size: 1Gi
                tolerations:
                  - effect: NoSchedule
                    key: node-role.kubernetes.io/master
                    operator: Exists
                  - effect: NoExecute
                    key: node.kubernetes.io/not-ready
                    operator: Exists
                    tolerationSeconds: 300
                  - effect: NoExecute
                    key: node.kubernetes.io/unreachable
                    operator: Exists
                    tolerationSeconds: 300
                  - effect: NoSchedule
                    key: node.kubernetes.io/memory-pressure
                    operator: Exists
              scanType: Node
              content: ssg-ocp4-ds.xml
              maxRetryOnTimeout: 3
              scanTolerations:
                - operator: Exists
            - timeout: 30m
              contentImage: 'registry.redhat.io/compliance/openshift-compliance-content-rhel8@sha256:b286929357b82f8ff3845f535bab23382bf06f075ff2379063e2456f1a93e809'
              strictNodeScan: true
              profile: xccdf_org.ssgproject.content_profile_cis
              name: ocp4-cis
              showNotApplicable: false
              rawResultStorage:
                nodeSelector:
                  node-role.kubernetes.io/master: ''
                pvAccessModes:
                  - ReadWriteOnce
                rotation: 3
                size: 1Gi
                tolerations:
                  - effect: NoSchedule
                    key: node-role.kubernetes.io/master
                    operator: Exists
                  - effect: NoExecute
                    key: node.kubernetes.io/not-ready
                    operator: Exists
                    tolerationSeconds: 300
                  - effect: NoExecute
                    key: node.kubernetes.io/unreachable
                    operator: Exists
                    tolerationSeconds: 300
                  - effect: NoSchedule
                    key: node.kubernetes.io/memory-pressure
                    operator: Exists
              scanType: Platform
              content: ssg-ocp4-ds.xml
              maxRetryOnTimeout: 3
              scanTolerations:
                - operator: Exists
          schedule: 0 1 * * *
          suspend: false
        status:
          conditions:
            - lastTransitionTime: '2025-03-12T03:10:44Z'
              message: Compliance suite run is done running the scans
              reason: NotRunning
              status: 'False'
              type: Processing
            - lastTransitionTime: '2025-03-12T03:10:44Z'
              message: Compliance suite run is done and has results
              reason: Done
              status: 'True'
              type: Ready
          phase: DONE
          result: NON-COMPLIANT
          scanStatuses:
            - conditions:
                - lastTransitionTime: '2025-03-12T03:10:44Z'
                  message: Compliance scan run is done running the scans
                  reason: NotRunning
                  status: 'False'
                  type: Processing
                - lastTransitionTime: '2025-03-12T03:10:44Z'
                  message: Compliance scan run is done and has results
                  reason: Done
                  status: 'True'
                  type: Ready
              endTimestamp: '2025-03-12T03:10:44Z'
              name: ocp4-cis-node-master
              phase: DONE
              remainingRetries: 3
              result: NON-COMPLIANT
              resultsStorage:
                name: ocp4-cis-node-master
                namespace: openshift-compliance
              startTimestamp: '2025-03-12T03:09:30Z'
            - conditions:
                - lastTransitionTime: '2025-03-12T03:10:44Z'
                  message: Compliance scan run is done running the scans
                  reason: NotRunning
                  status: 'False'
                  type: Processing
                - lastTransitionTime: '2025-03-12T03:10:44Z'
                  message: Compliance scan run is done and has results
                  reason: Done
                  status: 'True'
                  type: Ready
              endTimestamp: '2025-03-12T03:10:44Z'
              name: ocp4-cis-node-worker
              phase: DONE
              remainingRetries: 3
              result: NON-COMPLIANT
              resultsStorage:
                name: ocp4-cis-node-worker
                namespace: openshift-compliance
              startTimestamp: '2025-03-12T03:09:22Z'
            - resultsStorage:
                name: ocp4-cis
                namespace: openshift-compliance
              name: ocp4-cis
              remainingRetries: 3
              startTimestamp: '2025-03-12T03:09:22Z'
              warnings: 'could not fetch /apis/apps/v1/namespaces/openshift-sdn/daemonsets/sdn: daemonsets.apps "sdn" not found'
              conditions:
                - lastTransitionTime: '2025-03-12T03:10:44Z'
                  message: Compliance scan run is done running the scans
                  reason: NotRunning
                  status: 'False'
                  type: Processing
                - lastTransitionTime: '2025-03-12T03:10:44Z'
                  message: Compliance scan run is done and has results
                  reason: Done
                  status: 'True'
                  type: Ready
              phase: DONE
              endTimestamp: '2025-03-12T03:10:44Z'
              result: NON-COMPLIANT

And the ComplianceScan, it tells which profile runs on what kind of nodes, and the compliance scan result.

apiVersion: compliance.openshift.io/v1alpha1
        kind: ComplianceScan
        metadata:
          annotations:
            compliance.openshift.io/check-count: '94'
          resourceVersion: '20397087'
          name: ocp4-cis-node-worker
          namespace: openshift-compliance
          ownerReferences:
            - apiVersion: compliance.openshift.io/v1alpha1
              blockOwnerDeletion: true
              controller: true
              kind: ComplianceSuite
              name: cis-compliance
              uid: 38e6939a-ac3f-4d9d-9c90-44dc3cb35632
          finalizers:
            - scan.finalizers.compliance.openshift.io
          labels:
            compliance.openshift.io/profile-guid: fea955f1-9f13-56fd-aacf-868b95b7283f
            compliance.openshift.io/suite: cis-compliance
        spec:
          nodeSelector:
            node-role.kubernetes.io/worker: ''
          timeout: 30m
          contentImage: 'registry.redhat.io/compliance/openshift-compliance-content-rhel8@sha256:b286929357b82f8ff3845f535bab23382bf06f075ff2379063e2456f1a93e809'
          strictNodeScan: true
          profile: xccdf_org.ssgproject.content_profile_cis-node
          showNotApplicable: false
          rawResultStorage:
            nodeSelector:
              node-role.kubernetes.io/master: ''
            pvAccessModes:
              - ReadWriteOnce
            rotation: 3
            size: 1Gi
            tolerations:
              - effect: NoSchedule
                key: node-role.kubernetes.io/master
                operator: Exists
              - effect: NoExecute
                key: node.kubernetes.io/not-ready
                operator: Exists
                tolerationSeconds: 300
              - effect: NoExecute
                key: node.kubernetes.io/unreachable
                operator: Exists
                tolerationSeconds: 300
              - effect: NoSchedule
                key: node.kubernetes.io/memory-pressure
                operator: Exists
          scanType: Node
          content: ssg-ocp4-ds.xml
          maxRetryOnTimeout: 3
          scanTolerations:
            - operator: Exists
        status:
          conditions:
            - lastTransitionTime: '2025-03-12T03:10:44Z'
              message: Compliance scan run is done running the scans
              reason: NotRunning
              status: 'False'
              type: Processing
            - lastTransitionTime: '2025-03-12T03:10:44Z'
              message: Compliance scan run is done and has results
              reason: Done
              status: 'True'
              type: Ready
          endTimestamp: '2025-03-12T03:10:44Z'
          phase: DONE
          remainingRetries: 3
          result: NON-COMPLIANT
          resultsStorage:
            name: ocp4-cis-node-worker
            namespace: openshift-compliance
          startTimestamp: '2025-03-12T03:09:22Z'

There are many ComplianceCheckResult after a compliance scan.

In our compliance run, there are around 279.

oc get ComplianceCheckResult -A | wc -l
        
        # 279

This example ComplianceCheckResult object contains information about the compliance check results for a specific compliance profile item.

instructions: |-
          To verify that the kubeadmin secret has been deleted, make sure
          that oc get secrets kubeadmin -n kube-system
          returns a NotFound error.
          Is it the case that the kubeadmin secret has not been deleted?
        metadata:
          annotations:
            compliance.openshift.io/last-scanned-timestamp: '2025-03-12T03:09:22Z'
            compliance.openshift.io/rule: kubeadmin-removed
          resourceVersion: '20396818'
          name: ocp4-cis-kubeadmin-removed
          namespace: openshift-compliance
          ownerReferences:
            - apiVersion: compliance.openshift.io/v1alpha1
              blockOwnerDeletion: true
              controller: true
              kind: ComplianceScan
              name: ocp4-cis
              uid: fd80670b-0782-4c11-ab04-42bd72a7dc54
          labels:
            compliance.openshift.io/check-severity: medium
            compliance.openshift.io/check-status: FAIL
            compliance.openshift.io/profile-guid: a230315d-3e4a-5b58-b00f-f96f1553e036
            compliance.openshift.io/scan-name: ocp4-cis
            compliance.openshift.io/suite: cis-compliance
        status: FAIL
        kind: ComplianceCheckResult
        rationale: |-
          The kubeadmin user has an auto-generated password and a self-signed certificate, and has effectively
        
          cluster-admin
        
          permissions; therefore, it's considered a security liability.
        id: xccdf_org.ssgproject.content_rule_kubeadmin_removed
        description: |-
          Ensure that the kubeadmin secret has been removed
          The kubeadmin user is meant to be a temporary user used for bootstrapping purposes. It is preferable to assign system administrators whose users are backed by an Identity Provider.
        
          Make sure to remove the user as described in the documentation ( https://docs.openshift.com/container-platform/latest/authentication/remove-kubeadmin.html )
        severity: medium
        apiVersion: compliance.openshift.io/v1alpha1

The ComplianceRemediation resource is used to define the remediation actions that should be taken when a compliance check fails.

apiVersion: compliance.openshift.io/v1alpha1
        kind: ComplianceRemediation
        metadata:
          annotations:
            compliance.openshift.io/xccdf-value-used: var-openshift-audit-profile
          resourceVersion: '20396576'
          name: ocp4-cis-audit-profile-set
          namespace: openshift-compliance
          ownerReferences:
            - apiVersion: compliance.openshift.io/v1alpha1
              blockOwnerDeletion: true
              controller: true
              kind: ComplianceCheckResult
              name: ocp4-cis-audit-profile-set
              uid: 59e647ba-8612-46b2-8864-42b3dd9c9fcc
          labels:
            compliance.openshift.io/scan-name: ocp4-cis
            compliance.openshift.io/suite: cis-compliance
        spec:
          apply: false
          current:
            object:
              apiVersion: config.openshift.io/v1
              kind: APIServer
              metadata:
                name: cluster
              spec:
                audit:
                  profile: WriteRequestBodies
          outdated: {}
          type: Configuration
        status:
          applicationState: NotApplied

There are 3 compliance remediations generated.

oc get ComplianceRemediation -A
        
        # NAMESPACE              NAME                                                             STATE
        
        # openshift-compliance   ocp4-cis-api-server-encryption-provider-cipher                   NotApplied
        
        # openshift-compliance   ocp4-cis-audit-profile-set                                       NotApplied
        
        # openshift-compliance   ocp4-cis-kubelet-configure-tls-cipher-suites-ingresscontroller   NotApplied

Generating Human-Readable Reports

While you can examine compliance results using the Kubernetes API and custom resources, it’s often more convenient to generate human-readable HTML reports for analysis and documentation purposes.

Extracting and Converting Scan Results

First, let’s check the PVC name that contains the report raw data.

Next, we define a pod to extract data from the PV. We run this pod in privileged mode to grant it access to the PV due to backend storage limitations. If your storage solution permits, remove the privileged mode.

apiVersion: "v1"
        kind: Pod
        metadata:
          name: pv-extract
        spec:
          # securityContext:
          #   runAsNonRoot: true
          #   seccompProfile:
          #     type: RuntimeDefault
          containers:
            - name: pv-extract-pod
              image: registry.access.redhat.com/ubi9/ubi
              command: ["sleep", "3000"]
              volumeMounts:
              - mountPath: "/workers-scan-results"
                name: workers-scan-vol
              securityContext:
                privileged: true
                # allowPrivilegeEscalation: true
                # allowPrivilegeEscalation: false
                # capabilities:
                #  drop: [ALL]
          volumes:
            - name: workers-scan-vol
              persistentVolumeClaim:
                claimName: ocp4-cis-node-master

You can create the pod easily using the webUI as follows:

On bastation machine, you can copy the files from the pod using the following command:

oc cp pv-extract:/workers-scan-results -n openshift-compliance .

On a rhel machine, copy the report raw data from bastation to local rhel machine, then you can use the following command to convert the bzip2 file into report html.


        # get command oscap
        
        dnf install -y openscap-scan
        
        
        # in the directory where you have the report.xml.bz2 file
        
        cat << 'EOF' > report.sh
        #!/bin/bash
        
        # Ensure that openscap is installed
        
        if ! command -v oscap &> /dev/null; then
          echo "Please install openscap first."
          exit 1
        fi
        
        # Loop through all .xml.bzip2 files in the current directory
        
        find . -maxdepth 1 -name "*.xml.bzip2" -print0 | while IFS= read -r -d $'\0' file; do
          # Get the filename (without extension)
          filename=$(basename "$file" .xml.bzip2)
        
          # Generate a unique output filename
          output_file="report_${filename}_$(date +%s).html"
        
          # Execute the oscap command to generate the report
          oscap xccdf generate report --output "$output_file" "$file"
        
          # Check if the command was executed successfully
          if [ $? -eq 0 ]; then
            echo "Generated report for $file: $output_file"
          else
            echo "Error generating report for $file."
          fi
        done
        
        echo "Processing complete."
        EOF
        
        bash report.sh
        
        # Generated report for ./openscap-pod-19994a9a1de267c235b347b8a6e1502b13ad99c0.xml.bzip2: report_openscap-pod-19994a9a1de267c235b347b8a6e1502b13ad99c0_1741357399.html
        
        # Generated report for ./openscap-pod-fd1520f0f9f45782bb20d55a348df304b6449965.xml.bzip2: report_openscap-pod-fd1520f0f9f45782bb20d55a348df304b6449965_1741357400.html
        
        # Generated report for ./openscap-pod-e25e31adc70c84fd0f2bc355e5d0221b8c655a58.xml.bzip2: report_openscap-pod-e25e31adc70c84fd0f2bc355e5d0221b8c655a58_1741357401.html
        
        # Generated report for ./openscap-pod-3baa2cb68109d2d1f3b6c3421be4b7e20c344692.xml.bzip2: report_openscap-pod-3baa2cb68109d2d1f3b6c3421be4b7e20c344692_1741357401.html
        
        # Processing complete.

Here are some sample report attached in this repo, you can check it out by download the html files and open them locally.

Remediating Compliance Issues (AIGC)

After running a compliance scan and reviewing the results, you’ll likely need to address any non-compliant items. The Compliance Operator provides mechanisms to help remediate these issues.

Understanding Remediations

For each failed check, the Compliance Operator may generate a ComplianceRemediation resource that contains the necessary configuration to fix the issue. These remediations can be applied manually or automatically.

Manual Remediation

When using the default ScanSetting, remediations are not applied automatically. You can review and apply them manually:

  1. List available remediations:

    oc get ComplianceRemediation -n openshift-compliance
  2. Review a specific remediation:

    oc get ComplianceRemediation <remediation-name> -n openshift-compliance -o yaml
  3. Apply a remediation by setting spec.apply to true:

    oc patch ComplianceRemediation <remediation-name> \
                --type merge \
                -p '{"spec":{"apply":true}}' \
                -n openshift-compliance

Automatic Remediation

If you want remediations to be applied automatically, use the default-auto-apply ScanSetting when creating your ScanSettingBinding:

apiVersion: compliance.openshift.io/v1alpha1
        kind: ScanSettingBinding
        metadata:
          name: auto-apply-compliance
          namespace: openshift-compliance
        profiles:
          - name: ocp4-cis
            kind: Profile
            apiGroup: compliance.openshift.io/v1alpha1
        settingsRef:
          name: default-auto-apply
          kind: ScanSetting
          apiGroup: compliance.openshift.io/v1alpha1

Best Practices for Compliance Management

  1. Start with a baseline scan: Begin with a standard profile like ocp4-cis to establish a baseline compliance status.

  2. Create TailoredProfiles for customization: If the standard profiles don’t meet your exact needs, create TailoredProfiles to customize which rules are included and how variables are set.

  3. Schedule regular scans: Use the schedule field in ScanSettings to run scans on a regular basis (e.g., daily or weekly).

  4. Implement a remediation strategy: Decide whether to use automatic or manual remediation based on your organization’s change management policies.

  5. Document exceptions: For rules that cannot be remediated due to business requirements, document the exceptions and the compensating controls.

  6. Generate and archive reports: Regularly generate HTML reports and archive them for audit purposes.

  7. Monitor for drift: After achieving compliance, continue scanning to detect any drift from the compliant state.

  8. Test remediations in non-production first: Before applying remediations in production, test them in a non-production environment to ensure they don’t cause unintended consequences.

Conclusion (AIGC)

The Compliance Operator is a powerful tool for ensuring your OpenShift cluster meets security standards and compliance requirements. By understanding its components and workflow, you can effectively scan, report on, and remediate compliance issues in your environment.

end