-
Notifications
You must be signed in to change notification settings - Fork 15
Generalizing template placeholders #3
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
mwhicks1
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could clarify the proposal, per the comments.
|
Since I was the one who wrote up this proposal, I can't actually add my approval on GitHub. But, as a maintainer, I do approve of this RFC and think it would add value to the language. (My writing up the proposal from @WanderingStar was perhaps already an implicit endorsement, but I'm making that an explicit endorsement here.) |
|
This RFC makes the limitations in the validator with respect to templates placeholders more of an issue. We always type a template placeholder as With this extension, a valid policy could contain |
|
@john-h-kastner-aws do you envision there being a solution to the validator problem you describe above, or is that a blocking concern for this RFC? For instance, is there a road toward being able to type template placeholders more precisely than Alternately, does this RFC need to wait until we have "typed holes", i.e., explicitly typed template placeholders? (That would be its own RFC, of course.) Alternately, do we need to slim down this RFC so that the feature is restricted in some way such that it doesn't run afoul of the validator issue? (Restricting which operations are legal on template placeholders, for instance) |
The possible extension to the typechecker mentioned in RFC #5 is one path by which we could use With RFC #8 it would become possible to unsoundly access attributes on template placeholders under partial schema validation rules. Alternatively this doesn't have to block if we're happy to let the typechecker reject attribute access expressions while allowing them for customers who don't use a schema. |
Could you typecheck it if you wrote |
No. This could work if we defined the type of a placeholder as the union of all defined entity types and then updated entity LUBs so they have an optional attribute if an attribute does not exist for every element of the LUB, but the type of that attribute is consistent everywhere that it is defined. We would need to think about that more since it might not be sound. This would amount to |
|
In response to @john-h-kastner-aws's comment farther above about the misleadingness of what's labeled Example 2 in the current RFC text: It was proposed in some offline discussion that we restrict This restriction sounds good to me on its face. However, it does end up disallowing the Example 1 that motivated this RFC in the first place. It also disallows the non-numbered example under "Non-proposals" which was suggested as a "fix" for the bad policy there. In short, we have no examples where this RFC actually helps, if we implement this restriction. Further, in the case where the policy scope has |
|
Just to enumerate them, we have approximately three courses of action here as I see it: (given that the restriction proposed above makes the feature meaningless and fails to address the motivating use case)
|
|
Thanks for the further discussion. Thinking a little more about your option 2, I think it works as long as
One question is whether arbitrary names must be instantiated with entities, or whether primitive values are also allowed. A related question is whether templates are validated on their own, or whether they are validated only when they are linked. The latter approach is simplest, but it might be nice to provide more assurance at template creation time. (E.g., you could label slots with types, validate assuming those types, and then check that links provide values of the expected type.) |
|
I think all of this is good discussion and probably belongs in a separate RFC. I'm perfectly OK with the scope restrictions you propose for I was envisioning that the new arbitrary names would only be instantiated with entities, as that still enables some interesting use cases without additional implementation/validation difficulty of allowing other types; and allowing other types could always be a follow-up RFC later, as it would be a backward-compatible change if we write the APIs correctly. Perhaps we should specifically stipulate that the APIs should be written this way. I agree that it would be nice to provide some validation at template creation time, as far as possible. We might not even require typed slots to at least catch some errors (unrelated to the slots). Typed slots sounds like a separate RFC to me, unless you feel it should be included in the same RFC. Note we could do typed slots either before or after the arbitrary-names change. |
|
After some in person discussion yesterday, I have a proposal to support precise typechecking for template placeholders. This builds on the observation that an extension to the typechecker mentioned in the RFC for As proposed there, an expression Without first accepting RFC #5 and implementing As long as the template placeholder appears in the policy scope we would generate some effect constraining its entity type. It would then be possible to access attributes on the template placeholder. |
Looks great! Do you propose to consider doing this as part of this RFC, as it is stated, or perhaps your proposal should be a separate improvement that needs to be implemented before this RFC's implementation can proceed? |
|
@mwhicks1 your update to the RFC text looks great to me. May I propose a tweak to the syntax for discussion: instead of I propose I find this more readable particularly in the multivariable case, where instead of we would have I feel that the first one might on first glance mentally parse as "template ?user", "?resourcebound" which is misleading. I also suspect that the ()s might leave more doors open to add more syntax for other features later. |
I like it. RFC updated. However, whilst updating the text, I thought of another syntax that I actually like a little better. It's given at the bottom under alternatives. What do you think? |
|
I think the While we're proposing syntax tweaks, another possible tweak would be (note the addition of the double-arrow). Not sure if this adds anything vs the existing proposal. |
|
One more question: should we allow including Pros:
Cons:
|
It is proposing they can be any type. Since we are validating only linked policies, and not templates, there is no reason not to do this, that I can see. |
For backward compatibility I'd prefer them to be optional. I don't have a problem if they are included. I lean a little toward warning the user that they are optional, perhaps only in a "verbose warnings" mode, if we have that. |
john-h-kastner-aws
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This all sounds good to me.
|
|
||
| Link-time validation has three drawbacks, though. | ||
|
|
||
| 1. Fundamental errors in a template are not discovered until the template is first linked. E.g., `permit(principal in ?principal,action,resource) when { 1 < "hello" >}` will _always_ be invalid when linked, and it would be nice to know that as early as possible. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial schema validation offers a way around this. We'd still do link-time typechecking, but would be able to report some errors earlier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! If/when we accept this one, we can update the partial-schema RFC to mention this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 partial schema validation could make this a non-issue.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Partial schema validation won't help if we want to be able to automatically analyze policies though. We need precise types and would need something stronger here (type inference).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could analyze a fully linked policy template though, right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, but we also want to analyze templates in their own right. For example, you might want to know if there is a way to instantiate one of your templates so that this instantiation breaks a property you care about.
|
|
||
| All introduced placeholder variables presented so far are assumed to be entities (just like `?principal` and `?resource`). The particular _type_ of the entity is not given, for simplicity. Eliding the type poses a problem for validating templates on their own; we would have to wait to validate a template each time it is linked. However, link-time validation makes it straightforward to allow placeholder variables to have any type (`string`, `bool`, etc.), not just entity types. | ||
|
|
||
| Link-time validation has the benefit that it is lower overhead to write the templates, and potentially more flexible, since the particulars of the types don't need to be spelled out. New types added after the template is created that work with the template don't require changing the template. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be clear, this RFC is proposing that we typecheck templates only when linking?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. So we don't typecheck templates, just template instances. Is that a change from what we do now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. We currently typecheck the template and then when checking a linked template we only need to see that linking won't cause the policy to have type False.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see. Then that's a breaking change. Does the change concern you?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think any existing templates/instantiations will fail to validate after this change: templates typechecking is obviously more permissive, and then typechecking the instantiations (for existing templates with the placeholders in the head) should not be able to cause any errors since it previously typechecked with AnyEntity, and now were typechecking with a specific entity type.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note that we could still do creation-time validation when templates involve only ?principal and ?resource. I just updated the RFC to make this point.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We could, but I'm not convinced that we need to to maintain backwards compatibility.
khieta
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I added some comments from the perspective of someone who hasn't been involved in the discussion so far. Aside from some minor differences of opinion, I approve of this RFC.
|
|
||
| 1. The `?principal` and `?resource` placeholders may appear in the `when`/`unless` conditions of a policy when they also appear in the policy scope. | ||
|
|
||
| 2. Placeholder variables are not limited to `?principal` and `?resource`. A general variable binding mechanism permits introducing additional placeholder variables in the policy, which can appear in the `when`/`unless` conditions. Moreover, these additional variables need not be linked to values of entity type only; any Cedar type is acceptable. Including `?principal` and/or `?resource` in this list is optional; restrictions on their use are enforced either way. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"this list" what list?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see later it's the list in template(...). Would be nice to clean up wording here or show an example of the syntax.
| && ?principal.currentAccessLevel >= 2 | ||
| }; | ||
| ``` | ||
| This template uses `?principal`, an ancestor of `principal`, to be used in the `when` clause (the condition) of the policy. Notice that `?principal` appears in the scope; this is required in order for it to also appear in the condition. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete "to be used"
| ## Use type parameter syntax | ||
|
|
||
| Rather than write `template (?user, ?resourcebound) permit ( principal, ...)` an alternative would be to write `permit<?user,?resourcebound>( principal, ...)`. Using the `<...>` notation resembles parameterization on types used in other languages, as with C++ templates and Java generics. | ||
|
|
||
| The benefit of this syntax is that (1) it does not introduce a new keyword (`template`); (2) a normal policy looks closer to a "template" without parameters; and (3) it follows conventions similar to previous languages. I don't know if the parser would be any harder to write with this alternative syntax. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I slightly prefer this alternative syntax. I feel like template(...) will be confused with @template(...) since prior to this proposed change, annotations were the only construct allowed before permit or forbid.
Of course, we could have special error messages to help guide users in that case. But it still feels a little ugly to me to add a new keyword.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I made a comment above which I should have made inline on this text. Adding it here:
I think the permit<?user,?resourcebound> syntax, while it might be more familiar to C++ or Java programmers, is less readable for less-technically-savvy users, so I'm against it. One of Cedar's goals is to be readable for non-experts and non-programmers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I also don't quite understand the worry about template(...) being confused with @template(...). Is it any different than possible confusion between permit(...) and @permit(...), which could happen today?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fair point about @permit(...). Also a fair point that our target audience may not be familiar with templates in other languages -- I am probably biasing towards permit<?user,?resourcebound> due to C++ experience.
|
|
||
| Link-time validation has three drawbacks, though. | ||
|
|
||
| 1. Fundamental errors in a template are not discovered until the template is first linked. E.g., `permit(principal in ?principal,action,resource) when { 1 < "hello" >}` will _always_ be invalid when linked, and it would be nice to know that as early as possible. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1 partial schema validation could make this a non-issue.
|
|
||
| If a variable is included in the list that does not appear in the actual template, we can issue a warning. | ||
|
|
||
| While all introduced placeholder variables presented so far are assumed to be entities (just like `?principal` and `?resource`), there is no reason why they cannot have arbitrary type. The particular type of the placeholder need not be given, for simplicity. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"there is no reason" are arbitrary-typed placeholder variables in scope for this RFC, or is that a proposed future extension? If this will be included as part of the current RFC it would be nice to see some concrete examples. The string and long cases are easy, but I wonder if there's anything difficult about supporting placeholder variables that have type record or set.
|
The final comment period (FCP) for this RFC is starting now, with intent to accept this RFC. There seems to be broad support for the RFC, and in the core team's judgment the few outstanding questions remaining above are minor and it seems likely they can be resolved before the end of the FCP. The FCP will end Wednesday 2023-07-05 at noon PT / 3pm ET / 7pm UTC. If no new unresolved major objections are voiced by then, this RFC will be merged. For more on the RFC process, see https://github.com/cedar-policy/rfcs. |
This also presents a problem for any tools that need to perform automated reasoning over templates. Doing so requires precise type information, which is lost with the fully generalized approach for templates. I think there is independent value in allowing I propose that we adopt this extension alone. Arbitrary placeholders can be added independently later, if there is need and we have had time to think through their ramifications for type checking analysis. |
This was the original proposal in this RFC, and was rejected in favor of this expanded version. See the comments above, especially this one and the discussion surrounding it |
Ack. I missed this part (the thread has gotten long!). In that case, I vote for option I do like the idea of generalized templates, but we may also want to be able to analyze them, which requires supporting some way to constrain the type of arbitrary placeholders. |
In retrospect I think we should have made a new RFC after that discussion, rather than just updating this one and greatly expanding its scope :) Lesson learned for the future |
We have been iterating on this for a long time, and the need for generalizing templates seems clear: We have a particular use-case that seems well justified, and we have a general principle that all dynamically-created policies should be templatizable so that we can (a) avoid code injection attacks, and (b) make sense of the overall possible permissions states by storing policies in one place. I take the point that we will want to analyze templates in advance. That speaks to having creation-time (strict) validation. What about going with the proposal at the end of the RFC that involves labeling placeholder variables with their expected type? |
|
After reading the RFC, I think it could benefit from saying something about the new format of a template link. I'm pretty sure the intent is to make the obvious generalization of the current design where the link contains a map from placeholder name to value, but now there can be placeholder names other than just The next related question is what the API to add a template link will look like. Currently, we have |
Yes, I think the alternative should address creation-time strict validation. Note though that we might want to have a more detailed discussion about the syntax etc. in a separate RFC, and also to address Matt's comments above. Re syntax: it might be redundant / confusing to support this form of type annotation for templates, and then also support the |
why in a separate RFC? This is the RFC that's about exactly this change, shouldn't the discussion be here? |
I'm fine with either. Was hoping that we can figure out an easier way to keep track of all the conversation threads in the new RFC :) |
|
We (Cedar maintainers) are aborting the FCP for this RFC due to additional concerns raised above and at the maintainers meeting. It will be returned to Pending state for revisions; the intent is to revert this RFC back to closer to its original form (more narrow in scope). The other generalizations (arbitrary template placeholders and/or arbitrary types for placeholders) can be discussed in separate RFCs if anyone wants to open them. |
|
More status updates: I'm personally abandoning this RFC and will be closing it. That said, I hope this general topic and use-case will be taken up in a future RFC, and there's a chance that it could even be me that opens a new RFC on this topic in the future. The proposal in the most recent comment -- to revert this RFC back to closer to its original form, but with the restriction that I hope that someday we find a way to introduce the broader feature, with arbitrary template placeholders of arbitrary types, but this has some fundamental issues that came up during FCP, and needs more thought. At this point I think everyone agrees that should be a new RFC which may or may not look different from this one. Rather than push through a very restricted version of this RFC that doesn't solve the actual motivating problems, I'd rather hold out for that future better RFC that actually solves problems. |
|
For what it's worth, we've implemented a proof of concept that uses an external templating mechanism to accomplish this and cedar-policy/cedar#106 without relying on template linking. The resulting policies are obviously less space efficient than the template links, but we have full control over them. Annotations let us link the populated policies back to their template sources. |
|
I have a couple of more usecases for this feature, both stepping from Association constraints for constrained roles. Usecase Without this feature, one could implement this pattern is based on creating a static policy per role and loading the associated projects from a database. an example of this is below // Constrained Approver Role - Associated Projects The problem with this option is that permissions management is being stored in the database storing associated projects. This does not fulfil the purpose of AVP/cedar, as a part of your authz data lies with the DB. A better way to solve this if this feature was available is to create a template linked policy when a user is granted a role and a project is assigned to the user. The template would like lie and the corresponding template linked policy that gets created when Joe is assigned "timesheet viewer" role in paris and london would be like below. |
I don't know that I believe this statement, that information relevant to permissions management should not live outside of your policy store. Reasons that I think it would make sense:
This is not to say that what you propose is not a reasonable approach, and thus justification for this RFC. I am pointing out that there are other ways to do it, and reason to believe that customers might prefer those alternatives. |
|
I am in favor of this proposal. It would be ideal to have a template which can take an arbitrary slot like The only options I have are to create different templates for the different slot values, but we have too many values for that approach. So, we could not use templates and just write policies directly - but we like the ability to modify aspects of the template. So, what we do is we fetch that slot value and pass it into the authorization request. Its extra latency on every auth call, and worse - its a fragmented permissions environment. Introduction of a bug into our secondary "supplemental policy" store is a possibility. |
|
What would it take for this proposal to be reopened? Its also unclear why this proposal is rejected based upon the comment thread.
As a customer I disagree with this statement. I want all information relevant to permissions management to live within the policy store. If I fetch information from other places, then that introduces consistency concerns and opens vulnerabilities. Do any other permission stores rely on user input to verify permissions? That seems like an easy way to spoof permissions. |
This RFC was created from (migrated from) cedar-policy/cedar#81.
Rendered
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.