Using Open Source Cedar to Write and Enforce Custom Authorization Policies
Cedar is an open source language and software development kit (SDK) for writing and enforcing authorization policies for your applications. You can use Cedar to control access to resources such as photos in a photo-sharing app, compute nodes in a micro-services cluster, or components in a workflow automation system. You specify fine-grained permissions as Cedar policies, and your application authorizes access requests by calling the Cedar SDK’s authorization engine. Cedar has a simple and expressive syntax that supports common authorization paradigms, including both role-based access control (RBAC) and attribute-based access control (ABAC). Because Cedar policies are separate from application code, they can be independently authored, analyzed, and audited, and even shared among multiple applications.
In this blog post, we introduce Cedar and the SDK using an example application, TinyTodo, whose users and teams can organize, track, and share their todo lists. We present examples of TinyTodo permissions as Cedar policies and how TinyTodo uses the Cedar authorization engine to ensure that only intended users are granted access. A more detailed version of this post is included with the TinyTodo code.
TinyTodo allows individuals, called
Users, and groups, called
Teams, to organize, track, and share their todo lists.
Lists which they can populate with tasks. As tasks are completed, they can be checked off the list.
We don’t want to allow TinyTodo users to see or make changes to just any task list. TinyTodo uses Cedar to control who has access to what. A
List‘s creator, called its owner, can share the list with other
Teams. Owners can share lists in two different modes: reader and editor. A reader can get details of a
List and the tasks inside it. An editor can do those things as well, but may also add new tasks, as well as edit, (un)check, and remove existing tasks.
We specify and enforce these access permissions using Cedar. Here is one of TinyTodo’s Cedar policies.
This policy states that any principal (a TinyTodo
User) can perform any action on any resource (a TinyTodo
List) as long as the resource has an
owner attribute that matches the requesting principal.
Here’s another TinyTodo Cedar policy.
This policy states that any principal can read the contents of a task list (
Action::"GetList") so long as they are in either the list’s
readers group, or its
Cedar’s authorizer enforces default deny: A request is authorized only if a specific
permit policy grants it.
The full set of policies can be found in the file TinyTodo file
policies.cedar (discussed below). To learn more about Cedar’s syntax and capabilities, check out the Cedar online tutorial at https://www.cedarpolicy.com/.
To build TinyTodo you need to install Rust and Python3, and the Python3
requests module. Download and build the TinyTodo code by doing the following:
cargo build command will automatically download and build the Cedar Rust packages
cedar-policy-validator, and others, from Rust’s standard package registry,
crates.io, and build the TinyTodo server,
tiny-todo-server. The TinyTodo CLI is a Python script,
tinytodo.py, which interacts with the server. The basic architecture is shown in Figure 1.
Let’s run TinyTodo. To begin, we start the server, assume the identity of user
andrew, create a new todo list called
Cedar blog post, add two tasks to that list, and then complete one of the tasks.
toggle_task commands are all authorized by the Cedar
Policy 1 we saw above: since
andrew is the owner of
List ID 0, he is allowed to carry out any action on it.
Now, continuing as user
andrew, we share the list with team
interns as a reader. TinyTodo is configured so that the relationship between users and teams is as shown in Figure 2. We switch the user identity to
aaron, list the tasks, and attempt to complete another task, but the attempt is denied because
aaronis only allowed to view the list (since he’s a member of
interns) not edit it. Finally, we switch to user
kesha and attempt to view the list, but the attempt is not allowed (
interns is a member of
temp, but not the reverse).
get_list command is authorized by the Cedar
Policy 2 we saw above, since
aaron is a member of the Team
andrew made a reader of
get_list commands are both denied because no specific policy exists that authorizes them.
Extending TinyTodo’s Policies with Administrator Privileges
We can change the policies with no updates to the application code because they are defined and maintained independently. To see this, add the following policy to the end of the
This policy states that any
user who is a member of
Team::"Admin” is able to carry out any action on any
List (all of which are part of the
Application::"TinyTodo" group). Since user
emina is defined to be a member of
Team::"Admin" (see Figure 2), if we restart TinyTodo to use this new policy, we can see
emina is able to view and edit any list:
Enforcing access requests
When the TinyTodo server receives a command from the client, such as
toggle_task, it checks to see if that command is allowed by invoking the Cedar authorization engine. To do so, it translates the command information into a Cedar request and passes it with relevant data to the Cedar authorization engine, which either allows or denies the request.
Here’s what that looks like in the server code, written in Rust. Each command has a corresponding handler, and that handler first calls the function
self.is_authorized to authorize the request before continuing with the command logic. Here’s what that function looks like:
The Cedar authorization engine is stored in the variable
self.authorizer and is invoked via the call
self.authorizer.is_authorized(&q, &self.policies, &es). The first argument is the access request
&q — can the
resource with an empty context? An example from our sample run above is whether
User::"kesha" can perform action
Action::"GetList" on resource
List::"0". (The notation
Type::"id" used here is of a Cedar entity UID, which has Rust type
cedar_policy::EntityUid in the code.) The second argument is the set of Cedar policies
&self.policies the engine will consult when deciding the request; these were read in by the server when it started up. The last argument
&es is the set of entities the engine will consider when consulting the policies. These are data objects that represent TinyTodo’s
Lists, to which the policies may refer. The Cedar authorizer returns a decision: If
Decision::Allow then the TinyTodo command can proceed; if
Decision::Deny then the server returns that access is denied. The request and its outcome are logged by the calls to
We are just getting started with TinyTodo, and we have only seen some of what the Cedar SDK can do. You can find a full tutorial in
TUTORIAL.md in the
tinytodo source code directory which explains (1) the full set of TinyTodo Cedar policies; (2) information about TinyTodo’s Cedar data model, i.e., how TinyTodo stores information about users, teams, lists and tasks as Cedar entities; (3) how we specify the expected data model and structure of TinyTodo access requests as a Cedar schema, and use the Cedar SDK’s validator to ensure that policies conform to the schema; and (4) challenge problems for extending TinyTodo to be even more full featured.
Cedar and Open Source
Cedar is the authorization policy language used by customers of the Amazon Verified Permissions and AWS Verified Access managed services. With the release of the Cedar SDK on GitHub, we provide transparency into Cedar’s development, invite community contributions, and hope to build trust in Cedar’s security.
All of Cedar’s code is available at https://github.com/cedar-policy/. Check out the roadmap and issues list on the site to see where it is going and how you could contribute. We welcome submissions of issues and feature requests via GitHub issues. We built the core Cedar SDK components (for example, the authorizer) using a new process called verification-guided development which as explained in this Amazon Science blog post, provides extra assurance that they are safe and secure. To contribute to these components, you can submit a “request for comments” and engage with the core team to get your change approved.
To learn more, feel free to submit questions, comments, and suggestions via the public Cedar Slack workspace, https://cedar-policy.slack.com. You can also complete the online Cedar tutorial and play with it via the language playground at https://www.cedarpolicy.com/.