Skip to content

Cedarling Nativity Plan

Michael Schwartz edited this page Nov 11, 2024 · 184 revisions

JS App

  • Needs to call the WASM component using a few javascript lines of code (ideally 1-2)
  • Input from JS component is object
input = { 
           "access_token": "...", 
           "id_token": "...", 
           "userinfo_token": "...", 
           "tx_token": "...",
           "resource": {"id": "12345", "type": "Ticket", "creator": "mike@gluu.org", "organization": "gluu"},
           "action": "View",
           "context": {
                       "ip_address": "54.9.21.201",
                       "network_type": "VPN",
                       "user_agent": "Chrome 125.0.6422.77 (Official Build) (arm64)",
                       "time": "1719266610.98636",
                      }
         }

decision_result = authz(input)

Bootstrap properties

  • CEDARLING_APPLICATION_NAME : Human friendly identifier for this application

  • CEDARLING_POLICY_STORE_URI : Location of policy store JSON, used if policy store is not local, or retreived from Lock Master.

  • CEDARLING_POLICY_STORE_ID : The identifier of the policy store in case there is more then one policy_store_id in the policy store.

  • CEDARLING_LOG_TYPE : off, memory, std_out, lock

  • CEDARLING_LOG_TTL : in case of memory store, TTL (time to live) of log entities in seconds.

  • CEDARLING_LOCAL_JWKS : JWKS file with public keys

  • CEDARLING_LOCAL_POLICY_STORE : JSON object with policy store

  • CEDARLING_JWT_SIG_VALIDATION : Enabled | Disabled -- Whether to check the signature of all JWT tokens. This requires an iss is present.

  • CEDARLING_JWT_STATUS_VALIDATION : Enabled | Disabled -- Whether to check the status of the JWT. On startup, the Cedarling should fetch and retreive the latest Status List JWT from the .well-known/openid-configuration via the status_list_endpoint claim and cache it. See the IETF Draft for more info.

  • CEDARLING_JWT_SIGNATURE_ALGORITHMS_SUPPORTED : Only tokens signed with these algorithms are acceptable to the Cedarling.

  • CEDARLING_AT_ISS_VALIDATION : When enabled, the iss claim must be present in access token and the scheme must be https.

  • CEDARLING_AT_JTI_VALIDATION : When enabled, the jti claim must be present in access token.

  • CEDARLING_AT_NBF_VALIDATION : When enabled, the nbf claim must be present in access token and the Cedarling should verify that the current date is after the nbf.

  • CEDARLING_AT_EXP_VALIDATION : When enabled, the exp claim must be present and not past the date specified.

  • CEDARLING_IDT_ISS_VALIDATION : When enabled, the iss claim must be present in id_token and the scheme must be https.

  • CEDARLING_IDT_SUB_VALIDATION : When enabled, the sub claim must be present in id_token.

  • CEDARLING_IDT_EXP_VALIDATION : When enabled, the exp claim must be present and not past the date specified.

  • CEDARLING_IDT_IAT_VALIDATION : When enabled, the iat claim must be present in id_token.

  • CEDARLING_IDT_AUD_VALIDATION : When enabled, the aud claim must be present in id_token.

  • CEDARLING_USERINFO_ISS_VALIDATION : When enabled, the iss claim must be present and the scheme must be https.

  • CEDARLING_USERINFO_SUB_VALIDATION : When enabled, the sub claim must be present in Userinfo JWT.

  • CEDARLING_USERINFO_AUD_VALIDATION : When enabled, the aud claim must be present in Userinfo JWT.

  • CEDARLING_USERINFO_EXP_VALIDATION : When enabled, the exp claim must be present and not past the date specified.

  • CEDARLING_ID_TOKEN_TRUST_MODE : Strict | None. Varying levels of validations based on the preference of the developer. Strict mode requires (1) id_token aud matches the access_token client_id; (2) if a Userinfo token is present, the sub matches the id_token, and that the aud matches the access token client_id.

The following bootstrap properties are only needed for enterprise deployments.

  • CEDARLING_LOCK : Enabled | Disabled. If Enabled, the Cedarling will connect to the Lock Master for policies, and subscribe for SSE events.

  • CEDARLING_LOCK_MASTER_CONFIGURATION_URI : Required if LOCK == Enabled. URI where Cedarling can get JSON file with all required metadata about Lock Master, i.e. .well-known/lock-master-configuration.

  • CEDARLING_DYNAMIC_CONFIGURATION : Enabled | Disabled, controls whether Cedarling should listen for SSE config updates.

  • CEDARLING_LOCK_SSA_JWT : SSA for DCR in a Lock Master deployment. The Cedarling will validate this SSA JWT prior to DCR.

  • CEDARLING_AUDIT_LOG_INTERVAL : How often to send log messages to Lock Master (0 to turn off trasmission).

  • CEDARLING_AUDIT_HEALTH_INTERVAL : How often to send health messages to Lock Master (0 to turn off transmission).

  • CEDARLING_AUDIT_TELEMETRY_INTERVAL : How often to send telemetry messages to Lock Master (0 to turn off transmission).

  • CEDARLING_LISTEN_SSE : Enabled | Disabled: controls whether Cedarling should listen for updates from the Lock Server.

