Open tmishina opened 3 years ago
I think count function of OVAL dictionary can be used, but current yamlfile content test does not support including additional elements like count.
@evgenyz Could you help us embed count
into template or raw OVAL rule definition? ind:yamlfilecontent_object
(in the small set example below) is the point?
<?xml version="1.0"?>
<ds:data-stream-collection xmlns:cat="urn:oasis:names:tc:entity:xmlns:xml:catalog" xmlns:cpe-dict="http://cpe.mitre.org/dictionary/2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:ds="http://scap.nist.gov/schema/scap/source/1.2" xmlns:html="http://www.w3.org/1999/xhtml" xmlns:ind="http://oval.mitre.org/XMLSchema/oval-definitions-5#independent" xmlns:linux="http://oval.mitre.org/XMLSchema/oval-definitions-5#linux" xmlns:ocil="http://scap.nist.gov/schema/ocil/2.0" xmlns:oval="http://oval.mitre.org/XMLSchema/oval-common-5" xmlns:oval-def="http://oval.mitre.org/XMLSchema/oval-definitions-5" xmlns:unix="http://oval.mitre.org/XMLSchema/oval-definitions-5#unix" xmlns:xccdf-1.2="http://checklists.nist.gov/xccdf/1.2" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" id="scap_org.open-scap_collection_from_xccdf_ssg-ocp4-xccdf-1.2.xml" schematron-version="1.3">
<ds:component id="scap_org.open-scap_comp_ssg-ocp4-oval.xml" timestamp="2021-01-13T03:46:40">
<oval-def:oval_definitions xsi:schemaLocation="http://oval.mitre.org/XMLSchema/oval-common-5 oval-common-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5 oval-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#independent independent-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#unix unix-definitions-schema.xsd http://oval.mitre.org/XMLSchema/oval-definitions-5#linux linux-definitions-schema.xsd">
<oval-def:definitions>
<oval-def:definition class="compliance" id="oval:ssg-kubelet_configure_tls_cipher_suites_ingresscontroller:def:1" version="1">
<oval-def:metadata>
<oval-def:title>Ensure that the Kubelet only makes use of Strong Cryptographic Ciphers</oval-def:title>
<oval-def:affected family="unix">
<oval-def:platform>Red Hat OpenShift Container Platform 4</oval-def:platform>
</oval-def:affected>
<oval-def:description>In the YAML/JSON file '/apis/operator.openshift.io/v1/namespaces/openshift-ingress-operator/ingresscontrollers/default' at path '.status.tlsProfile.ciphers[:]' all: value equals '^(ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-RSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-RSA-AES256-GCM-SHA384|ECDHE-RSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES256-GCM-SHA384|AES256-GCM-SHA384|AES128-GCM-SHA256)$'</oval-def:description>
<oval-def:reference ref_id="kubelet_configure_tls_cipher_suites_ingresscontroller" source="ssg"/>
</oval-def:metadata>
<oval-def:criteria>
<oval-def:criterion comment="In the YAML/JSON file '/apis/operator.openshift.io/v1/namespaces/openshift-ingress-operator/ingresscontrollers/default' at path '.status.tlsProfile.ciphers[:]' all" test_ref="oval:ssg-test_kubelet_configure_tls_cipher_suites_ingresscontroller:tst:1"/>
<oval-def:criterion comment="Make sure that the file '/apis/operator.openshift.io/v1/namespaces/openshift-ingress-operator/ingresscontrollers/default' exists." test_ref="oval:ssg-test_file_for_kubelet_configure_tls_cipher_suites_ingresscontroller:tst:1"/>
</oval-def:criteria>
</oval-def:definition>
</oval-def:definitions>
<oval-def:tests>
<ind:yamlfilecontent_test id="oval:ssg-test_kubelet_configure_tls_cipher_suites_ingresscontroller:tst:1" check="all" check_existence="only_one_exists" comment="In the file '/apis/operator.openshift.io/v1/namespaces/openshift-ingress-operator/ingresscontrollers/default' find only one object at path '.status.tlsProfile.ciphers[:]'." version="1">
<ind:object object_ref="oval:ssg-object_kubelet_configure_tls_cipher_suites_ingresscontroller:obj:1"/>
<ind:state state_ref="oval:ssg-state_kubelet_configure_tls_cipher_suites_ingresscontroller:ste:1"/>
</ind:yamlfilecontent_test>
<unix:file_test id="oval:ssg-test_file_for_kubelet_configure_tls_cipher_suites_ingresscontroller:tst:1" check="all" check_existence="only_one_exists" comment="Find the file to be checked ('/apis/operator.openshift.io/v1/namespaces/openshift-ingress-operator/ingresscontrollers/default')." version="1">
<unix:object object_ref="oval:ssg-object_file_for_kubelet_configure_tls_cipher_suites_ingresscontroller:obj:1"/>
</unix:file_test>
</oval-def:tests>
<oval-def:objects>
<unix:file_object id="oval:ssg-object_file_for_kubelet_configure_tls_cipher_suites_ingresscontroller:obj:1" version="1">
<unix:filepath var_ref="oval:ssg-kubelet_configure_tls_cipher_suites_ingresscontroller_file_location:var:1"/>
</unix:file_object>
<ind:yamlfilecontent_object id="oval:ssg-object_kubelet_configure_tls_cipher_suites_ingresscontroller:obj:1" version="1">
<ind:filepath var_ref="oval:ssg-kubelet_configure_tls_cipher_suites_ingresscontroller_file_location:var:1"/>
<ind:yamlpath>.status.tlsProfile.ciphers[:]</ind:yamlpath>
</ind:yamlfilecontent_object>
</oval-def:objects>
<oval-def:states>
<ind:yamlfilecontent_state id="oval:ssg-state_kubelet_configure_tls_cipher_suites_ingresscontroller:ste:1" version="1">
<ind:value datatype="record">
<oval-def:field name="#" operation="pattern match">^(ECDHE-ECDSA-AES128-GCM-SHA256|ECDHE-RSA-AES128-GCM-SHA256|ECDHE-ECDSA-CHACHA20-POLY1305|ECDHE-RSA-AES256-GCM-SHA384|ECDHE-RSA-CHACHA20-POLY1305|ECDHE-ECDSA-AES256-GCM-SHA384|AES256-GCM-SHA384|AES128-GCM-SHA256)$</oval-def:field>
</ind:value>
</ind:yamlfilecontent_state>
</oval-def:states>
<oval-def:variables>
<oval-def:local_variable id="oval:ssg-kubelet_configure_tls_cipher_suites_ingresscontroller_file_location:var:1" datatype="string" comment="The actual path of the file to scan." version="1">
<oval-def:concat>
<oval-def:variable_component var_ref="oval:ssg-ocp_data_root:var:1"/>
<oval-def:literal_component>/apis/operator.openshift.io/v1/namespaces/openshift-ingress-operator/ingresscontrollers/default</oval-def:literal_component>
</oval-def:concat>
</oval-def:local_variable>
</oval-def:variables>
</oval-def:oval_definitions>
</ds:data-stream-collection>
Okay, so you want to count how many elements of the array were returned in the object oval:ssg-object_kubelet_configure_tls_cipher_suites_ingresscontroller:obj:1
, right?
Here is the test (variable test oval:0:tst:6
) which would make sure that record oval:ssg-object_kubelet_configure_tls_cipher_suites_ingresscontroller:obj:1
has 4 name="#"
fields
(see <ind-def:value>4</ind-def:value>
in oval:0:ste:7
).
I know that OVAL can be brain-damaging, don't hesitate to ask for explanation.
Also, are you sure that it is a good idea to count array elements?
<ind-def:variable_test version="1" id="oval:0:tst:6" check="all">
<ind-def:object object_ref="oval:0:obj:7"/>
<ind-def:state state_ref="oval:0:ste:7"/>
</ind-def:variable_test>
<ind-def:variable_object version="1" id="oval:0:obj:7">
<ind-def:var_ref>oval:0:var:4</ind-def:var_ref>
</ind-def:variable_object>
<ind-def:variable_state version="1" id="oval:0:ste:7">
<ind-def:var_ref>oval:0:var:4</ind-def:var_ref>
<ind-def:value>4</ind-def:value>
</ind-def:variable_state>
<local_variable comment="var" datatype="int" version="1" id="oval:0:var:4">
<count>
<object_component object_ref="oval:ssg-object_kubelet_configure_tls_cipher_suites_ingresscontroller:obj:1" item_field="value" record_field="#"/>
</count>
</local_variable>
@evgenyz Thank you, I'm now clearer about how I can use the count function.
Here let me use concrete example - section 5.1.3 of CIS Benchmark for OpenShift.
It requires minimizing the number of wildcard roles. Example of a rule with wildcard is as follows (there are two rules containing *
).
items:
- apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: admin
rules:
- apiGroups:
- packages.operators.coreos.com
resources:
- packagemanifests
verbs:
- '*'
- apiGroups:
- admissionregistration.k8s.io
resources:
- mutatingwebhookconfigurations
verbs:
- '*'
...
I think the rule should count the number of wildcard rules and warn user if the number excesses some threshold.
To count the wildcard roles with curl
, we can use following command.
$ curl -H "Authorization: Bearer $(oc whoami -t)" "https://$(KUBE_API_SERVER)/apis/rbac.authorization.k8s.io/v1/clusterroles" | jq .items[].rules[].verbs[] | sort | uniq -c
28 "*"
...
My strategy was:
yamlfile_value
(without counting)To get wildcard roles using yamlfile_value
, the rule (without considering counting) would be as follows.
template:
name: yamlfile_value
vars:
ocp_data: "true"
filepath: 'apis/rbac.authorization.k8s.io/v1/clusterroles'
yamlpath: ".items[:].rules[:].verbs[:]"
values:
- value: '\*'
operation: 'pattern match'
Before adding counting function, I tried to run this check. Result is: the API resource collector fails to save multiple clusterrole
resources.
I imagine this kind of multiple resource collection has not implemented yet (there are some commented out rules using such multiple collection). Single resource check (like below) works file, but it does not achieve what we want to check.
template:
name: yamlfile_value
vars:
ocp_data: "true"
filepath: '/apis/rbac.authorization.k8s.io/v1/clusterroles/admin'
yamlpath: ".rules[61].verbs[0]"
values:
- value: '\*'
operation: 'pattern match'
Do you or your colleagues know how to solve this multiple-resource collection issue?
There are two issues on Compliance Operator to implement section 5.x rules.
Assume that there are two rules and they attempt to collect following resources.
When rule 1 is performed, the resource is stored in /kubernetes-api-resources/apis/rbac.authorization.k8s.io/v1/clusterroles/admin
.
And then rule 2 attempts to save a resource to /kubernetes-api-resources/apis/rbac.authorization.k8s.io/v1/clusterroles
, it will fail because there already exists a directory. This error does not happen when only rule 2 is selected.
With yamlfile_value
template, multiple entries can be specified like yamlpath: ".items[:].rules[:].verbs[:]"
(this path is to check the wildcard rule - 5.1.3).
When null entry exists in the traversing, the check will fail.
For example, following json returns error, not ["read"]
. I think it is difficult to avoid this error as jq
also returns error, but I'd like to get result ["read"]
.
{
"items": [
{
"rules": [
{
"verbs": [
"read"
]
}
]
},
{
"rules": null
}
]
}
In my understanding, we need to update Compliance Operator. Does anyone know the way to avoid these errors? or do I need to propose enhancements to Compliance Operator?
In theory yaml probe could be adjusted to treat null
as an empty array (or map, dep. on context), but I'm not sure if it won't bring other unwanted side-effects.
What are the results for .items[:].rules[:]
path in that case?
It may be an empty array (map) for null
. In my case I want to enumerate verbs (e.g., ["delete", "create",...'
) and honestly I have not yet thought about the side-effect.
{
"apiGroups": [
"operators.coreos.com"
],
"resources": [
"subscriptions"
],
"verbs": [
"create",
"update",
"patch",
"delete"
]
}
{
}
^^^^ empty
...
@yuumasato is this still valid
Not sure if this exact issue is valid, but it is still relevant.
CIS 1.6.0 sections 5.1.x
and5.2.x
are MANUAL
.
cc: @rhmdnd @Vincent056
Which products and profiles does the rule apply to?
Describe the configuration setting enforced by this rule.
Rules in section 5 of CIS Benchmark for Kubernetes (OpenShift) (Control 5.1.2-5.1.4, 5.2.1-5.2.9) which require counting the number of elements in YAML files. Count the number of elements, and compare them with predefined constants.
Why is the configuration security relevant?
The numbers of the configurations should be minimized to reduce security risks; for example, the grater number of wildcard role (section 5.1.3) indicates higher security risk.
How to check the configuration?
Get resources of kubernetes, count the number of specific elements in the resources and check whether the number is grater than a predefined constant value.
Is it order dependent? (does it need to be at certain place in the file?)
No.
What is correct and incorrect syntax?
(N/A)
How to remediate
(TBD; Automated remediation is difficult)
Does any command need to be run?
api-resource-collector
of Compliance Operator will be used to fetch kubernetes resources.Are there going to be other rules like this one in the future? Is it worth creating template? (similar configuration format, similar remediation process...)
Yes; a number of rules may use this type of rule.
Are there any caveats to be considered when testing?
(TBD)
Is the configuration loaded directly by the or is it stored in some intermediate database (similar to dconf)?
api-resource-collector
of Compliance Operator can load the configurations.Is it possible to check / remediate this configuration in offline mode? (scanning containers or offline systems)
No
Please provide security policy references if possible e.g. STIG
CIS Benchmark for Kubernetes (OpenShift)