From 40d56761879fb6ac5c9c64c0147e22e7b591740a Mon Sep 17 00:00:00 2001 From: Jannik Hollenbach Date: Tue, 14 Oct 2025 16:09:51 +0200 Subject: [PATCH 1/3] =?UTF-8?q?That=20isn't=20my=20name=20=F0=9F=98=85?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Jannik Hollenbach --- .../docs/architecture/09_architecture_decisions/adr_0002.md | 2 +- .../docs/architecture/09_architecture_decisions/adr_0003.md | 2 +- .../docs/architecture/09_architecture_decisions/adr_0009.md | 2 +- .../docs/architecture/09_architecture_decisions/adr_0012.md | 2 +- .../docs/architecture/09_architecture_decisions/adr_0015.md | 2 +- .../docs/architecture/09_architecture_decisions/adr_0016.md | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/documentation/docs/architecture/09_architecture_decisions/adr_0002.md b/documentation/docs/architecture/09_architecture_decisions/adr_0002.md index 13c2344601..5758865afb 100644 --- a/documentation/docs/architecture/09_architecture_decisions/adr_0002.md +++ b/documentation/docs/architecture/09_architecture_decisions/adr_0002.md @@ -12,7 +12,7 @@ sidebar_label: "ADR-0002" |----------------|----------| | **Status**: | ACCEPTED | | **Date**: | 2020-05-20 | -| **Author(s)**: | Jannik Hollenbach [jannick.hollenbach@iteratec.com](mailto:jannick.hollenbach@iteratec.com), Jorge Estigarribia [jorge.estigarribia@iteratec.com](mailto:jorge.estigarribia@iteratec.com), Robert Seedorff [Robert.Seedorff@iteratec.com](mailto:Robert.Seedorff@iteratec.com), Sven Strittmatter [sven.strittmatter@iteratec.com](mailto:Sven.Strittmatter@iteratec.com) | +| **Author(s)**: | Jannik Hollenbach [jannik.hollenbach@iteratec.com](mailto:jannik.hollenbach@iteratec.com), Jorge Estigarribia [jorge.estigarribia@iteratec.com](mailto:jorge.estigarribia@iteratec.com), Robert Seedorff [Robert.Seedorff@iteratec.com](mailto:Robert.Seedorff@iteratec.com), Sven Strittmatter [sven.strittmatter@iteratec.com](mailto:Sven.Strittmatter@iteratec.com) | ## Context diff --git a/documentation/docs/architecture/09_architecture_decisions/adr_0003.md b/documentation/docs/architecture/09_architecture_decisions/adr_0003.md index a9f6673120..ecc18045e0 100644 --- a/documentation/docs/architecture/09_architecture_decisions/adr_0003.md +++ b/documentation/docs/architecture/09_architecture_decisions/adr_0003.md @@ -12,7 +12,7 @@ sidebar_label: "ADR-0003" |----------------|----------| | **Status**: | ACCEPTED | | **Date**: | 2020-05-20 | -| **Author(s)**: | Jannik Hollenbach [jannick.hollenbach@iteratec.com](mailto:jannick.hollenbach@iteratec.com), Robert Seedorff [Robert.Seedorff@iteratec.com](mailto:Robert.Seedorff@iteratec.com), Sven Strittmatter [sven.strittmatter@iteratec.com](mailto:Sven.Strittmatter@iteratec.com) | +| **Author(s)**: | Jannik Hollenbach [jannik.hollenbach@iteratec.com](mailto:jannik.hollenbach@iteratec.com), Robert Seedorff [Robert.Seedorff@iteratec.com](mailto:Robert.Seedorff@iteratec.com), Sven Strittmatter [sven.strittmatter@iteratec.com](mailto:Sven.Strittmatter@iteratec.com) | ## Context diff --git a/documentation/docs/architecture/09_architecture_decisions/adr_0009.md b/documentation/docs/architecture/09_architecture_decisions/adr_0009.md index ec6c527791..4e82be5c7e 100644 --- a/documentation/docs/architecture/09_architecture_decisions/adr_0009.md +++ b/documentation/docs/architecture/09_architecture_decisions/adr_0009.md @@ -12,7 +12,7 @@ sidebar_label: "ADR-0009" |----------------|----------| | **Status**: | ACCEPTED | | **Date**: | 2021-10-07 | -| **Author(s)**: | Max Maass [max.maass@iteratec.com](mailto:max.maass@iteratec.com), Jannik Hollenbach [jannick.hollenbach@iteratec.com](mailto:jannick.hollenbach@iteratec.com) | +| **Author(s)**: | Max Maass [max.maass@iteratec.com](mailto:max.maass@iteratec.com), Jannik Hollenbach [jannik.hollenbach@iteratec.com](mailto:jannik.hollenbach@iteratec.com) | ## Context diff --git a/documentation/docs/architecture/09_architecture_decisions/adr_0012.md b/documentation/docs/architecture/09_architecture_decisions/adr_0012.md index 91a2d80e57..ef5cecf3ca 100644 --- a/documentation/docs/architecture/09_architecture_decisions/adr_0012.md +++ b/documentation/docs/architecture/09_architecture_decisions/adr_0012.md @@ -13,7 +13,7 @@ sidebar_label: "ADR-0012" | -------------- | -------------------------------------------------------------------------------------- | | **Status**: | OPEN | | **Date**: | 2022-06-17 | -| **Author(s)**: | Jannik Hollenbach [jannick.hollenbach@iteratec.com](mailto:jannick.hollenbach@iteratec.com), Max Maass [max.maass@iteratec.com](mailto:max.maass@iteratec.com) | +| **Author(s)**: | Jannik Hollenbach [jannik.hollenbach@iteratec.com](mailto:jannik.hollenbach@iteratec.com), Max Maass [max.maass@iteratec.com](mailto:max.maass@iteratec.com) | ## Context diff --git a/documentation/docs/architecture/09_architecture_decisions/adr_0015.md b/documentation/docs/architecture/09_architecture_decisions/adr_0015.md index 192b9dca3e..fa8144ed82 100644 --- a/documentation/docs/architecture/09_architecture_decisions/adr_0015.md +++ b/documentation/docs/architecture/09_architecture_decisions/adr_0015.md @@ -13,7 +13,7 @@ sidebar_label: "ADR-0015" | -------------- | ------------------------------------------------------------------------------------------------------ | | **Status**: | ACCEPTED | | **Date**: | 2022-09-13 | -| **Author(s)**: | Jannik Hollenbach [jannick.hollenbach@iteratec.com](mailto:jannick.hollenbach@iteratec.com), Sven Strittmatter [sven.strittmatter@iteratec.com](mailto:Sven.Strittmatter@iteratec.com) | +| **Author(s)**: | Jannik Hollenbach [jannik.hollenbach@iteratec.com](mailto:jannik.hollenbach@iteratec.com), Sven Strittmatter [sven.strittmatter@iteratec.com](mailto:Sven.Strittmatter@iteratec.com) | :::info This ADR should have been written prior to implementation. But we started documenting ADR later. This ADR has therefore been written retrospectively to record the decision made at that time. diff --git a/documentation/docs/architecture/09_architecture_decisions/adr_0016.md b/documentation/docs/architecture/09_architecture_decisions/adr_0016.md index ca1a36741c..80f704c6c4 100644 --- a/documentation/docs/architecture/09_architecture_decisions/adr_0016.md +++ b/documentation/docs/architecture/09_architecture_decisions/adr_0016.md @@ -13,7 +13,7 @@ sidebar_label: "ADR-0016" | -------------- | ------------------------------------------------------------------------------------------------------ | | **Status**: | ACCEPTED | | **Date**: | 2022-09-13 | -| **Author(s)**: | Jannik Hollenbach [jannick.hollenbach@iteratec.com](mailto:jannick.hollenbach@iteratec.com), Sven Strittmatter [sven.strittmatter@iteratec.com](mailto:Sven.Strittmatter@iteratec.com) | +| **Author(s)**: | Jannik Hollenbach [jannik.hollenbach@iteratec.com](mailto:jannik.hollenbach@iteratec.com), Sven Strittmatter [sven.strittmatter@iteratec.com](mailto:Sven.Strittmatter@iteratec.com) | :::info This ADR should have been written prior to implementation. But we started documenting ADR later. This ADR has therefore been written retrospectively to record the decision made at that time. From 106148e432c968e974ced64909fd76006586f8e3 Mon Sep 17 00:00:00 2001 From: Jannik Hollenbach Date: Tue, 14 Oct 2025 16:15:04 +0200 Subject: [PATCH 2/3] Add CEL Matcher ADR for CascadingRules Most of the text and structure here is generated based on the following prompt, then manually reviewed, just in case anybody wants to save time reading boilerplate :D ```prompt Please have a look at the current syntax for CascadingRules in the following files: documentation/docs/how-tos/scanning-networks.md documentation/docs/api/crds/cascading-rule.md Please write a ADR in the documentation/docs/architecture/09_architecture_decisions directory with a sugegsted move to switch out the custom `matches` object syntax of the CascadingRule with the Common Expression Language (CEL). The goal here would be make the CascadingRules more dynamic by allowing a wide range of expressions without us having to model the matcher syntax for everything ourself. describe the pros and cons of that approach try to follow the structure of existing ADRs in this repo ``` Signed-off-by: Jannik Hollenbach --- .../09_architecture_decisions/adr_0020.md | 175 ++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 documentation/docs/architecture/09_architecture_decisions/adr_0020.md diff --git a/documentation/docs/architecture/09_architecture_decisions/adr_0020.md b/documentation/docs/architecture/09_architecture_decisions/adr_0020.md new file mode 100644 index 0000000000..adc204282a --- /dev/null +++ b/documentation/docs/architecture/09_architecture_decisions/adr_0020.md @@ -0,0 +1,175 @@ +--- +# 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. (maybe?) **Automatic Translation**: Provide tooling or documentation to help users translate existing `anyOf` rules to CEL expressions. +3. (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. +4. **Documentation**: Create extensive documentation with examples showing common patterns and migration guides. +5. **Proposed Deprecation Path**: + - Version 5.x: Introduce CEL support alongside existing syntax and mark `anyOf` as deprecated with warnings + - Version 6.0.0: Remove support for `anyOf` syntax + +## 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. + +## 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) \ No newline at end of file From d6e1aacb4d1a36da719b7e3a57f412b04f717b45 Mon Sep 17 00:00:00 2001 From: Jannik Hollenbach Date: Thu, 16 Oct 2025 11:28:40 +0200 Subject: [PATCH 3/3] Clarify dual support period and automatic translation possibilities Signed-off-by: Jannik Hollenbach --- .../09_architecture_decisions/adr_0020.md | 48 ++++++++++++++++--- 1 file changed, 42 insertions(+), 6 deletions(-) diff --git a/documentation/docs/architecture/09_architecture_decisions/adr_0020.md b/documentation/docs/architecture/09_architecture_decisions/adr_0020.md index adc204282a..dab19dab88 100644 --- a/documentation/docs/architecture/09_architecture_decisions/adr_0020.md +++ b/documentation/docs/architecture/09_architecture_decisions/adr_0020.md @@ -113,12 +113,37 @@ expression: | 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. (maybe?) **Automatic Translation**: Provide tooling or documentation to help users translate existing `anyOf` rules to CEL expressions. -3. (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. -4. **Documentation**: Create extensive documentation with examples showing common patterns and migration guides. -5. **Proposed Deprecation Path**: - - Version 5.x: Introduce CEL support alongside existing syntax and mark `anyOf` as deprecated with warnings - - Version 6.0.0: Remove support for `anyOf` syntax + +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 @@ -139,6 +164,17 @@ To ensure backward compatibility and smooth migration: 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