-
Notifications
You must be signed in to change notification settings - Fork 179
Add proposed ADR to use CEL in CascadingRules #3328
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Weltraumschaf
merged 3 commits into
secureCodeBox:main
from
J12934:docs/adr-cel-for-cascading-rules
Oct 22, 2025
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
211 changes: 211 additions & 0 deletions
211
documentation/docs/architecture/09_architecture_decisions/adr_0020.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,211 @@ | ||
| --- | ||
| # SPDX-FileCopyrightText: the secureCodeBox authors | ||
| # | ||
| # SPDX-License-Identifier: Apache-2.0 | ||
|
|
||
| title: "ADR-0020: Adopting Common Expression Language (CEL) for CascadingRule Matching" | ||
| sidebar_label: "ADR-0020" | ||
| --- | ||
| # ADR-0020: Adopting Common Expression Language (CEL) for CascadingRule Matching | ||
|
|
||
| | <!-- --> | <!-- --> | | ||
| |----------------|----------------------------------------------------------------------------------------------| | ||
| | **Status**: | PROPOSED | | ||
| | **Date**: | 2025-10-14 | | ||
| | **Author(s)**: | Jannik Hollenbach [jannik.hollenbach@iteratec.com](mailto:jannik.hollenbach@iteratec.com) | | ||
|
|
||
| ## Context | ||
|
|
||
| CascadingRules in secureCodeBox currently use a custom `matches` object syntax to define which findings should trigger subsequent scans. The current implementation uses a declarative YAML structure with `anyOf` rules that perform partial deep comparison against finding fields: | ||
|
|
||
| ```yaml | ||
| spec: | ||
| matches: | ||
| anyOf: | ||
| - category: "Open Port" | ||
| attributes: | ||
| port: 22 | ||
| state: open | ||
| - category: "Open Port" | ||
| attributes: | ||
| service: "ssh" | ||
| state: open | ||
| ``` | ||
|
|
||
| While this approach works well for simple matching scenarios, it has several limitations: | ||
|
|
||
| 1. **Limited Expressiveness**: The current syntax only supports exact matching and partial deep comparison. Complex conditions like range checks, regex patterns, logical combinations beyond `anyOf`, or computed values are not possible without extending the custom syntax. | ||
| 2. **Maintenance Burden**: Every new matching requirement necessitates extending the custom matcher implementation. This creates ongoing maintenance overhead and increases the complexity of the codebase. | ||
| 3. **Lack of Flexibility**: Common use cases like checking if a port is within a range (e.g., `port >= 8000 && port <= 9000`), matching against multiple patterns, or combining conditions with complex boolean logic require workarounds or are simply not possible. | ||
|
|
||
| [Common Expression Language (CEL)](https://github.com/google/cel-spec) is a non-Turing complete expression language designed for evaluating expressions in a safe, fast, and portable manner. It is already widely adopted in the Kubernetes ecosystem, particularly in: | ||
|
|
||
| - Kubernetes ValidatingAdmissionPolicy (since v1.26) | ||
| - Kubernetes Custom Resource Definitions (CRD validation rules) | ||
| - Istio authorization policies | ||
| - Various other cloud-native projects | ||
|
|
||
| CEL provides a familiar C-like syntax and is specifically designed for configuration and policy evaluation use cases, making it an ideal fit for CascadingRule matching logic. | ||
|
|
||
| ## Decision | ||
|
|
||
| We propose migrating the CascadingRule `matches` specification from the current custom object syntax to use Common Expression Language (CEL) expressions. | ||
|
|
||
| ### Proposed Syntax | ||
|
|
||
| Instead of the current `matches.anyOf` structure, users would write CEL expressions that evaluate to a boolean: | ||
|
|
||
| ```yaml | ||
| spec: | ||
| matches: | ||
| expression: | | ||
| (finding.category == "Open Port" && finding.attributes.port == 22 && finding.attributes.state == "open") || | ||
| (finding.category == "Open Port" && finding.attributes.service == "ssh" && finding.attributes.state == "open") | ||
| ``` | ||
|
|
||
| Or more concisely: | ||
|
|
||
| ```yaml | ||
| spec: | ||
| matches: | ||
| expression: | | ||
| finding.category == "Open Port" && | ||
| finding.attributes.state == "open" && | ||
| (finding.attributes.port == 22 || finding.attributes.service == "ssh") | ||
| ``` | ||
|
|
||
| ### Advanced Use Cases Enabled by CEL | ||
|
|
||
| CEL would enable powerful matching scenarios that are currently impossible: | ||
|
|
||
| **Range Checks:** | ||
| ```yaml | ||
| expression: | | ||
| finding.category == "Open Port" && | ||
| finding.attributes.port >= 8000 && | ||
| finding.attributes.port <= 9000 | ||
| ``` | ||
|
|
||
| **Regex Matching:** | ||
| ```yaml | ||
| expression: | | ||
| finding.category == "Subdomain" && | ||
| finding.attributes.hostname.matches("^.*\\.example\\.com$") | ||
| ``` | ||
|
|
||
| **Complex Boolean Logic:** | ||
| ```yaml | ||
| expression: | | ||
| (finding.severity in ["HIGH", "CRITICAL"] && finding.category == "Vulnerability") || | ||
| (finding.category == "Open Port" && finding.attributes.port in [22, 23, 3389]) | ||
| ``` | ||
|
|
||
| **Computed Values:** | ||
| ```yaml | ||
| expression: | | ||
| finding.category == "Open Port" && | ||
| has(finding.attributes.service) && | ||
| finding.attributes.service.startsWith("http") | ||
| ``` | ||
|
|
||
| ### Migration Strategy | ||
|
|
||
| To ensure backward compatibility and smooth migration: | ||
|
|
||
| 1. **Dual Support Period**: Support both the legacy `matches.anyOf` syntax and the new `matches.expression` syntax simultaneously for at least two major versions. | ||
|
|
||
| 2. **Automatic Translation (Preferred Approach)**: Implement automatic runtime translation of `matches.anyOf` to CEL expressions: | ||
| - When a CascadingRule contains only `matches.anyOf`, automatically translate it to an equivalent CEL expression at runtime | ||
| - Log an informational message indicating the automatic translation occurred | ||
| - This approach eliminates the need for complex conflict resolution logic | ||
| - Users can gradually migrate at their own pace without breaking changes | ||
| - The translation logic can be removed in a future major version when `anyOf` support is dropped | ||
|
|
||
| **If automatic translation is implemented, the conflict resolution below becomes unnecessary.** | ||
|
|
||
| 3. **Conflict Resolution (Alternative if no automatic translation)**: When both `matches.anyOf` and `matches.expression` are specified in the same CascadingRule: | ||
| - Generally automatic translation would be prefered as it eliminates manual work and potential errors, but if that turns out to be hard to achieve, manual translation might be the only option. | ||
| - **CEL takes precedence**: The `matches.expression` will be evaluated and `matches.anyOf` will be ignored | ||
| - **Emit a warning**: Log a warning message and add a Kubernetes event to the CascadingRule resource indicating the conflict | ||
| - **Add status condition**: Update the CascadingRule status with a condition indicating that both matchers were specified and CEL was used | ||
|
|
||
| Example warning message: | ||
| ``` | ||
| Warning: CascadingRule 'nmap-hostscan' specifies both 'matches.anyOf' and 'matches.expression'. | ||
| Using CEL expression and ignoring anyOf matcher. Please remove the deprecated 'matches.anyOf' field. | ||
| ``` | ||
|
|
||
| 4. **Translation Documentation**: Provide documentation to help users manually translate existing `anyOf` rules to CEL expressions to better help users understanding of the new syntax. | ||
|
|
||
| 5. (consider) **Validation**: Implement comprehensive validation of CEL expressions at CRD admission time to catch syntax errors early. We have avoided validating webhooks so far, as they have a overhead in terms of cert management, but might be worthwhile for this issue. | ||
|
|
||
| 6. **Documentation**: Create extensive documentation with examples showing common patterns and migration guides. | ||
|
|
||
| 7. **Proposed Deprecation Path**: | ||
| - Version 5.x: Introduce CEL support with automatic translation of `anyOf` (if implemented) or dual support, mark `anyOf` as deprecated with informational/warning messages | ||
| - Version 6.0.0: Remove support for `anyOf` syntax and automatic translation logic | ||
|
|
||
| ## Consequences | ||
|
|
||
| ### Positive Consequences | ||
|
|
||
| 1. **Increased Flexibility**: Users can express arbitrarily complex matching logic without waiting for custom syntax extensions. | ||
| 2. **Reduced Maintenance**: The secureCodeBox team no longer needs to maintain and extend custom matching logic. CEL is maintained by Google and the broader community. | ||
| 3. **Industry Standard**: CEL is becoming the de facto standard for policy expressions in Kubernetes, making it familiar to many users. | ||
| 4. **Better Tooling**: CEL has existing tooling, documentation, and community support that users can leverage. | ||
| 5. **Type Safety**: CEL provides compile-time type checking, catching errors before runtime. | ||
| 6. **Security**: CEL is non-Turing complete and designed to be safe for user-provided expressions, preventing infinite loops or resource exhaustion. | ||
|
|
||
| ### Negative Consequences | ||
|
|
||
| 1. **Breaking Change**: Eventually removing the `anyOf` syntax will require users to migrate their existing CascadingRules. | ||
| 2. **Learning Curve**: Users unfamiliar with CEL will need to learn a new expression syntax, though it's relatively simple and well-documented. | ||
| 3. **Migration Effort**: Existing CascadingRules will need to be updated, requiring effort from users and clear migration documentation. | ||
| 4. **Increased Complexity**: The cascading hook codebase will temporarily be more complex during the dual-support period. | ||
| 5. **Dependency Addition**: Adding the cel library increases the dependency footprint of the operator. | ||
| 6. **Error Messages**: CEL error messages may be less intuitive than custom validation errors, requiring careful wrapping and contextualization. | ||
| 7. **Potential Confusion**: During the dual-support period, users might accidentally specify both matchers, though the clear precedence rule and warnings mitigate this risk. | ||
|
|
||
| ### Mitigation Strategies | ||
|
|
||
| - **If automatic translation is implemented**: The migration becomes seamless with minimal user impact | ||
| - Provide comprehensive migration guides with side-by-side examples | ||
| - Create a validation tool or script to help users test their CEL expressions | ||
| - Maintain the dual-support period for sufficient time to allow gradual migration | ||
| - Offer community support and examples for common migration scenarios | ||
| - If no automatic translation: Implement clear conflict detection with actionable warning messages | ||
| - Add linting/validation in CI/CD pipelines to detect deprecated usage early | ||
|
|
||
| ## Alternatives Considered | ||
|
|
||
| ### 1. Extend the Current Custom Syntax | ||
|
|
||
| We could continue extending the `matches` object with new fields and operators (e.g., `allOf`, `noneOf`, etc.). | ||
|
|
||
| **Rejected because**: This would perpetuate the maintenance burden and still wouldn't provide the full flexibility of a proper expression language. Each new requirement would require code changes and releases. | ||
|
|
||
| ### 2. Use JSONPath or JMESPath | ||
|
|
||
| These are query languages designed for JSON data extraction and filtering. | ||
|
|
||
| **Rejected because**: While powerful for data extraction, they are less intuitive for boolean logic and condition evaluation. CEL is specifically designed for policy evaluation use cases. | ||
|
|
||
| ### 3. Use JavaScript or Lua | ||
|
|
||
| Embed a scripting language for maximum flexibility. | ||
|
|
||
| **Rejected because**: Full scripting languages are Turing complete and pose security risks when evaluating user-provided code. They also have higher performance overhead and complexity. CEL's non-Turing complete nature makes it safer and more appropriate for this use case. | ||
|
|
||
| ### 4. Use Rego (Open Policy Agent) | ||
|
|
||
| Rego is the policy language used by Open Policy Agent. | ||
|
|
||
| **Rejected because**: While Rego is powerful, it has a steeper learning curve and is less widely adopted in the Kubernetes ecosystem compared to CEL. CEL's integration with Kubernetes CRDs and admission policies makes it a more natural fit. | ||
|
|
||
| ## References | ||
|
|
||
| - [CEL Specification](https://github.com/google/cel-spec) | ||
| - [cel-go Implementation](https://github.com/google/cel-go) | ||
| - [cel-js Implementation](https://github.com/marcbachmann/cel-js) | ||
| - [Kubernetes CEL Validation](https://kubernetes.io/docs/reference/using-api/cel/) | ||
| - [Current CascadingRule Documentation](https://www.securecodebox.io/docs/api/crds/cascading-rule) | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if accidentally both is configured? Precedence of CEL + warning?