When I started working with a financial services customer on their Red Hat OpenShift governance posture, the technical compliance checks were solid, withNational Institute of Standards and Technology (NIST) 800-53, Payment Card Industry Data Security Standard (PCI DSS), and Center for Internet Security (CIS) Benchmark scans running reliably via the OpenShift compliance operator. But there was a persistent frustration: the ComplianceCheckResult objects coming out of the operator were islands. They told you what failed, but not what it meant to the business.
Their security team had internal severity ratings differing from the compliance operator's security content defaults. Their service management team tracked every finding against a ServiceNow ticket or internal audit system. Auditors needed references to internal control identifiers mapping regulations to specific checks. None of that context survived the scan boundary. The result was a painful, manual enrichment step before any result could flow into dashboards or downstream Security Information and Event Management (SIEM) tooling.
This gap shows up across enterprises. The compliance operator is a Kubernetes-native scanner, but compliance programs don't live in Kubernetes; instead, they live in Governance, Risk, and Compliance (GRC) tools, audit spreadsheets, ticketing systems, and custom dashboards. The missing link was a way to carry your organization's metadata alongside the operator's results.
This gap becomes visible only in the field. You can design a scanner to be technically correct and still have it fall short of what real compliance programs need day to day. I raised this with the compliance operator engineering team as a concrete customer requirement—not a feature wish, but a documented pain point that directly hindered automation and auditability. What followed was a tight feedback loop: field observation, engineering discussion, design, and implementation. That cycle, where Consulting identifies what customers hit in production and Engineering turns it into a durable platform capability, is one of the most direct ways customer experience shapes the product roadmap.
I'm happy to share the result of this collaboration is now available: the compliance operator supports custom metadata propagation on ComplianceCheckResult objects, letting you attach business-specific labels and annotations directly to the Rule objects driving your scans. When a scan runs, that metadata flows automatically onto every result without post-processing, lookup tables, or manual enrichment steps.
The problem: Compliance results without business context
The ComplianceCheckResult custom resource already carries useful system-generated metadata. Labels such as compliance.openshift.io/check-status, compliance.openshift.io/check-severity, and compliance.openshift.io/suite are automatically applied by the operator and can be used to filter and query results. For example:
$ oc get compliancecheckresults -n openshift-compliance \
-l 'compliance.openshift.io/check-status=FAIL,compliance.openshift.io/check-severity=high'But all those labels are generated from the compliance content in ProfileBundle objects. There was no mechanism to inject your own metadata: no way to say “this check maps to internal control ID CTL-0042,” or “the business severity for this finding is P1,” or “findings from this scan should route to ticket queue SEC-INFRA.”
This created a major downstream operational burden. Teams building dashboards in Grafana, Splunk, or ServiceNow had to maintain secondary lookup tables to re-enrich the results after the fact. Any time a scan was rerun or a new cluster was onboarded, that enrichment had to be reapplied manually. Automation was fragile because the correlation was external to the resource.
How custom metadata propagation bridges the gap
The new capability lets you annotate and label the Rule objects making up a compliance profile. When the compliance operator runs a scan and produces ComplianceCheckResult objects, it automatically propagates any custom labels and annotations present on the source Rule onto the corresponding result.
This means the enrichment is tied to the rule itself, not the scan configuration. A rule labeled with business-unit=wire-transfer will produce results carrying that label regardless of which ScanSetting or ScanSettingBinding triggers the scan. Rescans pick up the metadata automatically, and any downstream tool reading ComplianceCheckResult objects receives the business context without any additional transformation step.
The metadata propagation respects Kubernetes conventions: you can attach both labels (for filtering and selector queries) and annotations (for richer, longer-form metadata such as ticket references, control IDs, or descriptions).
How it works: Annotating Rule objects directly
The key insight is that enrichment happens at the Rule level, not the scan level. Rule objects are the parsed compliance checks loaded from a ProfileBundle, with one Rule per compliance check. When the operator generates ComplianceCheckResult objects after a scan, it copies any custom labels and annotations present on the source Rule directly onto the result.
You annotate the rule once, and every subsequent scan evaluating that rule automatically produces enriched results, regardless of profile, ScanSetting, or schedule.
Let's walk through the complete workflow using a real example from a payments platform team.
Step 1: Verify compliance operator version
Check the installed version before proceeding:
$ oc get csv -n openshift-compliance | grep complianceThis feature requires compliance operator 1.9.0 or later.
Step 2: Apply business labels and annotations to a Rule
First, identify the Rule object you want to enrich. Rules are named using the pattern <profile>-<rule-name> and live in the openshift-compliance namespace:
$ oc get rules -n openshift-compliance | grep accounts-no-clusterApply labels for dimensions you'll filter or query on, such as business unit, organization, and risk tier:
$ oc label rule ocp4-accounts-no-clusterrolebindings-default-service-account \
business-unit=wire-transfer \
business-org=payments \
risk-tier=critical \
-n openshift-compliance
rule.compliance.openshift.io/ocp4-accounts-no-clusterrolebindings-default-service-account labeledApply annotations for richer metadata not required to be a selector, including internal control IDs, ticket references, and audit identifiers:
$ oc annotate rule ocp4-accounts-no-clusterrolebindings-default-service-account \
my-org.io/internal-control-id=CTL-0042 \
my-org.io/csi-id=CSI-123 \
-n openshift-compliance
rule.compliance.openshift.io/ocp4-accounts-no-clusterrolebindings-default-service-account annotatedStep 3: Create a ScanSettingBinding (if one doesn't already exist)
If no scan is configured for the target profile yet, create a ScanSettingBinding to bind the profile to a ScanSetting. Creating the binding immediately triggers the first scan:
$ cat <<'EOF' | oc apply -f -
apiVersion: compliance.openshift.io/v1alpha1
kind: ScanSettingBinding
metadata:
name: ocp4-bsi-scan
namespace: openshift-compliance
profiles:
- apiGroup: compliance.openshift.io/v1alpha1
kind: Profile
name: ocp4-bsi
settingsRef:
apiGroup: compliance.openshift.io/v1alpha1
kind: ScanSetting
name: default
EOF
scansettingbinding.compliance.openshift.io/ocp4-bsi-scan createdStep 4: Verify the scan is running
Check that the ScanSettingBinding is ready and the underlying ComplianceScan was created and has started:
$ oc get ssb -n openshift-compliance
NAME STATUS
ocp4-bsi-scan READY
$ oc get compliancescan -n openshift-compliance
NAME PHASE RESULT
ocp4-bsi RUNNING NOT-AVAILABLEWait for the scan to complete:
$ oc get compliancescan -n openshift-compliance
NAME PHASE RESULT
ocp4-bsi DONE NON-COMPLIANTStep 5: Trigger a rescan (if a binding already existed)
If a ScanSettingBinding was already in place and you added metadata to rules after the last scan, trigger a rescan manually rather than waiting for the next scheduled run:
$ oc annotate compliancescan ocp4-bsi \
compliance.openshift.io/rescan= \
-n openshift-complianceStep 6: Query results using your custom labels
Once the scan completes, the ComplianceCheckResult objects for rules you enriched are immediately queryable by your custom label selectors:
$ oc get compliancecheckresults \
-l business-unit=wire-transfer \
-n openshift-compliance
NAME STATUS SEVERITY
ocp4-bsi-accounts-no-clusterrolebindings-default-service-account PASS mediumStep 7: Inspect the propagated annotations on a result
Verify your custom annotations from the Rule are present on the result:
$ oc get compliancecheckresult \
ocp4-bsi-accounts-no-clusterrolebindings-default-service-account \
-n openshift-compliance \
-o json | jq -r '.metadata.annotations | to_entries[] | "\(.key)=\(.value)"'
compliance.openshift.io/last-scanned-timestamp=2026-06-04T15:17:23Z
compliance.openshift.io/rule=accounts-no-clusterrolebindings-default-service-account
control.compliance.openshift.io/BSI=APP.4.4.A9
my-org.io/csi-id=CSI-123
my-org.io/internal-control-id=CTL-0042
policies.open-cluster-management.io/controls=APP.4.4.A9
policies.open-cluster-management.io/standards=BSIStep 8: Inspect the propagated labels on a result
Similarly, verify the custom labels propagated from the Rule:
$ oc get compliancecheckresult \
ocp4-bsi-accounts-no-clusterrolebindings-default-service-account \
-n openshift-compliance \
-o json | jq -r '.metadata.labels | to_entries[] | "\(.key)=\(.value)"'
business-org=payments
business-unit=wire-transfer
compliance.openshift.io/check-severity=medium
compliance.openshift.io/check-status=PASS
compliance.openshift.io/profile-guid=5c86fe2e-cf42-5a6f-9301-35f26d0bd1e2
compliance.openshift.io/scan-name=ocp4-bsi
compliance.openshift.io/suite=ocp4-bsi-scan
risk-tier=criticalYour custom metadata sits alongside the system-generated labels. Both the operator's standard fields and your business context are now part of the same resource, queryable with standard Kubernetes tooling.
Viewing enriched results downstream
The value of this feature compounds when results flow into downstream tooling. Because the metadata is on the Kubernetes resource itself, rather than in a sidecar database or lookup table, any tool reading ComplianceCheckResult objects automatically receives the enriched data. Prometheus exporters, SIEM connectors, Red Hat Advanced Cluster Management for Kubernetes policy engines, and custom controllers all benefit without any additional plumbing.
Filtering by custom labels
You can filter results using your own label selectors directly with oc:
# All wire-transfer failures, regardless of which profile found them
$ oc get compliancecheckresults -n openshift-compliance \
-l 'compliance.openshift.io/check-status=FAIL,business-unit=wire-transfer'
# All critical-risk-tier results across the payments org
$ oc get compliancecheckresults -n openshift-compliance \
-l 'business-org=payments,risk-tier=critical'Because labels follow the standard Kubernetes label selector model, these queries compose freely with the system-generated labels. You can mix and match your business labels with operator-managed ones such as compliance.openshift.io/check-severity in a single selector.
Inspecting annotations for rich metadata
Annotations carry the longer-form identifiers, such as internal control IDs, CSI references, ticket numbers, that don't fit cleanly into label values. You can extract them for any result using jq:
$ oc get compliancecheckresult \
ocp4-bsi-accounts-no-clusterrolebindings-default-service-account \
-n openshift-compliance \
-o json | jq -r '.metadata.annotations | to_entries[] | "\(.key)=\(.value)"'
my-org.io/csi-id=CSI-123
my-org.io/internal-control-id=CTL-0042These values are available to any downstream process fetching the resource, such as a webhook, an Ansible playbook, a custom operator, or an external integration.
Integration with Red Hat Advanced Cluster Management
If you're managing multiple clusters with Red Hat Advanced Cluster Management, ComplianceCheckResult objects are surfaced through the Red Hat Advanced Cluster Management governance framework. Custom labels and annotations on results flow through to the Red Hat Advanced Cluster Management policy reporting layer, giving you a unified view of your business-context compliance posture across your entire fleet.
GitOps and policy-as-code workflows
Because Rule objects are Kubernetes resources, you can manage their labels and annotations directly within your existing GitOps pipelines.
Store your label and annotation definitions as patch files in a Git repository and apply them via Argo CD or Red Hat OpenShift GitOps. When your control mapping changes due to a new audit cycle or a restructured organization, update the patch file and your next scan automatically reflects the updated business context.
Real-world use cases
Here are three patterns emerging directly from customer conversations:
Mapping compliance findings to internal controls
Large regulated organizations (financial services, healthcare, government) maintain internal control frameworks not mapping 1:1 to NIST, CIS, or PCI DSS rule IDs. By attaching a label such as internal-control-id pointing to the matching control in your GRC framework, you establish a direct connection. It's a one-time mapping exercise across the rule catalog, but once it's done, every scan result flowing out carries the control ID with it. Downstream audit systems read those labels directly to correlate findings to controls, requiring no extract, transform, load (ETL) step, and no lookup tables to maintain.
Routing findings to the right team automatically
Multi-team platform engineering organizations can attach a team or ticket-queue label to rules. An automated controller or webhook reads FAIL results and opens tickets in the appropriate team without human triage. This pattern extends naturally across clusters. In a fleet with separate development, staging, and production clusters, the same rule can carry different environment or cluster-tier labels. A FAIL in production routes to the on-call queue with higher severity, while the same finding in development lands in the team's regular backlog. The routing logic stays in one place (labels on the rule), and the controller handles the rest regardless of whether you're operating one cluster or 50.
Supporting multi-cycle audits
Many organizations run overlapping audit cycles, such as quarterly reviews, annual certifications, and regulatory reassessments, against the same cluster. By parameterizing the audit-cycle=Q2-2026 or audit-cycle=SOC-2026 label on rules, you support tagging every finding automatically with its assessment period. This eliminates the need for additional steps in correlation tables or complex timestamp logic: dashboards and controllers can filter by audit cycle using standard Kubernetes label selectors to track remediation progress, compare posture across cycles, or generate audit-specific reports.
Getting started
The custom metadata propagation capability is available in compliance operator 1.9.0 and later. To get started:
- Upgrade to compliance operator 1.9.0 or later via OperatorHub or your GitOps pipeline.
- Define your metadata schema by agreeing on key naming conventions using a domain-scoped prefix (for example,
my-org.io/,security.acme.io/). Use labels for values you'll filter on; use annotations for richer identifiers such as control IDs and ticket references. - Identify the
Ruleobjects you want to enrich withoc get rules -n openshift-compliance. - Apply labels and annotations to those
Ruleobjects usingoc labelandoc annotate. - Run or rescan by creating a
ScanSettingBindingif one doesn't exist, or triggering a rescan with thecompliance.openshift.io/rescan=annotation on the existingComplianceScan. - Verify
ComplianceCheckResultobjects carry your custom metadata, then update downstream tooling to use the new label and annotation dimensions.
For full documentation, see the OpenShift compliance operator documentation.
The compliance data generated by the compliance operator has always been detailed and accurate. This enhancement closes the loop by making that data contextual, meaning the people and tools that use it can act on it without a secondary enrichment pass. For teams operating at scale across many clusters, that's a meaningful reduction in operational overhead and a step toward truly automated compliance-to-action pipelines.
We would love to hear how your team is structuring metadata to automate compliance. If you've built custom workflows or want to share your feedback, join the conversation in the Red Hat OpenShift Commons or share your thoughts with us on the Red Hat Customer Portal.