The ComplianceAsCode project provides security guidance, baselines, and associated validation mechanisms utilizing the Security Content Automation Protocol (SCAP) to achieve security hardening for various products. ComplianceAsCode provides content for Red Hat OpenShift to comply with the requirements set by local government regulations and industry standards required for deploying the solution.

The ComplianceAsCode content follows the SCAP format to help translate the generic requirements set by the regulatory frameworks into implementation specifics and automate the remediations where possible. Refer to the SCAP Security Guide for more information on SCAP format.

ComplianceAsCode content guide provides the best practices and security relevant configuration guidelines to securely configure the Red Hat OpenShift Container Platform system. The guidelines written in SCAP format consists of two parts:

  • Rules: Rules are written specific to a configuration setting with the automated remediation or the suggested remediation when the configuration item is not in desired state during compliance audit. Rules are described per the XCCDF standard in YAML format. Rules contain the checks written in OVAL format to verify the configuration setting and remediations when the configuration setting is not as suggested. Remediations can be executed on Ansible, Bash, Anaconda Installer, Puppet, and for OpenShift on ignition and Kubernetes.
  • Profiles and Controls: Profiles and Controls are product-specific and groups the selected rules to align with a specific compliance or regulatory standard.

Writing a rule

The top level of the ComplianceAsCode content repository has directories created for different products and applications/openshift is for OpenShift, which contains rules in subdirectories grouped by components.

├── accounts
├── api-server
├── authentication
├── controller
├── etcd
├── general
├── integrity
├── kubelet
├── logging
├── master
├── networking
├── openshift-api-server
├── rbac
├── registry
├── risk-assessment
├── scc
├── scheduler
├── secrets
└── worker

Create a directory for the rules in the matching component directory (e.g., registry). Directory naming follows snake casing and is referred to as rule ID.

├── approved_registries
├── image_pruner_active
├── image_scanning
├── imagestream_sets_schedule
├── ocp_allowed_registries
├── ocp_allowed_registries_for_import
├── ocp_insecure_allowed_registries_for_import
├── ocp_insecure_registries
├── read_only_registry_access
└── registry_access

Each rule directory must contain rule.yml which contains details on the desired state of a configuration item. Rules should be written for a single configuration item. Complex configurations must be separated into smaller parts as independent rules. A rule can also contain the following subdirectories when required.

  • Tests: Contain the unit tests for the rule. Bash scripts are used for setting the configurations to check the various scenarios. The following is an example test script that sets a configuration value:
    # remediation = none
    mkdir -p /kubernetes-api-resources/apis/<api_name>/<api_version>/namespaces/<namespace_name>/<api_kind>
    cat << EOF > /kubernetes-api-resources/apis/<api_name>/<api_version>/namespaces/<namespace_name>/<api_kind>/<object_name>

Specifying remediation = none in a comment informs the test framework that remediation is not expected for the rule. The test framework patches the yaml content present in the /kubernetes-api-resources/apis directory and checks the rules against it.

  • Kubernetes: Contains the remediation to apply when the configuration set is not as desired in the shared.yml, which is a Kubernetes manifest patched to update the configuration setting.
  • Oval: Contains the shared.xml which follows custom OVAL syntax for OR-ing rules, which can be used to break down complex rules into smaller rules and OVAL checks for the smaller rules for validating the actual rule. Each smaller rule should have its own rule directory the same as all other rules, including its own tests and remediations.
  • Policy: Contains details of the regulatory policy for which the rule is created.

Rule sections

