kirino 0.7.10

Zero-trust authentication and authorization framework with RBAC and dynamic risk assessment.
docs.rs failed to build kirino-0.7.10
Please check the build logs for more information.
See Builds for ideas on how to fix a failed build, or Metadata for how to configure docs.rs builds.
If you believe this is docs.rs' fault, open an issue.
Visit the last successful build: kirino-0.7.8

A fully generic, trait-based authentication and authorization framework for Rust. Provides identity types, credential management, passport challenges, a complete RBAC system (RBAC0/1/2) implementing the ANSI INCITS 359-2004 standard, and a dynamic authorization layer with trust scoring, anomaly detection, and DO-178C inspired autonomy levels (L0โ€“L4).

The name kirino comes from the character Kirino in the game Blue Archive.

Still in development, the API may change in the future.

Features

  • ๐Ÿ›ก๏ธ Zero-Trust Architecture: Anonymous, Basic, Temporary, and Service identity types
  • ๐Ÿ”‘ Multi-Credential Support: One-time tokens, JWT, service tokens, and more
  • ๐ŸŽซ Passport Challenges: Static password, key pair, OAuth, TOTP/HOTP, captcha, biometric
  • ๐Ÿ”’ Argon2 Password Hashing: Secure password verification out of the box
  • ๐Ÿ” Password Policy: Bootstrap temporary passwords, forced first-login change and max-age rotation as one kernel rule
  • ๐ŸŽฏ Full RBAC System: RBAC0 (base), RBAC1 (hierarchy), RBAC2 (constraints)
  • ๐Ÿ”„ Role Inheritance: Multi-level role hierarchies with cycle detection
  • โ›“๏ธ Separation of Duty: SSD (static) and DSD (dynamic) constraint enforcement
  • ๐Ÿ“Š Cardinality & Prerequisite Constraints: Limit role holders and enforce role prerequisites
  • โฑ๏ธ Temporal Constraints: Time-bounded role validity with automatic expiry
  • ๐Ÿ’พ In-Memory First: Zero-dependency reference implementations for all backends
  • ๐Ÿ—„๏ธ Pluggable Storage: Trait-based backends for SQL, Redis, and more
  • ๐Ÿ“ Audit Logging: Three-layer composable audit (sink + policy engine + analyzer)
  • ๐Ÿง  Dynamic Authorization: Runtime risk scoring with trust decay, anomaly detection, and domain scoping
  • ๐ŸŽ›๏ธ Autonomy Levels: DO-178C inspired L0โ€“L4 autonomy levels with configurable strategies
  • ๐Ÿ” Anomaly Detection: Sliding-window z-score pattern deviation with adaptive baselines
  • ๐Ÿ“‰ Trust Decay: Configurable exponential trust decay with background worker
  • ๐Ÿงฉ Fully Generic: Define your own Permission and Subject types via traits
  • โšก Async/Tokio: Built on async Rust with Tokio runtime
  • ๐Ÿ”Œ JWT Integration: Built-in JWT issuance and verification

Quick Start

Add kirino to your Cargo.toml:

[dependencies]
kirino = "0.5"
tokio = { version = "1", features = ["full"] }
serde = { version = "1", features = ["derive"] }

Define your permissions and roles:

use kirino::rbac::prelude::*;

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
enum MyPermission {
    DocumentRead,
    DocumentWrite,
    UserManage,
}

impl PermissionTrait for MyPermission {
    fn name(&self) -> &str {
        match self {
            Self::DocumentRead => "document:read",
            Self::DocumentWrite => "document:write",
            Self::UserManage => "user:manage",
        }
    }

    fn domain(&self) -> &'static str {
        match self {
            Self::DocumentRead | Self::DocumentWrite => "document",
            Self::UserManage => "user",
        }
    }
}

