feat(rules): add service enforcement rules#1982
Conversation
Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
Signed-off-by: Oliver Bähler <oliverbaehler@hotmail.com>
Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
There was a problem hiding this comment.
Pull request overview
This PR introduces service-focused Namespace Rule enforcement (types, LoadBalancer CIDRs, ExternalName hostnames, NodePort ranges) and associated validation, expanding the existing rule engine so Service admissions can be evaluated and reported consistently (including improved “allowed list” messaging). It also adds RuleStatus rule validation plumbing and updates controller runtime configuration options and Helm chart values/templates to support the new webhook and rule fields.
Changes:
- Add
enforce.servicesAPI types + deep-copy support, plus rule-body validation for services/workloads. - Add Service admission rule evaluators (service type, LoadBalancer CIDRs, ExternalName hostnames, NodePort ranges) and extend evaluator messaging to include rule descriptions/details.
- Update controller/webhook wiring, Helm chart values/schema/templates, and developer tooling (
make testvia gotestsum) to support the feature rollout.
Reviewed changes
Copilot reviewed 60 out of 60 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| pkg/runtime/events/reasons.go | Add new service-related event reasons. |
| pkg/ruleengine/validate.go | New ruleset body validation logic. |
| pkg/ruleengine/validate_test.go | Unit tests for rule-body validation. |
| pkg/ruleengine/enforce_evaluator.go | Add richer decision context/messaging. |
| pkg/ruleengine/convert_test.go | Tests for extracting enforce bodies. |
| pkg/api/rules/zz_generated.deepcopy.go | DeepCopy updates for new fields/types. |
| pkg/api/rules/enforce_types.go | Add Services enforcement block. |
| pkg/api/rules/enforce_services_types.go | New API types for service enforcement. |
| pkg/api/forbidden_list.go | Fix exact-match implementation (slices.Contains). |
| pkg/api/forbidden_list_test.go | Add regression tests for exact-match. |
| Makefile | Switch make test to gotestsum. |
| internal/webhook/tenant/validation/rule_validator.go | Delegate rule validation to ruleengine validator. |
| internal/webhook/service/validating.go | Update handler type to accept ruleset. |
| internal/webhook/service/handler.go | Use tenant+ruleset typed handler wrapper. |
| internal/webhook/rules/utils.go | Shared expression match description helper. |
| internal/webhook/rules/status/validation.go | New RuleStatus validating webhook handler. |
| internal/webhook/rules/services/validation/utils.go | Shared helpers for service rule checks. |
| internal/webhook/rules/services/validation/utils_test.go | Unit tests for service helpers. |
| internal/webhook/rules/services/validation/service_type.go | Enforce allowed Service types. |
| internal/webhook/rules/services/validation/service_type_test.go | Tests for service type enforcement. |
| internal/webhook/rules/services/validation/node_port.go | Enforce NodePort range rules. |
| internal/webhook/rules/services/validation/node_port_test.go | Tests for NodePort enforcement. |
| internal/webhook/rules/services/validation/loadbalancer.go | Enforce LoadBalancer CIDR constraints. |
| internal/webhook/rules/services/validation/loadbalancer_test.go | Tests for LoadBalancer CIDR enforcement. |
| internal/webhook/rules/services/validation/factory.go | Service rules handler factory + evaluation loop. |
| internal/webhook/rules/services/validation/factory_test.go | Test helper for service rules. |
| internal/webhook/rules/services/validation/external_name.go | Enforce ExternalName hostname rules. |
| internal/webhook/rules/services/validation/external_name_test.go | Tests for ExternalName enforcement. |
| internal/webhook/rules/pods/validation/schedulers.go | Add rule descriptions/allowed label to messages. |
| internal/webhook/rules/pods/validation/schedulers_test.go | Update/add scheduler rule tests. |
| internal/webhook/rules/pods/validation/registry.go | Add registry rule descriptions/allowed label. |
| internal/webhook/rules/pods/validation/qos.go | Add QoS rule descriptions/allowed label. |
| internal/webhook/rules/pods/validation/qos_test.go | Add/update QoS rule tests. |
| internal/webhook/rules/pods/validation/factory_test.go | Test helper for pod rules. |
| internal/webhook/route/rules.go | New route for RuleStatus validating webhook. |
| internal/controllers/utils/options.go | Add runtime controller options + conversion helper. |
| internal/controllers/tenantowner/manager.go | Apply unified controller options helper. |
| internal/controllers/tenant/manager.go | Apply unified controller options helper. |
| internal/controllers/rulestatus/manager.go | Use DeepCopy + unified controller options. |
| internal/controllers/resources/namespaced.go | Apply unified controller options helper. |
| internal/controllers/resources/global.go | Apply unified controller options helper. |
| internal/controllers/resourcepools/pool_controller.go | Apply unified controller options helper. |
| internal/controllers/resourcepools/claim_controller.go | Apply unified controller options helper. |
| internal/controllers/pv/controller.go | Apply unified controller options helper. |
| internal/controllers/customquotas/global_custom_quota_controller.go | Apply unified controller options helper. |
| internal/controllers/customquotas/custom_quota_controller.go | Apply unified controller options helper. |
| internal/controllers/admission/validating.go | Apply unified controller options helper. |
| internal/controllers/admission/mutating.go | Apply unified controller options helper. |
| hack/distro/capsule/example-setup/tenants.yaml | Update example tenant rules with service enforcement. |
| e2e/namespace_metadata_controller_test.go | Rename tenant used in e2e test. |
| cmd/controller/main.go | Add cache sync timeout flag; register service rules handler. |
| charts/capsule/values.yaml | Add rulestatus webhook values. |
| charts/capsule/values.schema.json | Add rulestatus webhook schema. |
| charts/capsule/templates/configuration.yaml | Render rulestatus validating webhook config. |
| charts/capsule/README.md | Document new rulestatus webhook values. |
| charts/capsule/crds/capsule.clastix.io_tenants.yaml | CRD schema for enforce.services. |
| charts/capsule/crds/capsule.clastix.io_rulestatuses.yaml | CRD schema for enforce.services. |
Comments suppressed due to low confidence (1)
internal/webhook/tenant/validation/rule_validator.go:86
- Tenant rule validation no longer verifies that rule.NamespaceSelector is syntactically valid (metav1.LabelSelectorAsSelector). Invalid selectors can now be admitted and will later fail during ruleset evaluation/selection with harder-to-trace errors.
| servicerules.ServiceRules(regexCache), | ||
| service.Validating(), | ||
| ), | ||
| ), |
| func describeExpressionMatch(match api.ExpressionMatch) string { | ||
| parts := make([]string, 0, 2) | ||
|
|
||
| if len(match.Exact) > 0 { | ||
| parts = append(parts, fmt.Sprintf("exact: %s", strings.Join(match.Exact, ", "))) | ||
| } |
Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 63 out of 63 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
internal/webhook/tenant/validation/rule_validator.go:86
- This webhook no longer validates
rule.NamespaceSelectorvalues. That means a Tenant can be admitted with an invalid selector, but laterpkg/tenant.BuildNamespaceRuleBodyStatuswill error at runtime when evaluating rules. Consider reinstating selector compilation validation (e.g.,metav1.LabelSelectorAsSelector) and returning arules[i].namespaceSelector is invalidadmission error.
| for i := range limit { | ||
| description := describeRule(set, rules[i]) | ||
| if description == "" { | ||
| continue | ||
| } | ||
|
|
||
| parts = append(parts, description) | ||
| } |
| func describeExpressionMatch(match api.ExpressionMatch) string { | ||
| parts := make([]string, 0, 2) | ||
|
|
||
| if len(match.Exact) > 0 { | ||
| parts = append(parts, fmt.Sprintf("exact: %s", strings.Join(match.Exact, ", "))) | ||
| } | ||
|
|
||
| if match.Expression != "" { | ||
| parts = append(parts, fmt.Sprintf("exp: %s", match.Expression)) | ||
| } | ||
|
|
||
| return strings.Join(parts, "; ") | ||
| } |
|
|
||
| // Negative control: a key the admin did NOT deny is correctly allowed, | ||
| // proving the webhook is not simply denying everything. | ||
| func TestPoC_NegativeControl_BenignAllowed(t *testing.T) { |
Signed-off-by: Oliver Baehler <oliver@sudo-i.net>
No description provided.