Title
#help
o

Owen Cummings

11/07/2022, 11:39 PM
I am getting an error when using the PlanResources API that does not occur when I use the CheckResources API. It seems like it is a bug, but wanted some guidance in case I am doing something wrong I’ve determined that it is due to my Derived Roles, specifically
location_roles: P.attr.roles[R.attr.location_id]
If I hard code this to location_roles: P.attr.roles["1"]everything seems to work as expected.
apiVersion: api.cerbos.dev/v1
variables: 
  location_roles: P.attr.roles[R.attr.location_id]
derivedRoles:
  name: my_roles
  definitions:
    - name: global_admin
      parentRoles:
        - user
      condition:
        match:
          expr: ("Global Admin" in V.location_roles)
{"log.level":"info","@timestamp":"2022-11-07T23:34:00.201Z","log.logger":"cerbos.payload","message":"server request payload logged as grpc.request.content field","system":"grpc","span.kind":"server","grpc.service":"cerbos.svc.v1.CerbosService","grpc.method":"PlanResources","peer.address":"127.0.0.1:52082","http":{"x_forwarded_for":["172.17.0.1"],"x_forwarded_host":["localhost:3592"]},"grpc.request.content":{"msg":{"action":"entry:read","principal":{"id":"1","policyVersion":"default","roles":["user"],"attr":{"employee_id":"123","permissions":{"1":["entry.read_all"]},"roles":{"1":["Employee"]}}},"resource":{"kind":"entry","attr":{"location_id":"1"},"policyVersion":"default"},"includeMeta":true}}}
{"log.level":"error","@timestamp":"2022-11-07T23:34:00.203Z","log.logger":"cerbos.grpc","message":"Resources query plan request failed","grpc.start_time":"2022-11-07T23:34:00Z","system":"grpc","span.kind":"server","grpc.service":"cerbos.svc.v1.CerbosService","grpc.method":"PlanResources","peer.address":"127.0.0.1:52082","http":{"x_forwarded_for":["172.17.0.1"],"x_forwarded_host":["localhost:3592"]},"cerbos":{"call_id":"01GHA734RAWRPKZD2E4NGASBH1"},"error":"error evaluating condition \"(\\\"Employee\\\" in V.location_roles)\": invalid qualifier type: *structpb.Value"}
{"log.level":"error","@timestamp":"2022-11-07T23:34:00.203Z","log.logger":"cerbos.grpc","message":"Handled request","grpc.start_time":"2022-11-07T23:34:00Z","system":"grpc","span.kind":"server","grpc.service":"cerbos.svc.v1.CerbosService","grpc.method":"PlanResources","cerbos":{"call_id":"01GHA734RAWRPKZD2E4NGASBH1"},"peer.address":"127.0.0.1:52082","http":{"x_forwarded_for":["172.17.0.1"],"x_forwarded_host":["localhost:3592"]},"error":"rpc error: code = Internal desc = Resources query plan request failed","grpc.code":"Internal","grpc.time_ms":2.047}
Dennis (Cerbos)

Dennis (Cerbos)

11/07/2022, 11:48 PM
This looks like a bug. Thanks for reporting it. But even if the call succeeded, the produced AST would be complex. I’d suggest another way to write the expression.
11:51 PM
I’ll post the alternative expression in a few minutes.
o

Owen Cummings

11/07/2022, 11:52 PM
Cool thanks, I was also wondering if I was overcomplicating things. Basically trying to model multiple roles in a multi-tenant system with support for custom roles
Dennis (Cerbos)

Dennis (Cerbos)

11/07/2022, 11:57 PM
Something like:
R.attr.location_id in P.attr.roles.filter(x, P.attr.roles[x].exists(y, y == "Global Admin"))
In the above expression the RHS can be pre-evaluated, so the produced AST can be simple
R.attr.location_id in [<list of constants>]
o

Owen Cummings

11/08/2022, 12:29 AM
Are there any resources available that describe “the right way” to design policies?
Dennis (Cerbos)

Dennis (Cerbos)

11/08/2022, 12:38 AM
Well, I’d say your policy is written in a very neat and idiomatic way. It is the query planner that introduces some nuances. Ideally, it should be smart enough to produce the
R.attr.location_id in <list of constants>
. If your question is more general, there’s a tutorial https://docs.cerbos.dev/cerbos/latest/tutorial/00_intro.html that gives an example of how to design the policy.
o

Owen Cummings

11/08/2022, 12:41 AM
gotcha, I guess I was wondering how you just looked at my policy and then knew the query planner would produce a complex AST. If there were any guidance on what to avoid
Dennis (Cerbos)

Dennis (Cerbos)

11/08/2022, 12:44 AM
Generally, the AST looks complex when
P
and
R
are both present in the struct indexing expression like in your
P.attr.roles[R.attr.location_id].
My trick was to separate them into subexpressions.
o

Owen Cummings

11/08/2022, 12:46 AM
ah, super helpful, thanks!
Dennis (Cerbos)

Dennis (Cerbos)

11/08/2022, 12:57 AM
I’ve created an issue to track the bug
5:06 AM
I can’t reproduce the original problem with Cerbos v0.22.0, which we have just released. Can you please try the latest version if you haven’t yet?
o

Owen Cummings

11/08/2022, 4:51 PM
I was reproducing with 0.22 I will get you a repro case
5:13 PM
Repro attached to the issue, assuming playground is running 0.22.0
Dennis (Cerbos)

Dennis (Cerbos)

11/08/2022, 6:14 PM
Thank you!
9:54 PM
I didn’t notice at first that the request contains the resource attribute location_id equal “1”. The query planner takes all known attributes into account, so the response should be unconditional “KIND_ALWAYS_ALLOWED”. It gives an error instead…