Cedarling Policy Store

The Cedarling Policy Store is a JSON file that contains all the data the Cedarling needs to verify JWT tokens and evaluate policies:

  1. Cedar Schema - JSON format Schema file
  2. Cedar Policies - JSON format Policy Set file (beware CLI bug cedar-950)
  3. Trusted Issuers - JSON file with below syntax

cedarling_store.json schema

{
    "cedar_version": "v4.0.0",
    "policy_stores": {
            "some_random_id": {
                "name": "",
                "description": "",
                "policies": {...}
                "trusted_issuers": {...},
                "schema": ""
            }
    },
}

Currently cedarling support only one policy_store in policy_stores map.
We have policy_stores map to avoid incompatible change in future.

Trusted Issuer Metadata Schema

This record contains the information needed to validate tokens from this issuer:

{
 "name": "Google", 
 "description": "Consumer IDP", 
 "openid_configuration_endpoint": "https://accounts.google.com/.well-known/openid-configuration",
 "access_tokens": {...},
 "id_tokens": {...},
 "userinfo_tokens": {...},
 "tx_tokens": {...}
}

see below for the "access_tokens", "id_tokens", "userinfo_tokens", and "tx_tokens" schema.

Token Entity Metadata Schema

{
  "user_id": "...",                     <-- OPTIONAL e.g. email, sub, uid
  "role_mapping": "...",                <-- OPTIONAL e.g. role, memberOf
  "claim_mapping": {                    <-- OPTIONAL
                      "email": {
                         "parser": "regex", 
                         "type": "Acme::Email",  
                         "regex_expression" : "^(?P<UID>[^@]+)@(?P<DOMAIN>.+)$", 
                         "UID": {"attr": "uid", "type":"string"}, 
                         "DOMAIN": {"attr": "domain", "type":"string"} 
                      }, 
                      "profile": {
                         "parser": "regex", 
                         "type": "Acme::URI", 
                         "regex_expression": "(?x) ^(?P<SCHEME>[a-zA-Z][a-zA-Z0-9+.-]*):\/\/ (?P<HOST>[^\/:#?]+) (?::(?P<PORT>\d+))?  (?P<PATH>\/[^?#]*)? (?:\?(?P<QUERY>[^#]*))?  (?:#(?P<FRAGMENT>.*))?$",
                         "SCHEME": {"attr": "scheme", "type":"string"}, 
                         "HOST": {"attr": "host", "type":"string"}, 
                         "PORT": {"attr": "port", "type":"string"}, 
                         "PATH": {"attr": "path", "type":"string"}, 
                         "QUERY": {"attr": "query", "type":"string"}, 
                         "FRAGMENT": {"attr": "fragment", "type":"string"}
                      },
                      "dolphin": {
                          "parser": "json", 
                          "type": "Acme::Dolphin"}
                      }
                   }
}

Note use of regex named capture groups which is more readable by referring to parts of a regex match by descriptive names rather than numbers. For example, (?P<name>...) defines a named capture group where name is the identifier, and ... is the regex pattern for what you want to capture.

Cedar Schema

namespace Jans {
    // ******  TYPES  ******
    type Url = {
        protocol: String,
        host: String,
        path: String,
    };
    type email_address = {
        id: String, 
        domain: String,
    };
    type Context = {
            network: ipaddr,
            network_type: String,
            user_agent: String, 
            operating_system: String,
            device_health: Set<String>,
            current_time: Long,
            geolocation: Set<String>,
            fraud_indicators: Set<String>,
    };

    // ******  Entities  ******
    entity Workload  = {
        client_id: String,
        iss: TrustedIssuer,
        name: String,
        spiffe_id: String,
        rp_id: String
    };
    entity Access_token  = {
        aud: String,
        exp: Long,
        iat: Long,
        iss: TrustedIssuer,
        jti: String,
        nbf: Long,
        scope: String,
    };
    entity TrustedIssuer = {
        issuer_entity_id: Url,
    };
    entity Role;
    entity User in [Role] {
        sub: String,
        username: String,
        email: email_address,
        phone_number: String,
        role: Set<String>,
    };
    entity id_token  = {
        acr: Set<String>,
        amr: String,
        aud: String,
        azp: String,
        birthdate: String,
        email: email_address,
        exp: Long,
        iat: Long,
        iss: TrustedIssuer,
        jti: String,        
        name: String,
        phone_number: String,
        role: Set<String>,
        sub: String,
    };
    entity Userinfo_token  = {
        aud: String,
        birthdate: String,
        email: email_address,
        exp: Long,
        iat: Long,
        iss: TrustedIssuer,
        jti: String,
        name: String,
        phone_number: String,
        role: Set<String>,
        sub: String,
    };
    entity HTTP_Request = {
        "url": Url,
        "header": Set<String>,
        "accept": Set<String>,
    };

