-
Notifications
You must be signed in to change notification settings - Fork 23
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
Add Go example for TinyTodo based on cedar-go #182
Conversation
Hey @andrewmwells-amazon, I've prepared the PR as suggested. There seems to be a problem with DCO sign off, do you need me to sign or does it only concern AWS staff? |
Hi @mqf20! To pass the DCO check you should include |
(Also: thanks for the contribution! I'll tag some reviewers who have familiarity with Go & the TinyTodo app) |
Got it, I just wasn't sure if the signing policy applies only to AWS staff. Should I withdraw this PR and resubmit a new one with a signed commit? |
You can |
@@ -0,0 +1,76 @@ | |||
from tinytodo import * |
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 assume that the go version uses the same "frontend" Python file as the Rust version.. If so, we should also use one copy only.
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.
Agreed, although it's not totally clear to me what value the Python frontend adds over just running go build
and cmd/server
directly. Maybe it lets you interact with the server from a REPL somewhat easily? Dunno.
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 use the Python REPL to interact with the backend server.
A high-level feedback from me is to reuse the files in the existing TinyTodo example (e.g., policies, entities, and Python files) as much as possible, which makes me wonder if we should restructure the TinyTodo folder into something like,
|
Agreed, this sounds neater. However, the Go implementation does not support some features (templates, schemas), so the Rust and Go implementations are not equivalent. |
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.
Thank you so much for writing all of this up and adeptly skirting some of the limitations of the current cedar-go
implementation!
I mostly skimmed over the actual application logic, but I did look more closely at the interface with cedar-go
and had a few questions. I decided to request changes because I think it's pretty important that isAuthorized()
adhere to the Cedar ethos of respecting the policy decision, even in the face of errors.
for _, e := range diag.Errors { | ||
errs = append(errs, errors.New(e.String())) | ||
} | ||
return false, nil, errors.Join(errs...) |
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 may be mistaken, but this doesn't seem to match the behavior of the Rust implementation:
let response = self.authorizer.is_authorized(&q, &self.policies, &es);
info!("Auth response: {:?}", response);
match response.decision() {
Decision::Allow => Ok(()),
Decision::Deny => Err(Error::AuthDenied(response.diagnostics().clone())),
}
That implementation seems to simply log any policy errors and just return the decision, which I think matches the spirit of Cedar's skip-on-error behavior:
The reasoning for the skip-on-error property is more involved. An alternative authorization algorithm we considered would be to Deny a request when any policy evaluation exhibits an error. While this might sound good at first, deny-on-error raises concerns of safety. An application that was working fine with 100 policies might suddenly start denying all requests if the 101st policy has an error. Skip-on-error avoids this dramatic failure mode, and is more flexible: applications can always choose to look at the authorization response’s diagnostics and take a different decision if an evaluated policy produces errors. For more information, see this blog post written by one of the Cedar designers.
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.
You're right, the Go implementation does not match the Rust implementation.
Before I fix the Go implementation, please correct me if I have misinterpreted the Rust implementation (I'm new to Rust):
let response = self.authorizer.is_authorized(&q, &self.policies, &es);
info!("Auth response: {:?}", response);
match response.decision() {
Decision::Allow => Ok(()),
Decision::Deny => Err(Error::AuthDenied(response.diagnostics().clone())),
}
- Returns an empty successful value if the decision is allow
- Returns an error with the diagnostics (errors and reasons) if the decision is deny
Based on Cedar's skip-on-error behavior that you quoted, it seems like the Rust implementation has overlooked a scenario: the decision is allow but errors are present.
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.
Based on Cedar's skip-on-error behavior that you quoted, it seems like the Rust implementation has overlooked a scenario: the decision is allow but errors are present.
I think the Rust implementation is following the spirit of the skip-on-error behavior. If the decision is allow, the request should be authorized, even if there are errors. Those errors are logged via the info!()
macro above the match
statement.
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.
Got it, let me know if this commit is aligned with the Rust implementation
@@ -0,0 +1,76 @@ | |||
from tinytodo import * |
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.
Agreed, although it's not totally clear to me what value the Python frontend adds over just running go build
and cmd/server
directly. Maybe it lets you interact with the server from a REPL somewhat easily? Dunno.
Signed-off-by: mqf20 <mingqingfoo@gmail.com>
d55ec40
to
5ad4eeb
Compare
…y/cedar-examples/pull/182/files#r1705923365) Signed-off-by: mqf20 <mingqingfoo@gmail.com>
Signed-off-by: mqf20 <mingqingfoo@gmail.com>
b6e4303
to
d7a29fa
Compare
…-policy#182 (comment)) Signed-off-by: mqf20 <mingqingfoo@gmail.com>
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.
Looks good! Thanks for taking my feedback.
@@ -14,18 +15,19 @@ import ( | |||
// | |||
// Non-existent entities (resources) will result in an error. (TODO: we may not want this behaviour) | |||
func (s *Server) isAuthorized( | |||
ctx context.Context, |
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.
nit: I'd consider putting this argument last to match the normal PARC order.
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.
In this case, the context here is different from the context in an authorization request (the C in PARC). In the Rust implementation, the authorization request is also missing.
Perhaps I should make this differentiation clearer?
Signed-off-by: mqf20 <mingqingfoo@gmail.com>
@patjakdev I just pushed commit 9839aea to clean up the Go module paths, and commit 98ccf5f to remove an irrelevant file I added by accident |
Signed-off-by: mqf20 <mingqingfoo@gmail.com>
@aaronjeline @shaobo-he-aws do you have any comments on this PR? |
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.
LGTM, as a person who rarely knows Go.
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.
Looks good overall. Two minor requests:
- The above comment, if there isn't a clear solution it's fine as is.
- Can you adjust the CI to auto-build this?
Signed-off-by: mqf20 <mingqingfoo@gmail.com>
Signed-off-by: mqf20 <mingqingfoo@gmail.com>
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.
Looks good, once CI passes :)
Also see cedar-policy/cedar-go#24.