I have a policy that I think might be simplified w...
# help
j
I have a policy that I think might be simplified with some additional features added to Cerbos. But perhaps there is already a better way. Let's say I'm creating the authz for a ticketing system like JIRA. Now I want to restrict which roles can "update". I essentially want to do this:
Copy code
if (ticketStatus in ["OPEN", "STARTED"]) {
    if (role in [A,B]) -> EFFECT_ALLOW
  } else if (ticketStatus in ["RESOLVED"]) {
   if (role in [C,D,E]) -> EFFECT_ALLOW
  } else {
   if (role in [F,G]) -> EFFECT_ALLOW
  }
So for certain ticket statuses, only certain roles can do an "update". That's dead simple in Cerbos. The problem is the else branch. The else branch is only executed when the ticket status is not OPEN, STARTED, or RESOLVED. But I do not want to have to repeat that condition in another rule. Here's how I've handled it:
Copy code
variables:
    local:
      conditionA: R.attr.status in ["OPEN", "STARTED"]
      conditionB: R.attr.status == "RESOLVED"
  rules:
    - actions:
        - "update"
      effect: EFFECT_ALLOW
      roles:
        - A
        - B
      condition:
        match:
          expr: V.conditionA

    - actions:
        - "update"
      effect: EFFECT_ALLOW
      roles:
        - C
        - D
        - E
      condition:
        match:
          expr: V.conditionB

    - actions:
        - "update"
      effect: EFFECT_ALLOW
      roles:
        - F
        - G
      condition:
        match:
          none:
            of:
              - expr: V.conditionA
              - expr: V.conditionB
This works, but it's not that elegant and there's likely some performance impact as the condition variables may be evaluated ahead of time even if there's no matching rule based on role. Rules can already have names. It would be nice if I can access the condition by rule name. So maybe something like this:
Copy code
rules:
    - actions:
        - "update"
      name: ruleA
      effect: EFFECT_ALLOW
      roles:
        - A
        - B
      condition:
        match:
          expr: R.attr.status in ["OPEN", "STARTED"]

    - actions:
        - "update"
      name: ruleB
      effect: EFFECT_ALLOW
      roles:
        - C
        - D
        - E
      condition:
        match:
          expr: R.attr.status == "RESOLVED"

    - actions:
        - "update"
      effect: EFFECT_ALLOW
      roles:
        - F
        - G
      condition:
        match:
          none:
            of:
              - expr: rule.ruleA.conditionA
              - expr: rule.ruleB.conditionB
Maybe this already exists and I just couldn't find it in the docs. I thought the rule name was more for logging/debugging. So my guess is this is not currently possible. Is there a better way of handling this that I haven't thought of? Thanks!
c
Hi. I'd model the scenario in the same way as you have. Yes, it's a bit verbose but that's kind of by design because we wanted the policies to be readable by even those who are not very familiar with programming. It's not possible for rules to refer to other rules. While it would be nice to be able to do that, introducing such indirections can make policies hard to understand and open more avenues for mistakes by policy authors. We try hard to strike a balance between being good enough to model most authorization logic and turning into a YAML-based programming language 🙂
j
Understood, thanks!