    // ******  Actions  ******
    action Compare appliesTo {
        principal: [User, Role],
        resource: Workload,
        context: Context,
    };
    action Execute appliesTo {
        principal: [User, Role],
        resource: Workload,
        context: Context,
    };
    action Monitor appliesTo {
        principal: [User, Role],
        resource: Workload,
        context: Context,
    };
    action Read appliesTo {
        principal: [User, Role],
        resource: Workload,
        context: Context,
    };
    action Search appliesTo {
        principal: [User, Role],
        resource: Workload,
        context: Context,
    };
    action Share appliesTo {
        principal: [User, Role],
        resource: Workload,
        context: Context,
    };
    action Tag appliesTo {
        principal: [User, Role],
        resource: Workload,
        context: Context,
    };
    action Write appliesTo {
        principal: [User, Role],
        resource: Workload,
        context: Context,
    };
    action GET appliesTo {
          principal: Workload,
          resource: HTTP_Request,
          context: Context,
    };
    action PUT appliesTo {
        principal: Workload,
        resource: HTTP_Request,
        context: Context,
    };
    action DELETE appliesTo {
        principal: Workload,
        resource: HTTP_Request,
        context: Context,
    };
    action HEAD appliesTo {
        principal: Workload,
        resource: HTTP_Request,
        context: Context,
    };
    action PATCH appliesTo {
        principal: Workload,
        resource: HTTP_Request,
        context: Context,
    };
}

JSON Format

Entity Mapping

  • TrustedIssuer: Created on startup from Policy Store
  • Workload: Created from access token client_id
  • Application: Created if input supplies an Application name
  • Role: Created for each role claim value in the joined id_token and userinfo token
  • User: Created based on the joined id_token and userinfo token. sub is the entity identifier
  • Access_token: 1:1 mapping from claims in token
  • id_token: 1:1 mapping from claims in token
  • Userinfo_token: 1:1 mapping from claims in token

Cederling Agama Lab / AdminUI Mockups

Here

Lock Master Swagger

Swagger UI

Lock Master .well-known metadata

{
  "version": "1.0",
  "issuer": "yurem-evolved-woodcock.gluu.info",
  "audit": {
    "health_endpoint": "https://yurem-evolved-woodcock.gluu.info/jans-lock/v1/audit/health",
    "log_endpoint": "https://yurem-evolved-woodcock.gluu.info/jans-lock/v1/audit/log",
    "telemetry_endpoint": "https://yurem-evolved-woodcock.gluu.info/jans-lock/v1/audit/telemetry"
  },
  "config": {
    "config_endpoint": "https://yurem-evolved-woodcock.gluu.info/jans-lock/v1/config",
    "issuers_endpoint": "https://yurem-evolved-woodcock.gluu.info/jans-lock/v1/config/issuers",
    "policy_endpoint": "https://yurem-evolved-woodcock.gluu.info/jans-lock/v1/config/policy",
    "schema_endpoint": "https://yurem-evolved-woodcock.gluu.info/jans-lock/v1/config/schema",
    "sse_endpoint": "https://yurem-evolved-woodcock.gluu.info/jans-lock/v1/sse"
  }
}

Cedarling logger

Cedarling application has internal logger.

Configuration

Using configuration parameter CEDARLING_LOG_TYPE you can set up:

  • off - disabled
  • memory - store log entry in memory
  • std_out - write log entry data to std output stream
  • lock - centralize logs by sending to Jans Lock Server

Using the memory logger, we can set time to live entry in memory using CEDARLING_LOG_TTL.

Entry types

Each log entry marked with log type. In field log_kind. Possible variants:

  • Decision
  • System
  • Metric

Log Storage interface

pub trait LogStorage {
    /// return logs and remove them from the storage
    fn pop_logs(&self) -> Vec<LogEntry>;

    /// get specific log entry
    fn get_log_by_id(&self, id: &str) -> Option<LogEntry>;

    /// returns a list of all log ids
    fn get_log_ids(&self) -> Vec<String>;
}

Cedarling Startup Sequence

cedarling-startup

Source

Authz Sequence Diagram

Note: no JWT status check

cedarling-authz-sequence-diagram

Source

Topology Diagram

cedarling-lock-topology-concept

Clone this wiki locally