heimdall icon indicating copy to clipboard operation
heimdall copied to clipboard

Avoid unintended rule precedence across rule sets

Open dadrus opened this issue 10 months ago • 0 comments

Preflight checklist

  • [x] I agree to follow this project's Code of Conduct.
  • [x] I have read and am following this repository's Contribution Guidelines."
  • [ ] I have discussed this feature request with the community.

Describe the background of your feature request

Heimdall’s rule matching uses a radix tree, where more specific path expressions (e.g., /api/**) take precedence over less specific ones (e.g., /**). This works as intended within a single rule set, but across multiple rule sets, it can lead to unintended behavior: a specific rule in one set might take precedence over a general rule in another, even if the latter is meant to define a service’s base behavior. For example, a rule set defining /** for sub.domain.com with authentication could be bypassed by a rule matching /api/** for the same domain but with different settings from a different rule set, due to higher specificity.

This forces rule designers to list all intermediate paths (e.g., /**, /api/**, /api/v2/**) in a "catch-all" rule to ensure consistent behavior, contradicting heimdall’s promise of simplicity - relying on general rules and the default rule.

Describe your idea

Heimdall could automatically "claim" the least specific path defined in a rule set for each host it references, preventing more specific rules in other rule sets from taking precedence unexpectedly. So, rules within the claimed scope (e.g., sub.domain.com/**) prevent more specific rules (e.g., sub.domain.com/api/**) from other rule sets from taking precedence. Deployment of such conflicting rules would result in errors and be rejected.

Are there any workarounds or alternatives?

As written in the background section, a rule set author can claim every possible path expression in a rule set specific "catch-all" rule, which makes the rule set more verbose and undermines heimdall's simplicity promise.

Alternatively, or additionally, one can use a JWT issued by heimdall (which is anyway recommended), enriched with custom claims in a rule’s finalizer step. This creates a contract with the upstream service, which validates the JWT. It mitigates authentication inconsistencies (e.g., sub: "anonymous" is detectable), but a conflicting rule could mimic claims coming from authorization related steps. This approach is not viable for systems unable to validate JWTs (e.g., legacy systems in distrustful decomposition).

Version

0.15.0

Additional Context

No response

dadrus avatar Apr 11 '25 22:04 dadrus