Skip to content
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

Merged
merged 8 commits into from
Aug 29, 2024

Conversation

mqf20
Copy link
Contributor

@mqf20 mqf20 commented Aug 4, 2024

@mqf20 mqf20 changed the base branch from release/3.2.x to main August 4, 2024 14:37
@mqf20
Copy link
Contributor Author

mqf20 commented Aug 4, 2024

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?

@khieta
Copy link
Contributor

khieta commented Aug 5, 2024

Hi @mqf20! To pass the DCO check you should include -s in your git commit commands. I believe if you click the "Details" link next to the CI failure it'll take you to a page that explains more.

@khieta
Copy link
Contributor

khieta commented Aug 5, 2024

(Also: thanks for the contribution! I'll tag some reviewers who have familiarity with Go & the TinyTodo app)

@khieta khieta requested a review from aaronjeline August 5, 2024 16:50
@mqf20
Copy link
Contributor Author

mqf20 commented Aug 5, 2024

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?

@cdisselkoen
Copy link
Contributor

You can git commit --amend -s and then force-push to the PR branch

@@ -0,0 +1,76 @@
from tinytodo import *
Copy link
Contributor

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.

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.

Copy link
Contributor

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.

@shaobo-he-aws
Copy link
Contributor

shaobo-he-aws commented Aug 5, 2024

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,

tinytodo
  - policy.cedar
  - tinytodo.cedarschema
  - tinytodo.py
  - ...
  - rust
    - Cargo.toml
    - src
  - go
    - ...

@mqf20
Copy link
Contributor Author

mqf20 commented Aug 6, 2024

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,

tinytodo
  - policy.cedar
  - tinytodo.cedarschema
  - tinytodo.py
  - ...
  - rust
    - Cargo.toml
    - src
  - go
    - ...

Agreed, this sounds neater.

However, the Go implementation does not support some features (templates, schemas), so the Rust and Go implementations are not equivalent.

Copy link

@patjakdev patjakdev left a 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.

tinytodo-go/entities.json Show resolved Hide resolved
for _, e := range diag.Errors {
errs = append(errs, errors.New(e.String()))
}
return false, nil, errors.Join(errs...)

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.

Copy link
Contributor Author

@mqf20 mqf20 Aug 11, 2024

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.

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.

Copy link
Contributor Author

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

tinytodo-go/internal/app/server/context_test.go Outdated Show resolved Hide resolved
tinytodo-go/internal/app/server/entitystore/list.go Outdated Show resolved Hide resolved
tinytodo-go/tinytodo.py Show resolved Hide resolved
@@ -0,0 +1,76 @@
from tinytodo import *

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>
mqf20 added a commit to mqf20/cedar-examples that referenced this pull request Aug 12, 2024
Copy link

@patjakdev patjakdev left a 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,

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.

Copy link
Contributor Author

@mqf20 mqf20 Aug 16, 2024

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>
@mqf20
Copy link
Contributor Author

mqf20 commented Aug 17, 2024

@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>
@mqf20
Copy link
Contributor Author

mqf20 commented Aug 20, 2024

@aaronjeline @shaobo-he-aws do you have any comments on this PR?

Copy link
Contributor

@shaobo-he-aws shaobo-he-aws left a 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.

@mqf20 mqf20 requested a review from patjakdev August 22, 2024 03:57
Copy link
Contributor

@aaronjeline aaronjeline left a 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:

  1. The above comment, if there isn't a clear solution it's fine as is.
  2. Can you adjust the CI to auto-build this?

Signed-off-by: mqf20 <mingqingfoo@gmail.com>
Signed-off-by: mqf20 <mingqingfoo@gmail.com>
Copy link
Contributor

@aaronjeline aaronjeline left a 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 :)

@aaronjeline aaronjeline merged commit 230f291 into cedar-policy:main Aug 29, 2024
8 checks passed
@mqf20 mqf20 deleted the feature/tinytodo-go branch October 3, 2024 13:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants