From 4838606fa79a87355e1757b055a4c622c748f951 Mon Sep 17 00:00:00 2001 From: Watson Sato Date: Fri, 16 Aug 2024 10:02:55 +0200 Subject: [PATCH 1/8] Remove ocp4 rule from rhel control The audit_profile_set rule is an OCP rule, and is not necessary in this control file. Also, this rules is already selected in the pcidss_4_ocp4 control file, and breaks the auto referencing feature --- controls/pcidss_4.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/controls/pcidss_4.yml b/controls/pcidss_4.yml index 644c313138b..f0d90dc2c60 100644 --- a/controls/pcidss_4.yml +++ b/controls/pcidss_4.yml @@ -2787,7 +2787,6 @@ controls: rules: - var_auditd_name_format=fqd - auditd_name_format - - audit_profile_set - id: '10.3' title: Audit logs are protected from destruction and unauthorized modifications. From 9de4d0f6f6846595eb8a2a856cd470e893e3675a Mon Sep 17 00:00:00 2001 From: Watson Sato Date: Fri, 16 Aug 2024 10:03:40 +0200 Subject: [PATCH 2/8] Add pcidss4 reference to OCP4 control Let's auto ref the PCI-DSS v4.0 rules --- controls/pcidss_4_ocp4.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/controls/pcidss_4_ocp4.yml b/controls/pcidss_4_ocp4.yml index bd3d640547e..c5a6fcf5d60 100644 --- a/controls/pcidss_4_ocp4.yml +++ b/controls/pcidss_4_ocp4.yml @@ -5,6 +5,7 @@ version: '4.0' source: https://docs-prv.pcisecuritystandards.org/PCI%20DSS/Standard/PCI-DSS-v4_0.pdf levels: - id: base +reference_type: pcidss4 controls: - id: '1.1' From 9d92335283068d26d768c854753e45f36e174b2f Mon Sep 17 00:00:00 2001 From: Watson Sato Date: Mon, 26 Aug 2024 14:46:35 +0200 Subject: [PATCH 3/8] Update version-less PCI-DSS profile to v4.0 --- products/ocp4/profiles/pci-dss-node.profile | 2 +- products/ocp4/profiles/pci-dss.profile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/products/ocp4/profiles/pci-dss-node.profile b/products/ocp4/profiles/pci-dss-node.profile index 27a87d366b1..c83ece0933c 100644 --- a/products/ocp4/profiles/pci-dss-node.profile +++ b/products/ocp4/profiles/pci-dss-node.profile @@ -17,4 +17,4 @@ description: |- Ensures PCI-DSS v3.2.1 security configuration settings are applied. # Req-2.2 -extends: pci-dss-node-3-2 +extends: pci-dss-node-4-0 diff --git a/products/ocp4/profiles/pci-dss.profile b/products/ocp4/profiles/pci-dss.profile index e1935a5f9b9..93f741c0c34 100644 --- a/products/ocp4/profiles/pci-dss.profile +++ b/products/ocp4/profiles/pci-dss.profile @@ -17,4 +17,4 @@ description: |- Ensures PCI-DSS v3.2.1 security configuration settings are applied. # Req-2.2 -extends: pci-dss-3-2 +extends: pci-dss-4-0 From c2a587cecd56d56e52d2ff8f2e9c6dd49cd3a632 Mon Sep 17 00:00:00 2001 From: Watson Sato Date: Mon, 26 Aug 2024 11:01:57 +0200 Subject: [PATCH 4/8] Update PCI-DSS platform profile filters New platforms for node were added and these profiles were not updated to exclude these new node platforms. --- products/ocp4/profiles/pci-dss-3-2.profile | 3 ++- products/ocp4/profiles/pci-dss-4-0.profile | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/products/ocp4/profiles/pci-dss-3-2.profile b/products/ocp4/profiles/pci-dss-3-2.profile index aee6dff8bef..5e762d6be5d 100644 --- a/products/ocp4/profiles/pci-dss-3-2.profile +++ b/products/ocp4/profiles/pci-dss-3-2.profile @@ -16,7 +16,8 @@ title: 'PCI-DSS v3.2.1 Control Baseline for Red Hat OpenShift Container Platform description: |- Ensures PCI-DSS v3.2.1 security configuration settings are applied. -filter_rules: '"ocp4-node" not in platforms and "ocp4-master-node" not in platforms' +filter_rules: '"ocp4-node" not in platforms and "ocp4-master-node" not in platforms and "ocp4-node-on-sdn" not in platforms and "ocp4-node-on-ovn" not in platforms' + # Req-2.2 extends: cis diff --git a/products/ocp4/profiles/pci-dss-4-0.profile b/products/ocp4/profiles/pci-dss-4-0.profile index 55ad71646c7..f59f899170f 100644 --- a/products/ocp4/profiles/pci-dss-4-0.profile +++ b/products/ocp4/profiles/pci-dss-4-0.profile @@ -16,7 +16,7 @@ title: 'PCI-DSS v4.0.0 Control Baseline for Red Hat OpenShift Container Platform description: |- Ensures PCI-DSS v4.0.0 security configuration settings are applied. -filter_rules: '"ocp4-node" not in platforms and "ocp4-master-node" not in platforms' +filter_rules: '"ocp4-node" not in platforms and "ocp4-master-node" not in platforms and "ocp4-node-on-sdn" not in platforms and "ocp4-node-on-ovn" not in platforms' # Req-2.2 extends: cis From dba80dbac8c72dccb1305684ebfa9e8105224922 Mon Sep 17 00:00:00 2001 From: Watson Sato Date: Mon, 26 Aug 2024 13:54:04 +0200 Subject: [PATCH 5/8] Expand control processing to 'all' key Allow a control to extend all controls of a policy with 'all' key. --- docs/manual/developer/03_creating_content.md | 1 + ssg/controls.py | 19 +++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/docs/manual/developer/03_creating_content.md b/docs/manual/developer/03_creating_content.md index c89155e1068..f8a5ea06d27 100644 --- a/docs/manual/developer/03_creating_content.md +++ b/docs/manual/developer/03_creating_content.md @@ -700,6 +700,7 @@ Nesting can be accomplished both by * nesting whole control definitions, or by * nesting references to existing controls in the `policy:control` format, where the `policy:` part can be skipped if the reference points to a control in that policy. + * To nest all controls of a policy level, use `all` followed by the level. e.g: `cis_ocp4_1_4_0:all:level_2`. Nesting using references allows reuse of controls across multiple policies. diff --git a/ssg/controls.py b/ssg/controls.py index 80f8f583b5d..9568021f7e5 100644 --- a/ssg/controls.py +++ b/ssg/controls.py @@ -456,14 +456,25 @@ def resolve_controls(self): for control in policy.controls: self._resolve_control(pid, control) + def _get_foreign_subcontrols(self, policy_id, req): + if req.startswith("all"): + _, level_id = req.split(":", 1) + return self.get_all_controls_of_level(policy_id, level_id) + else: + return [self.get_control(policy_id, req)] + def _resolve_control(self, pid, control): for sub_name in control.controls: policy_id = pid if ":" in sub_name: - policy_id, sub_name = sub_name.split(":", 1) - subcontrol = self.get_control(policy_id, sub_name) - self._resolve_control(pid, subcontrol) - control.update_with(subcontrol) + policy_id, req = sub_name.split(":", 1) + subcontrols = self._get_foreign_subcontrols(policy_id, req) + else: + subcontrols = [self.get_control(policy_id, sub_name)] + + for subcontrol in subcontrols: + self._resolve_control(policy_id, subcontrol) + control.update_with(subcontrol) def get_control(self, policy_id, control_id): policy = self._get_policy(policy_id) From e0e795efb9de40f755f64ad08899588541d33cc1 Mon Sep 17 00:00:00 2001 From: Watson Sato Date: Mon, 26 Aug 2024 14:01:32 +0200 Subject: [PATCH 6/8] Add the references to the selected rules Change Control.add_references() to iterate over the selected rules, not the listed rules. There can be differences on the rules in 'selected' and 'rules'. When the Control is resolved, the final list of selected rules is in 'selected'. This is particularly more evident when we are importing other controls. --- ssg/controls.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ssg/controls.py b/ssg/controls.py index 9568021f7e5..c487d3f23ee 100644 --- a/ssg/controls.py +++ b/ssg/controls.py @@ -177,7 +177,7 @@ def represent_as_dict(self): return data def add_references(self, reference_type, rules): - for selection in self.rules: + for selection in self.selections: if "=" in selection: continue rule = rules.get(selection) From 7d982e85e62ddd6f1f1ea515e176d001b9137f7d Mon Sep 17 00:00:00 2001 From: Watson Sato Date: Mon, 26 Aug 2024 14:07:59 +0200 Subject: [PATCH 7/8] Import OCP4 CIS rather than extending it When a profile extends another one, the rules on the extended profile are not auto referenced. This patch importa the CIS into PCI-DSS, allowing the CIS rules to have PCI-DSS added automatically. --- controls/cis_ocp_1_4_0/section-4.yml | 1 + controls/pcidss_4_ocp4.yml | 2 ++ products/ocp4/profiles/cis-1-4.profile | 1 - products/ocp4/profiles/cis-1-5.profile | 1 - products/ocp4/profiles/pci-dss-4-0.profile | 2 -- products/ocp4/profiles/pci-dss-node-4-0.profile | 3 --- 6 files changed, 3 insertions(+), 7 deletions(-) diff --git a/controls/cis_ocp_1_4_0/section-4.yml b/controls/cis_ocp_1_4_0/section-4.yml index 6ad340af6e5..0c53db629c5 100644 --- a/controls/cis_ocp_1_4_0/section-4.yml +++ b/controls/cis_ocp_1_4_0/section-4.yml @@ -131,6 +131,7 @@ controls: status: automated rules: - kubelet_configure_event_creation + - var_event_record_qps=50 levels: [ level_2, ] - id: 4.2.9 title: Ensure that the --tls-cert-file and --tls-private-key-file arguments are set as appropriate diff --git a/controls/pcidss_4_ocp4.yml b/controls/pcidss_4_ocp4.yml index c5a6fcf5d60..696c8ce4682 100644 --- a/controls/pcidss_4_ocp4.yml +++ b/controls/pcidss_4_ocp4.yml @@ -387,6 +387,8 @@ controls: This control is also addressed by applying the OpenShift CIS recommendations. rules: - scansettingbinding_exists + controls: + - cis_ocp_1_4_0:all:level_2 - id: 2.2.2 title: Vendor default accounts are managed diff --git a/products/ocp4/profiles/cis-1-4.profile b/products/ocp4/profiles/cis-1-4.profile index bf486978ebb..13bafef301d 100644 --- a/products/ocp4/profiles/cis-1-4.profile +++ b/products/ocp4/profiles/cis-1-4.profile @@ -31,7 +31,6 @@ selections: - cis_ocp_1_4_0:all ### Variables - var_openshift_audit_profile=WriteRequestBodies - - var_event_record_qps=50 ### Helper Rules ### This is a helper rule to fetch the required api resource for detecting OCP version - version_detect_in_ocp diff --git a/products/ocp4/profiles/cis-1-5.profile b/products/ocp4/profiles/cis-1-5.profile index 78f05edf5e9..89c143af0e0 100644 --- a/products/ocp4/profiles/cis-1-5.profile +++ b/products/ocp4/profiles/cis-1-5.profile @@ -32,7 +32,6 @@ selections: - cis_ocp_1_4_0:all ### Variables - var_openshift_audit_profile=WriteRequestBodies - - var_event_record_qps=50 ### Helper Rules ### This is a helper rule to fetch the required api resource for detecting OCP version - version_detect_in_ocp diff --git a/products/ocp4/profiles/pci-dss-4-0.profile b/products/ocp4/profiles/pci-dss-4-0.profile index f59f899170f..5fd3e4afb41 100644 --- a/products/ocp4/profiles/pci-dss-4-0.profile +++ b/products/ocp4/profiles/pci-dss-4-0.profile @@ -18,8 +18,6 @@ description: |- filter_rules: '"ocp4-node" not in platforms and "ocp4-master-node" not in platforms and "ocp4-node-on-sdn" not in platforms and "ocp4-node-on-ovn" not in platforms' -# Req-2.2 -extends: cis selections: - pcidss_4_ocp4:all:base diff --git a/products/ocp4/profiles/pci-dss-node-4-0.profile b/products/ocp4/profiles/pci-dss-node-4-0.profile index 43c532013d9..afee4784a22 100644 --- a/products/ocp4/profiles/pci-dss-node-4-0.profile +++ b/products/ocp4/profiles/pci-dss-node-4-0.profile @@ -18,8 +18,5 @@ description: |- filter_rules: '"ocp4-node" in platforms or "ocp4-master-node" in platforms or "ocp4-node-on-sdn" in platforms or "ocp4-node-on-ovn" in platforms' -# Req-2.2 -extends: cis-node - selections: - pcidss_4_ocp4:all:base From 4d8484eb9711d1527a18d496be0bbcf4c59154ed Mon Sep 17 00:00:00 2001 From: Watson Sato Date: Tue, 27 Aug 2024 10:28:53 +0200 Subject: [PATCH 8/8] Add test for imports of 'all' controls Test import of all controls of a specific level. --- tests/unit/ssg-module/test_controls.py | 31 ++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/tests/unit/ssg-module/test_controls.py b/tests/unit/ssg-module/test_controls.py index 61f424d2b92..258b571e42d 100644 --- a/tests/unit/ssg-module/test_controls.py +++ b/tests/unit/ssg-module/test_controls.py @@ -486,6 +486,37 @@ def test_policy_parse_from_ours_and_foreign(): assert "really_ours" in control.selections assert "foreign" in control.selections +def test_policy_parse_foreign_with_all(): + main_control_dict = dict(id="top", controls=["foreign:all:level_1", "ours", "P:ours_qualified"]) + main_subcontrol_dicts = [dict(id="ours", rules=["ours"]), dict(id="ours_qualified", rules=["really_ours"])] + foreign_control_dicts = [dict(id="req1", rules=["foreign_1"], levels=["level_1"]), + dict(id="req2", rules=["foreign_2"], levels=["level_1", "level_2"]), + dict(id="req3", rules=["foreign_3"], levels=["level_2"])] + + main_policy = ssg.controls.Policy("") + main_policy.id = "P" + main_policy.save_controls_tree([main_control_dict] + main_subcontrol_dicts) + + foreign_policy = ssg.controls.Policy("") + foreign_policy.id = "foreign" + level1 = ssg.controls.Level.from_level_dict(dict(id="level_1")) + level2 = ssg.controls.Level.from_level_dict(dict(id="level_2")) + + foreign_policy.levels = [level1, level2] + foreign_policy.levels_by_id = {"level_1": level1, "level_2": level2} + foreign_policy.save_controls_tree(foreign_control_dicts) + + controls_manager = ssg.controls.ControlsManager("", dict()) + controls_manager.policies[main_policy.id] = main_policy + controls_manager.policies[foreign_policy.id] = foreign_policy + + controls_manager.resolve_controls() + control = controls_manager.get_control("P", "top") + assert "ours" in control.selections + assert "really_ours" in control.selections + assert "foreign_1" in control.selections + assert "foreign_2" in control.selections + assert "foreign_3" not in control.selections def test_policy_parse_from_referenced(minimal_empty_controls, one_simple_subcontrol): nested_controls = minimal_empty_controls