/cedar-learning

Learning about the Cedar fine-grained authorization engine 📚

Just me learning about Cedar.

Why?

Prerequisites

I'm using one tool here:

  • The cedar CLI
    • Supports linting, checking, formatting, validating, etc.
    • Available in the pkgx package manager: pkgx --sync cedar

Getting Started

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).

Are you familiar with the world of Harry Potter?

We illustrate how authorization works by borrowing examples from Harry Potter.

Check out the docs folder for details.

students

Where are the policies defined?

See policies.cedar.

Where is the data defined?

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

Who can view Hogwarts classrooms?

Cedar CLI

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

Cedar Agent

# 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\""

Further Research

  • 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

Tasks

merge

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_parse

Check that policy successfully parses.

cedar check-parse \
  --policies examples/policies.cedar

validate

Validates the policy against the schema.

cedar validate \
  --schema examples/schema.json \
  --policies examples/policies.cedar

cedar_agent

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