Cedar Policy Language

repository·main·Indexed 23 days ago

https://github.com/cedar-policy/cedar

Cedar is an expressive, performant, and analyzable policy language designed for fine-grained authorization (RBAC/ABAC) in applications, allowing developers to separate authorization logic from application code. The project includes the Cedar CLI for evaluating expressions, validating policies against schemas, and authorizing requests using entities and policy templates.

Tokens
49.8K
Snippets
118
Records
307
Agent score
81%

What's inside Cedar

  1. Overview of Cedar crates

    main

    The Cedar workspace contains several specialized crates:

    • cedar-policy: The main crate for authorization and policy validation against a schema.
    • cedar-policy-symcc: Contains the symbolic compiler for verifying policy properties with counterexamples.
    • cedar-policy-cli: A command-line interface for interacting with Cedar.
    • cedar-language-server: Implementation of the Cedar Language Server.
    • cedar-wasm: Provides a WebAssembly interface for using Cedar with JavaScript and TypeScript.
    • cedar-policy-core: (Internal) Core components like parser, evaluator, and typechecker.
    • cedar-policy-formatter: (Internal) Auto-formatter for Cedar policies.
    • cedar-testing: (Internal) Integration testing code.
  2. What is Context in Cedar policies

    main

    In Cedar, the context element provides additional information about the circumstances of an authorization request. It is used to pass dynamic data that is not persisted within the policy itself but is relevant to making authorization decisions at evaluation time.

    Common examples of context attributes include:

    • Date and time
    • IP addresses
    • Authentication methods
    • Custom application-specific data

    These attributes are passed into the evaluation engine during each request and can be referenced within policy conditions to implement fine-grained, environment-aware access control.

  3. What is Symbolic Cedar Compiler (SymCC)?

    main

    SymCC is a library that compiles Cedar policies into logical constraints in SMT-LIB format. It allows you to formally verify properties of your Cedar policies using an SMT solver. If a property is violated, SymCC can produce a concrete counterexample consisting of a synthesized request and entity store.

    Supported properties include:

    • Policy never errors: CedarSymCompiler::check_never_errors
    • Policy set always allows: CedarSymCompiler::check_always_allows
    • Policy set always denies: CedarSymCompiler::check_always_denies
    • Policy set subsumption: CedarSymCompiler::check_implies
    • Policy set equivalence: CedarSymCompiler::check_equivalent
    • Policy set disjointness: CedarSymCompiler::check_disjoint

    Each of these has a *_with_counterexample counterpart (e.g., check_always_allows_with_counterexample) that returns a synthesized request and entity store if the property is false.

  4. Use the inequality operator (!=) in Cedar policies

    main

    The != operator is a binary operator used to compare two operands of any type. It evaluates to true if the operands have different values or are of different types.

    Constraints:

    • You can only use != within when and unless clauses.
    • The validator requires that != is used on either:
      1. Two expressions of (possibly differing) entity types.
      2. Two expressions of the same non-entity type.
    <value> != <value>
  5. Use the if conditional operator

    main

    The if operator allows for conditional logic within a Cedar policy. It evaluates a boolean expression and returns one of two possible expressions based on the result.

    Syntax: if <boolean> then <T> else <U>

    Behavior:

    • If the condition evaluates to true, the expression <T> is returned.
    • If the condition evaluates to false, the expression <U> is returned.
    • Requirement: The condition must evaluate to a boolean value. If the condition evaluates to any other type or results in an error, the policy evaluation will fail.
    if <boolean> then <T> else <U>
  6. Understand the Principal element in Cedar policies

    main

    In a Cedar policy, the principal element represents the identity (such as a user, service, or other entity) making a request to perform an action on a resource.

    Key rules for the principal element:

    • Matching: A policy statement matches if the principal making the request is equal to the principal defined in the policy.
    • Requirement: The principal element must always be present in a policy statement.
    • Scope: If you specify principal without an expression to constrain its scope, the policy will apply to any principal.
  7. Use the `like` operator for wildcard string matching

    main

    The like operator is a binary operator used to evaluate if a string matches a specific pattern. The pattern can include one or more asterisks (*) which act as wildcards, matching zero or more of any character.

    To match a literal asterisk character instead of using it as a wildcard, use the escaped \* sequence within your pattern string.

    <string> like <string possibly with wildcards>
  8. Conventions for Cedar Error Types

    main

    Cedar follows a specific pattern for implementing errors to ensure API stability and rich diagnostics:

    • Structure: Methods returning errors should return a Result where the error type is a public enum. Each variant should be either another error enum or a single struct with private fields. Structs for a specific error enum are typically grouped in a submodule.
    • Naming: All error enums and structs must end in Error, but individual enum variants must not end in Error.
    • Exhaustiveness:
      • Use #[non_exhaustive] for parsing and validation errors to allow adding new variants without breaking callers.
      • Do not use #[non_exhaustive] for errors returned from the is_authorized API (e.g., EvaluationError), as callers should be forced to handle new variants.
    • Traits: Enums and their member structs should implement miette::Diagnostic and thiserror::Error. Use the #[error(...)] macro for Display implementations.
    • Encapsulation: Keep fields in error structs private. This allows changing error details without breaking the public API. Expose necessary details via public methods on the struct.
    /// The request does not conform to the schema
    #[derive(Debug, Diagnostic, Error)]
    #[non_exhaustive]
    pub enum RequestValidationError {
        /// Request action is not declared in the schema
        #[error(transparent)]
        #[diagnostic(transparent)]
        UndeclaredAction(#[from] request_validation_errors::UndeclaredActionError),
    
        // more error variants...
    }
    
    /// Error subtypes for [`RequestValidationError`]
    pub mod request_validation_errors {
        /// Request action is not declared in the schema
        #[derive(Debug, Diagnostic, Error)]
        #[error(transparent)]
        #[diagnostic(transparent)]
        pub struct UndeclaredActionError(
            #[from] cedar_policy_core::validator::request_validation_errors::UndeclaredActionError,
        );
    
        impl UndeclaredActionError {
            /// The action which was not declared in the schema
            pub fn action(&self) -> &EntityUid {
                RefCast::ref_cast(self.0.action())
            }
        }
    
        // more error structs...
    }
  9. Update templates and reflect changes in linked policies

    main

    When you update a policy template (e.g., by adding a when clause for Attribute-Based Access Control), all existing policies that were linked from that template will automatically reflect the new logic.

    For example, if a template is updated to require a department == "research" attribute, any previously linked policies (like AliceAccess or BobAccess) will immediately start enforcing this new condition during authorization requests, provided you include the --template-linked file in your authorize command.

    @id("AccessVacation")
    permit(
        principal in ?principal,
        action == Action::"view",
        resource == Photo::"VacationPhoto94.jpg"
    ) when {
        principal has department && principal.department == "research"
    };
  10. Choose the correct Cedar WASM sub-package

    main

    The loading behavior of Cedar WASM depends on your environment. Choose one of the following sub-packages:

    • @cedar-policy/cedar-wasm: ES Modules (Default). Best for bundlers. It loads WASM in a way that will be bundled into a single file if you use dynamic imports, or embedded into your main bundle if you use regular imports.
    • @cedar-policy/cedar-wasm/nodejs: CommonJS (for Node). Loads WASM using Node's fs module synchronously. Not designed for bundling or browser use.
    • @cedar-policy/cedar-wasm/web: Web (Customizable). Use this when you need to load the WASM binary in a custom way (e.g., via fetch or manual buffer management).