fn setup() {
    let mut role_registry = StaticRoleRegistry::new();
    role_registry.register(SimpleRole::new("admin", [
        MyPermission::DocumentRead, MyPermission::DocumentWrite,
        MyPermission::UserManage,
    ].into()));
    role_registry.register(SimpleRole::new("viewer", [
        MyPermission::DocumentRead,
    ].into()));

    let perm_registry = StaticPermissionRegistry::new([
        MyPermission::DocumentRead, MyPermission::DocumentWrite,
        MyPermission::UserManage,
    ].into());

    // Pass plain values โ€” the engine wraps them internally via Shared<Arc>
    let engine = RbacEngine::new(role_registry, perm_registry, InMemoryAssignmentStore::<String, MyPermission>::new());
}

Or use the built-in AuthService for a complete setup:

use kirino::service::login::{AuthService, build_default_engine};
use kirino::database::memory::InMemoryUserDatabase;

let db = InMemoryUserDatabase::new();
let engine = build_default_engine();
let service = AuthService::new(db, "jwt-secret", 24, engine, "admin", "viewer");

Documentation

Multilingual documentation is available:

Language Index
English docs/en/guides/index.md
็ฎ€ไฝ“ไธญๆ–‡ (Simplified Chinese) docs/zh-Hans/guides/index.md
็น้ซ”ไธญๆ–‡ (Traditional Chinese) docs/zh-Hant/guides/index.md
ๆ—ฅๆœฌ่ชž (Japanese) docs/ja/guides/index.md
ํ•œ๊ตญ์–ด (Korean) docs/ko/guides/index.md
ะ ัƒััะบะธะน (Russian) docs/ru/guides/index.md
Espaรฑol (Spanish) docs/es/guides/index.md
Franรงais (French) docs/fr/guides/index.md

Crate-level API documentation is available at docs.rs/kirino.

Architecture

Kirino is a layered authentication and authorization framework:

graph TD
    subgraph SERVICE["Service Layer"]
        AUTH["AuthService<br/>register / login / verify"]
        SESSION["SessionManager<br/>create / activate / destroy"]
    end

    subgraph AUTHN["Authentication Layer"]
        IDENTITY["Identity<br/>Anonymous / Basic / Temporary / Service"]
        CREDENTIAL["Credential<br/>OneTime / JWT / ServiceToken"]
        PASSPORT["Passport<br/>StaticPassword / KeyPair / OAuth / DynamicPassword / Captcha / Biometric"]
    end

    subgraph AUTHZ["Authorization Layer (RBAC)"]
        ENGINE["RbacEngine<br/>check / check_batch / check_hierarchical"]
        STORE["AssignmentStore / RoleStore"]
        CONSTRAINTS["ConstraintValidator<br/>SSD / DSD / Cardinality / Prerequisite"]
        CACHE["PermissionCache<br/>TTL-based LRU"]
        AUDIT["AuditLogger<br/>Sink + PolicyEngine + Analyzer"]
    end

    subgraph DYN["Dynamic Authorization"]
        ARBITER["AuthorizationArbiter<br/>authorize / risk_score / feedback"]
        TRUST["TrustScore + TrustDecayWorker"]
        ANOMALY["AnomalyDetector<br/>Sliding window + z-score"]
        POLICY["DynamicPolicy<br/>5-dim risk + autonomy L0-L4"]
        DOMAIN["TaskDomain + DomainScope"]
    end

    subgraph DB["Database Layer"]
        MEMORY["InMemory Stores<br/>(zero-dependency ref impl)"]
        DYNAMIC["Dynamic Auth<br/>(feature: rbac-dynamic)"]
        CACHE["Permission Cache<br/>(TTL-based)"]
    end

    IDENTITY --> CREDENTIAL --> PASSPORT --> AUTH --> SESSION
    SESSION --> ENGINE
    ENGINE --> STORE
    ENGINE --> CONSTRAINTS
    ENGINE --> CACHE
    ENGINE --> AUDIT
    ENGINE --> ARBITER
    ARBITER --> TRUST
    ARBITER --> ANOMALY
    ARBITER --> POLICY
    ARBITER --> DOMAIN
    ARBITER --> AUDIT
    STORE --> MEMORY
    STORE --> SQL
    CACHE --> REDIS

