diff --git a/applications/openshift-virtualization/kubevirt-restrict-vnc-access-to-workloads/rule.yml b/applications/openshift-virtualization/kubevirt-restrict-vnc-access-to-workloads/rule.yml new file mode 100644 index 000000000000..b2429e30b0c2 --- /dev/null +++ b/applications/openshift-virtualization/kubevirt-restrict-vnc-access-to-workloads/rule.yml @@ -0,0 +1,32 @@ +documentation_complete: true + +title: 'Restrict VNC Access to Cluster Workloads' + +description: |- + Only authorized subjects should be granted roles that allow VNC + access to virtual machines. VNC access is controlled through + Kubernetes RBAC by binding the token.kubevirt.io:generate + role. Unrestricted VNC access allows any bound subject to open a + graphical console session to running virtual machines, potentially + exposing sensitive workload data and enabling unauthorized + interaction with the guest operating system. + +rationale: |- + VNC provides direct graphical console access to a running virtual + machine. In an OpenShift Virtualization environment, this access is + gated by the token.kubevirt.io:generate role. If this role + is bound too broadly, unauthorized users can view and interact with + VM desktops, capture screen contents, and input commands. Restricting + VNC access through careful role binding review ensures that only + approved subjects can establish console sessions to cluster + workloads. + +severity: medium + +ocil_clause: 'unauthorized subjects have VNC access to cluster workloads' + +ocil: |- + Run the following command to list role bindings that grant VNC access: +
$ oc get rolebinding -ojson | jq -c '.items[] | select(.roleRef.name | contains("token.kubevirt.io:generate"))'
+ Verify that only authorized subjects are bound to the
+ token.kubevirt.io:generate role.
diff --git a/build-scripts/build_cel_content.py b/build-scripts/build_cel_content.py
index 74786b6b9185..c58f3820bc51 100755
--- a/build-scripts/build_cel_content.py
+++ b/build-scripts/build_cel_content.py
@@ -339,8 +339,10 @@ def generate_cel_content(cel_rules, profiles):
for rule_id in profile.selected:
if rule_id not in cel_rule_ids:
rule_name = rule_id_to_name(rule_id)
- raise ValueError(
- f"profile '{profile_name}' references unknown rule '{rule_name}'"
+ logging.warning(
+ "profile '%s' references rule '%s' without CEL checks "
+ "(manual rule) - skipping from CEL content",
+ profile_name, rule_name,
)
cel_profile = profile_to_cel_dict(profile, cel_rule_ids)
diff --git a/docs/manual/developer/13_cel_content.md b/docs/manual/developer/13_cel_content.md
index 91cbddf9c15d..3724857dd9e1 100644
--- a/docs/manual/developer/13_cel_content.md
+++ b/docs/manual/developer/13_cel_content.md
@@ -141,7 +141,7 @@ selections:
- kubevirt-persistent-reservation-disabled
```
-**Important:** CEL profiles can only select CEL rules. If a profile includes both CEL and OVAL rules, only the CEL rules will be included in the generated CEL content file.
+**Important:** CEL profiles can select both CEL rules and manual rules (rules without `cel/shared.yml`). Manual rules are skipped during CEL content generation with a warning — only CEL rules are included in the generated CEL content file.
## Creating a CEL Rule
@@ -347,8 +347,8 @@ The build system validates CEL content automatically:
**Profile Validation:**
- `selected` field must contain at least one rule
-- All selected rules must exist in CEL rules
-- Profile cannot reference OVAL rules
+- Rules without CEL checks (manual rules) are skipped with a warning during CEL content generation
+- No error is raised for manual rules referenced by CEL profiles
**Content Validation:**
- No duplicate rule names (after underscore-to-hyphen conversion)
@@ -434,9 +434,9 @@ cel-spec '{"resource": {"spec": {"enabled": true}}}' 'resource.spec.enabled == t
**Error: `CEL profile 'profile-name' has no rules`**
- Add rules to the `selections` field in the profile
-**Error: `profile 'profile-name' references unknown rule 'rule-name'`**
-- Verify the rule exists and has CEL checks (has `cel/shared.yml` with `expression` and `inputs`)
-- Check the rule ID matches the profile selection
+**Warning: `profile 'profile-name' references rule 'rule-name' without CEL checks (manual rule)`**
+- This is expected for manual rules without `cel/shared.yml` — they are skipped from CEL content
+- If the rule should have CEL checks, add `cel/shared.yml` with `expression` and `inputs`
### CEL Content Not Generated
diff --git a/products/ocp4/profiles/cis-vm-extension.profile b/products/ocp4/profiles/cis-vm-extension.profile
index a835ac42f886..b6d58d412849 100644
--- a/products/ocp4/profiles/cis-vm-extension.profile
+++ b/products/ocp4/profiles/cis-vm-extension.profile
@@ -28,3 +28,4 @@ selections:
- kubevirt-persistent-reservation-disabled
- kubevirt-no-vms-overcommitting-guest-memory
- kubevirt-enforce-trusted-tls-registries
+ - kubevirt-restrict-vnc-access-to-workloads