The rule.yml contains attributes in the following order:

  1. documentation_complete: Boolean value (true or false) indicating the documentation of the rule.
  2. prodtype: Product type for which the rule is valid. It will be ocp4 for Red Hat OpenShift Container Platform 4.
  3. title: The title for the rule must be in title case. It is similar to the expanded version of rule ID.
  4. description: HTML-like description of the rule, including the reason, details of the configuration parameter with the documentation link, command to check the configuration, and update the configuration to desired value.
  5. rationale: HTML-like description of the reason why the rule exists and the importance of setting the configuration as suggested.
  6. severity: Severity of the rule based upon the importance of improperly setting the configuration correctly.
  7. identifiers: Common Configuration Enumeration Identifiers (CCE ID) for the rule.
  8. cce@ocp4: Unique identifier to a compliance rule used for mapping it to the product (i.e., OCP). Pick an ID from the list of pre-generated IDs in shared/references/cce-redhat-avail.txt and delete the used ID to avoid reuse for other rules.
  9. references: References to the compliance or regulatory standards (e.g., NIST, SRG, DISA) to which the rule applies.
  10. ocil_clause: A statement which indicates the rule is valid and the system is not in a desired state.
  11. ocil: HTML-like description with details to check whether the rule is valid. It can contain the commands to assert the findings and the desired state.
  12. template: Predefined templates that can be used for checking the configurations. The yamlfile_value can be used for checking OpenShift configurations, which checks for a value in a YAML at a given path.
    • yamlfile_value: Supports the following parameters used for writing the checks.
      • ocp_data: Accept boolean value when set to true, file path would be treated as path in OCP yaml configuration dump.
      • filepath: Full path of the configuration file such as: /apis/<api_type>/<api_version>/namespaces/<namespace_name>/<api_kind>/<object_name>
      • filepath_suffix: The suffix to the file path.
      • yaml_path: The YAML path of the configuration parameter under check. (e.g., .spec.<parameter_name>).
      • entity_check: Check the results of the values and decide the final outcome (e.g. all means all the results of values must be true to say check met the conditions). Possible options are all, at least one, none satisfy and only one.
      • check_existence: Check that the values exist.
      • xccdf_variable: Use the XCCDF variable selector field if the comparison involves checking for a value selected by a XCCDF variable.

Define and set a default value for a variable as follows for the file (var_kubelet_tls_min_version_regex.var) in the component directory or as relevant based on the variable scope.

documentation_complete: true

title: 'Configure Kubelet to use secure TLS version'

description: 'TLS versions available for configuring Kubelet, excluding insecure versions'

type: string

operator: equals

interactive: false

  default: "^(?!VersionTLS10|VersionTLS11)"
  • regex_data: If set to true and combined with the xccdf_variable, it will use the value of the xccdf_variable as a regex and does a pattern match operation instead of equal operation.
  • values: A list of values to check.
    • key: This is the yaml key to check when the configuration parameter holds map data type.
    • value: The value to check, which can be a regex too.
    • type: The datatype of the field.
    • operation: This is the operation value. Most common operations are: equals, not equal, pattern match, greater than or equal, and less than or equal.

The following is an example of a rule.yml file:

documentation_complete: true

prodtype: ocp4

title: "Ensure custom tlsSecurityProfile configured for IngressController uses secure TLS version"

description: |-
    The configuration <tt>tlsSecurityProfile</tt> specifies TLS configurations
    to be used while establishing connections with the externally exposed
    servers. Though secure transport mode is used for establishing connections,
    the protocols used may not always be strong enough to avoid interception and
    manipulation of the data in transport. When Custom TLS Security profile is 
    used it's always better to configure TLS version 1.2 or newer to avoid any
    security breaches.

    Update minTLSVersion configured in Custom tlsSecurityProfile using the following command:
    {{% raw %}}<pre>oc patch -n openshift-ingress-operator default --type 'merge' --patch '{"spec":{"tlsSecurityProfile":{"custom":{"minTLSVersion":"VersionTLS12"}}}}'</pre>{{% endraw %}}

    For more information, follow
    OpenShift documentation:
    {{{ weblink(link="",
                text="the relevant documentation") }}}.

rationale: |-
    The authenticity and integrity of the container platform and communication
    between nodes and components must be secure. If an insecure protocol,
    cipher, or algorithms is used, during transmission of data, the data can be
    intercepted and manipulated. To thwart the manipulation of the data during
    transmission secure protocol, cipher and algorithms must be used.

severity: medium

    cce@ocp4: CCE-86323-3

    nist: SC-8,SC-8(1)
    srg: SRG-APP-000014-CTR-000040

ocil_clause: 'insecure TLS version configured in the Custom tlsSecurityProfile used for accessing external services'

ocil: |-
    To check for the configured tlsSecurityProfile use below command:
    <tt>$ oc get -n openshift-ingress-operator default -o jsonpath='{.spec.tlsSecurityProfile.custom.minTLSVersion}{"\n"}'</tt>
    The output shows the minTLSVersion configured in Custom tlsSecurityProfile
    for IngressController, which should be TLSv1.2 or newer.

    - general: |-
        {{{ openshift_cluster_setting("/apis/") | indent(8) }}}

    name: yamlfile_value
        ocp_data: "true"
        filepath: "/apis/"
        yamlpath: ".spec.tlsSecurityProfile.custom.minTLSVersion"
        check_existence: "any_exist"
            - value: "^(?!VersionTLS10|VersionTLS11)"
              operation: "pattern match"