Core Concepts

Authentication Pipeline

Kirino authenticates users through a three-step pipeline:

flowchart LR
    I["Identity<br/>Who are you?"]
    C["Credential<br/>Prove it"]
    P["Passport<br/>Challenge accepted"]

    I --> C --> P

RBAC Layers

Implements all three levels of the ANSI INCITS 359-2004 RBAC standard:

graph TD
    subgraph RBAC0["RBAC0 โ€” Base"]
        B0["Subject โ†” Role โ†” Permission"]
    end
    subgraph RBAC1["RBAC1 โ€” Hierarchy"]
        B1["Role inheritance with cycle detection"]
    end
    subgraph RBAC2["RBAC2 โ€” Constraints"]
        B2["SSD / DSD / Cardinality / Prerequisite / Temporal"]
    end
    RBAC0 --> RBAC1 --> RBAC2

Decision Flow

flowchart TD
    START(["check(subject, permission)"]) --> CACHE{"Cache hit?"}
    CACHE -->|yes| RETURN_CACHED(["Return cached result"])
    CACHE -->|no| DENIED{"In denied_permissions?"}
    DENIED -->|yes| RETURN_DENY(["DENY โ€” persist to cache"])
    DENIED -->|no| EXTRA{"In extra_permissions?"}
    EXTRA -->|yes| RETURN_ALLOW(["ALLOW โ€” persist to cache"])
    EXTRA -->|no| ROLES["Resolve assigned roles"]
    ROLES --> HIER["Expand role hierarchy"]
    HIER --> CHECK["Permission โˆˆ role permissions?"]
    CHECK -->|yes| RETURN_ALLOW2(["ALLOW โ€” persist to cache"])
    CHECK -->|no| RETURN_DENY2(["DENY โ€” persist to cache"])

Deny-override semantics: Denied permissions always take precedence over granted ones โ€” even over role-based or extra permissions.

Password Policy

Credential hygiene is part of access control, so it lives in the same surface as the permission catalog (rbac::policy) instead of in per-service configuration. PasswordPolicy carries two rules โ€” the bootstrap password must be changed on first login and a password must be changed after N days โ€” behind one master switch, and PasswordPolicy::change_requirement(&state, now) is a pure decision function with the clock injected:

flowchart TD
    STATE["PasswordState<br/>(is_initial, changed_at)"] --> POLICY{"PasswordPolicy<br/>enabled?"}
    POLICY -->|no| OK(["None โ€” continue"])
    POLICY -->|yes| FIRST{"initial password<br/>and switch on?"}
    FIRST -->|yes| REASON1(["InitialPassword"])
    FIRST -->|no| AGE{"age โ‰ฅ max_age_days?"}
    AGE -->|yes| REASON2(["Expired"])
    AGE -->|no| OK

The expiry rule is inclusive: a password that has reached exactly max_age_days is already stale. Callers get a reason enum, not a boolean, so a first-login change (a one-time operator secret) is distinguishable from a routine rotation in API responses and audit records.

First-run bootstrap is one kernel helper โ€” a random temporary password (never a fixed literal, paste-safe in a shell or a URL, always strong enough for validate_password) plus the initial-password state and the one-time operator log line:

use chrono::Utc;
use kirino::rbac::policy::{PasswordPolicy, bootstrap_credential};

let credential = bootstrap_credential("admin", Utc::now());
// hash credential.password() into the account, persist credential.state() ...
credential.emit_log(); // temporary password, printed once on the bootstrap terminal

let policy = PasswordPolicy::new(true, Some(90));
assert_eq!(
    policy.change_requirement(&credential.state(), Utc::now()).unwrap().as_str(),
    "initial_password",
);

