-
Notifications
You must be signed in to change notification settings - Fork 15
Description
I'm looking to gather use cases for an extension type for paths. I see value in it, and @emina suggested seeing about whether other people have a need for it as well before writing up an RFC. So, I guess I'm asking folks to comment on this about their use cases for path matching in policies.
Many filesystem and filesystem-like use cases (AWS S3, URLs, etc.) have identifiers that encode a tree hierarchy, i.e. paths. Policies for these use cases often include matching against certain components of the path but not others.
A path of a fixed length can be modeled directly as a record (as with the colon-separated parts of an AWS ARN) but not for a path of variable length (as with the last component of many ARNs).
A path of variable length can, of course, be modeled with hierarchy, but this can be significant overhead especially when parents are implicit and may not actually exist as entities themselves (e.g., in URLs).
It can also be modeled with tags, splitting the path into tags, for example a path "foo/bar/baz" modeled as tags "path1": "foo", "path2": "bar", "path3": "baz". Then matching a path like foo/*/baz is:
resource.hasTag("path1") && resource.getTag("path1") == "foo"
&&
resource.hasTag("path2") && resource.getTag("path2") like "*" // can be omitted
&&
resource.hasTag("path3") && resource.getTag("path3") == "baz"
&&
! resource.hasTag("path4")
This certainly works, but is pretty awkward, and might not be obvious to Cedar users (I know it took me some time to work out). Packaging it up as a Path type seems useful. You'd have a .getComponent(i) function. It seems like .getLength() might not be workable, but boolean comparator functions for length like .lengthEquals(n) might work? .hasComponent(i) is equivalent to .lengthGreaterThanOrEqualTo(i+1) at least, and ! .hasComponent(i) to .lengthLessThan(i+1). Maybe they could only take constants?
So you'd have something like:
resource.path.lengthEquals(3)
&&
resource.path.getComponent(0) == "foo"
&&
resource.path.getComponent(1) like "*" // can be omitted
&&
resource.path.getComponent(2) == "baz"