Just me learning about Cedar.
Why?
- It seems more fitting for application-level authorization than something like Open Policy / Rego.
- It has AWS' backing and has been rigorously tested.
- It's compatible with AWS Verified Permissions, a managed fine-grained authorization service.
- There's even a Terraform module for that coming soon!
I'm using one tool here:
- The
cedar
CLI- Supports linting, checking, formatting, validating, etc.
- Available in the pkgx package manager:
pkgx --sync cedar
We can perform authorization checks with the Cedar CLI by pointing it at our data and policies, and letting it evaluate an authorization decision for a given principal (user), action (read), and resource (classroom).
We illustrate how authorization works by borrowing examples from Harry Potter.
Check out the docs folder for details.
See policies.cedar.
If you want to torture yourself by looking at JSON, see the entities directory, or entities.json (which is just the concatenation of all those files).
In production, we could use an event-driven architecture with OPAL to sync data changes from a database into Cedar Agent.
Examples of data changes include:
- a teacher joins/leaves a school
- a teacher is assigned/unassigned a classroom
- a classroom gets created/destroyed
- a student enrolls/un-enrolls from a classroom
The answer is as you'd expect:
- Administrators of Hogwarts School of Witchcraft and Wizardry can view classrooms at Hogwarts.
- Administrators of any higher-level org units — of which Hogwarts is a descendant — may view classrooms at Hogwarts.
- Any teachers at Hogwarts that directly teach the class may view the classroom.
for i in \
Platform::Admin::\"dumbledore@hogwarts.edu\" \
Platform::Teacher::\"snape@hogwarts.edu\" \
Platform::Teacher::\"aurora.sinistra@hogwarts.edu\" \
Platform::Admin::\"maxime@beauxbatons.edu\" \
Platform::Teacher::\"molina@beauxbatons.edu\" \
Platform::Admin::\"barty.crouch@ministry.edu\" \
Platform::Teacher::\"arthur.weasley@ministry.edu\" \
Platform::Admin::\"president@magical_congress_usa.edu\" \
Platform::Teacher::\"teacher@magical_congress_usa.edu\" \
; do \
echo "\n\n~~~" ; \
echo $i ; \
cedar authorize \
--schema examples/schema.json \
--policies examples/policies.cedar \
--entities examples/entities.json \
--principal $i \
--action Platform::Action::\"viewClassroom\" \
--resource Platform::Classroom::\"hogwarts_astronomy\" ; \
done
The output looks like the following:
User | Result | Reason |
---|---|---|
dumbledore | ALLOW 🧙 | He administrates Hogwarts |
snape | DENY 🙅 | Does not teach Astronomy |
sinistra | ALLOW 🧙 | She teaches Astronomy 🔮 at Hogwarts |
maxime | DENY 🙅 | Admin at a completely different school |
molina | DENY 🙅 | Teaches at a completely different school |
barty.crouch | ALLOW 🧙 | Administrates a higher level org unit that oversees Hogwarts |
arthur.weasley | DENY 🙅 | Teaches at the Ministry, but is not an admin |
president | DENY 🙅 | Admin at a higher-level org unit, but one that isn't reachable |
# Start Cedar Agent
cedar-agent
# Upload policies and data to server
xc cedar_agent
# Perform authz check
http POST http://localhost:8180/v1/is_authorized \
principal="Platform::Teacher::\"aurora.sinistra@hogwarts.edu\"" \
action="Platform::Action::\"viewClassroom\"" \
resource="Platform::Classroom::\"hogwarts_astronomy\""
- Policy Templates
- We can't write a distinct policy for every principal/resource combination. That would be crazy
- One-liner to stringify all policies into one JSON file
- Calling this from Golang services?
- See the Go SDK for AWS Verified Permissions
- Also see Cedar Agent's REST API
Merges all entities and policies into entities.json
and policies.cedar
, respectively.
jq -s '.[0]=([.[]]|flatten)|.[0]' examples/entities/*.json > examples/entities.json
cat examples/policies/* > examples/policies.cedar
Check that policy successfully parses.
cedar check-parse \
--policies examples/policies.cedar
Validates the policy against the schema.
cedar validate \
--schema examples/schema.json \
--policies examples/policies.cedar
Upload policies and data to Cedar Agent
for i in examples/policies/*.cedar ; do \
echo $(basename $i .cedar) ; \
cp $i cedar-agent/ ; \
# Strip comments
sd '(\t| )*//.*$' '' cedar-agent/$(basename $i) ; \
# Strip newlines
sd \\n+ ' ' cedar-agent/$(basename $i) ; \
# Condense whitespaces into one
sd \\s+ ' ' cedar-agent/$(basename $i) ; \
# Escape double-quotes
#sd \" '\\"' cedar-agent/$(basename $i) ; \
# Build a JSON policy
jq -n '[{id: $id, content: $content}]' \
--arg id "$(basename $i .cedar)" \
--arg content "$(cat cedar-agent/$(basename $i))" > cedar-agent/$(basename $i .cedar).json ; \
# Execute HTTP Request
curl -X PUT \
-H "Content-Type: application/json" \
-d @./cedar-agent/$(basename $i .cedar).json \
http://localhost:8180/v1/policies ; \
done
curl -X PUT \
-H "Content-Type: application/json" \
-d @./examples/entities.json \
http://localhost:8180/v1/data