A service persists the pair (is_initial, changed_at) next to the password hash โ€” see PasswordStateStore โ€” and writes PasswordState::rotated(now) when the user changes it. Accounts that predate the tracking are adopted by the service, not guessed by the kernel.

First user: the deployment model is invitation-only, with one deliberate exemption โ€” the first account on an empty install may become an administrator without an invitation, because an empty install cannot otherwise be operated. It is opt-in (AuthService::with_auto_admin_first_user(true), off by default) and applies to the first account only; every later account goes through the invitation path.

Dynamic Authorization

On top of static RBAC, kirino provides a runtime risk-scoring layer inspired by NIST SP 800-207/162 and DO-178C:

flowchart TD
    REQ["ActionRequest<br/>(delegator + category + domain)"]
    REQ --> RISK["Compute 5-dimension risk score"]
    RISK --> D1["Trust (30%)"]
    RISK --> D2["Sensitivity (25%)"]
    RISK --> D3["Domain Scope (25%)"]
    RISK --> D4["Anomaly (10%)"]
    RISK --> D5["Delegator Type (10%)"]
    D1 & D2 & D3 & D4 & D5 --> MAP["Map risk โ†’ Autonomy Level"]
    MAP --> L0["L0: Lockdown (reject all)"]
    MAP --> L1["L1: Human approval required"]
    MAP --> L2["L2: Escalate + audit"]
    MAP --> L3["L3: Proceed with audit"]
    MAP --> L4["L4: Autonomous"]

Trust scores decay exponentially over time. Anomaly detection uses sliding-window z-score analysis. The arbiter supports lockdown/restore and compliance/violation feedback loops.

Identity Types

Identity Description
Anonymous Unauthenticated visitor, minimal permissions
Basic Standard user, starts with minimal permissions
Temporary Time-limited account, auto-expires
Service Service account for permission delegation

Built-in Roles (Default Engine)

Role Permissions
admin All permissions (13 across 6 domains)
operator agent:, config:read, knowledge:, container:read, system:read
viewer agent:read, config:read, knowledge:read, container:read, system:read
agent agent:execute, agent:read

Feature Flags

[features]
default = ["rbac-inmemory", "auth-password", "auth-jwt"]
rbac-core = []                     # Traits and engine only
rbac-inmemory = ["rbac-core"]      # In-memory assignment/role stores
rbac-hierarchy = ["rbac-core"]     # RBAC1 hierarchical role inheritance
rbac-constraints = ["rbac-core"]   # RBAC2 constraint models (SSD/DSD)
rbac-dynamic = ["rbac-core"]       # Dynamic risk-based authorization
rbac-full = [                      # All features enabled
    "rbac-inmemory", "rbac-hierarchy", "rbac-constraints",
    "rbac-dynamic", "auth-password", "auth-jwt"
]
auth-password = ["dep:argon2"]     # Argon2 password hashing
auth-jwt = ["dep:jsonwebtoken"]    # JWT token issuance/verification

Design Philosophy

Kirino is designed to be a pure library consumed by downstream projects:

  • โœ… Provides generic trait-based abstractions for RBAC
  • โœ… Implements ANSI INCITS 359-2004 standard (RBAC0/1/2)
  • โœ… Zero-dependency in-memory reference implementations
  • โœ… Domain-agnostic: define your own Subject and Permission types
  • โœ… Deny-override semantics for security-first access control
  • โœ… Cache-aware permission checks with TTL support

It does not prescribe:

  • โŒ Specific permission or role types (you define your own)
  • โŒ Authentication UI or middleware (library-level only)
  • โŒ Database schema (trait-based โ€” bring your own backend)
  • โŒ Network protocols (expose via your own API layer)

Requirements

  • Rust 1.75+ (edition 2021)
  • Tokio async runtime

License

Licensed under the Synthetic Source License (SySL), Version 1.0.