التحكم بالوصول

التحكم بالوصول على مستوى المؤسسات لوكلاء الذكاء الاصطناعي باستخدام adk-auth.

نظرة عامة

adk-auth يوفر التحكم بالوصول المستند إلى الأدوار (RBAC) مع تسجيل التدقيق ودعم SSO لوكلاء ADK. إنه يتيح تحكمًا آمنًا ودقيقًا في المستخدمين الذين يمكنهم الوصول إلى أي Tools.

البنية

┌─────────────────────────────────────────────────────────────────┐
│                        Agent Request                             │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                     SSO Token Validation                         │
│  ┌─────────────┐  ┌─────────────┐  ┌─────────────────────────┐  │
│  │ Google      │  │ Azure AD    │  │ OIDC Discovery          │  │
│  │ Provider    │  │ Provider    │  │ (Okta, Auth0, etc)     │  │
│  └─────────────┘  └─────────────┘  └─────────────────────────┘  │
│                          │                                       │
│                   ┌──────┴──────┐                                │
│                   │ JWKS Cache  │  ← Auto-refresh keys          │
│                   └─────────────┘                                │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼ TokenClaims
┌─────────────────────────────────────────────────────────────────┐
│                       Claims Mapper                              │
│                                                                  │
│    IdP Groups          →        adk-auth Roles                  │
│    ─────────────────────────────────────────                    │
│    "AdminGroup"        →        "admin"                         │
│    "DataAnalysts"      →        "analyst"                       │
│    (default)           →        "viewer"                         │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼ Roles
┌─────────────────────────────────────────────────────────────────┐
│                      Access Control                              │
│                                                                  │
│    Role: admin                                                   │
│    ├── allow: AllTools                                          │
│    └── allow: AllAgents                                         │
│                                                                  │
│    Role: analyst                                                 │
│    ├── allow: Tool("search")                                    │
│    ├── allow: Tool("summarize")                                 │
│    └── deny:  Tool("code_exec")  ← Deny takes precedence        │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼ Check Result
┌─────────────────────────────────────────────────────────────────┐
│                      Audit Logging                               │
│                                                                  │
│    {"user":"alice","resource":"search","outcome":"allowed"}     │
│    {"user":"bob","resource":"exec","outcome":"denied"}          │
└─────────────────────────────────────────────────────────────────┘
                                │
                                ▼
┌─────────────────────────────────────────────────────────────────┐
│                     Tool Execution                               │
│               (only if access granted)                          │
└─────────────────────────────────────────────────────────────────┘

مبادئ التصميم

1. أولوية الرفض

عندما يحتوي الدور على كل من قواعد السماح والرفض، دائمًا ما يفوز الرفض:

let role = Role::new("limited")
    .allow(Permission::AllTools)      // Allow everything...
    .deny(Permission::Tool("admin")); // ...except admin

// النتيجة: يمكن الوصول إلى أي أداة باستثناء "admin"

2. اتحاد الأدوار المتعددة

يحصل المستخدمون ذوو الأدوار المتعددة على اتحاد الأذونات، ولكن قواعد الرفض من أي دور تظل سارية:

let ac = AccessControl::builder()
    .role(reader)    // allow: search
    .role(writer)    // allow: write
    .assign("alice", "reader")
    .assign("alice", "writer")
    .build()?;

// يمكن لأليس الوصول إلى كل من "search" و "write"

3. الصريح فوق الضمني

الأذونات صريحة - لا يتم منح أي وصول افتراضيًا:

let role = Role::new("empty");
// هذا الدور لا يمنح أي أذونات

ac.check("user", &Permission::Tool("anything")); // ← مرفوض

4. فصل المصادقة والترخيص

  • المصادقة (SSO): تتحقق من هوية المستخدم (عبر JWT)
  • الترخيص (RBAC): يحدد ما يمكنهم الوصول إليه
// المصادقة: التحقق من JWT، استخراج المطالبات
let claims = provider.validate(token).await?;

// الترخيص: التحقق من إذن محدد
ac.check(&claims.sub, &Permission::Tool("search"))?;

// مدمج: SsoAccessControl يقوم بكليهما
sso.check_token(token, &permission).await?;

التثبيت

[dependencies]
adk-auth = "0.2.0"

# لدعم SSO/OAuth
adk-auth = { version = "0.2.0", features = ["sso"] }

المكونات الأساسية

Permission

pub enum Permission {
    Tool(String),     // أداة محددة بالاسم
    AllTools,         // رمز شامل: جميع الأدوات
    Agent(String),    // وكيل محدد بالاسم  
    AllAgents,        // رمز شامل: جميع الوكلاء
}

Role

let analyst = Role::new("analyst")
    .allow(Permission::Tool("search".into()))
    .allow(Permission::Tool("summarize".into()))
    .deny(Permission::Tool("code_exec".into()));

AccessControl

let ac = AccessControl::builder()
    .role(admin)
    .role(analyst)
    .assign("alice@company.com", "admin")
    .assign("bob@company.com", "analyst")
    .build()?;

// التحقق من الإذن
ac.check("bob@company.com", &Permission::Tool("search".into()))?;

ProtectedTool

يغلف أداة بفحص تلقائي للأذونات:

use adk_auth::ToolExt;

let protected = my_tool.with_access_control(Arc::new(ac));

// عند التنفيذ، يتحقق من الإذن قبل التشغيل
protected.execute(ctx, args).await?;

AuthMiddleware

يحمي مجموعة من الأدوات دفعة واحدة:

let middleware = AuthMiddleware::new(ac);
let protected_tools = middleware.protect_all(tools);

تكامل SSO

الموفرون المدعومون

الموفرConstructorالمصدر
GoogleGoogleProvider::new(client_id)accounts.google.com
Azure ADAzureADProvider::new(tenant, client)login.microsoftonline.com
OktaOktaProvider::new(domain, client){domain}/oauth2/default
Auth0Auth0Provider::new(domain, audience){domain}/
عامOidcProvider::from_discovery(issuer, client)أي موفر OIDC

TokenClaims

المطالبات المستخرجة من JWTs التي تم التحقق منها:

pub struct TokenClaims {
    pub sub: String,              // الموضوع (معرف المستخدم)
    pub email: Option<String>,    // البريد الإلكتروني
    pub name: Option<String>,     // الاسم المعروض
    pub groups: Vec<String>,      // مجموعات IdP
    pub roles: Vec<String>,       // أدوار IdP
    pub hd: Option<String>,       // نطاق Google المستضاف
    pub tid: Option<String>,      // معرف مستأجر Azure
    // ... المزيد من مطالبات OIDC القياسية
}

ClaimsMapper

يربط مجموعات IdP بأدوار adk-auth:

let mapper = ClaimsMapper::builder()
    .map_group("AdminGroup", "admin")
    .map_group("Users", "viewer")
    .default_role("guest")
    .user_id_from_email()
    .build();

SsoAccessControl

يجمع بين التحقق من SSO والتحكم في الوصول المستند إلى الدور (RBAC) في استدعاء واحد:

let sso = SsoAccessControl::builder()
    .validator(GoogleProvider::new("client-id"))
    .mapper(mapper)
    .access_control(ac)
    .audit_sink(audit)
    .build()?;

// التحقق من التوكن + التحقق من الإذن + سجل التدقيق
let claims = sso.check_token(token, &Permission::Tool("search".into())).await?;

تسجيل التدقيق

FileAuditSink

let audit = FileAuditSink::new("/var/log/adk/audit.jsonl")?;
let middleware = AuthMiddleware::with_audit(ac, audit);

تنسيق الإخراج (JSONL)

{"timestamp":"2025-01-01T10:30:00Z","user":"bob","session_id":"sess-123","event_type":"tool_access","resource":"search","outcome":"allowed"}
{"timestamp":"2025-01-01T10:30:01Z","user":"bob","session_id":"sess-123","event_type":"tool_access","resource":"code_exec","outcome":"denied"}

مخرجات تدقيق مخصصة

use adk_auth::{AuditSink, AuditEvent, AuthError};
use async_trait::async_trait;

pub struct DatabaseAuditSink { /* ... */ }

#[async_trait]
impl AuditSink for DatabaseAuditSink {
    async fn log(&self, event: AuditEvent) -> Result<(), AuthError> {
        // الإدراج في قاعدة البيانات
        sqlx::query("INSERT INTO audit_log ...")
            .bind(event.user)
            .bind(event.resource)
            .execute(&self.pool)
            .await?;
        Ok(())
    }
}

أمثلة

# التحكم الأساسي بالوصول المستند إلى الدور (RBAC)
cargo run --example auth_basic          # التحكم بالوصول المستند إلى الدور
cargo run --example auth_audit          # تسجيل التدقيق

# SSO (يتطلب --features sso)
cargo run --example auth_sso --features sso     # تدفق SSO كامل
cargo run --example auth_jwt --features sso     # التحقق من JWT
cargo run --example auth_oidc --features sso    # اكتشاف OIDC
cargo run --example auth_google --features sso  # هوية Google

أفضل ممارسات الأمان

الممارسةالوصف
الرفض افتراضيًامنح الأذونات المطلوبة صراحةً فقط
الرفض الصريحإضافة قواعد الرفض للعمليات الخطيرة
تدقيق كل شيءتمكين التسجيل للامتثال
التحقق من صحة الخادمالتحقق دائمًا من JWTs على الخادم
استخدام HTTPSتتطلب نقاط نهاية JWKS اتصالات آمنة
تدوير المفاتيحيتم تحديث ذاكرة التخزين المؤقت لـ JWKS تلقائيًا كل ساعة
تحديد عمر التوكناستخدام توكنات وصول قصيرة الأجل

معالجة الأخطاء

use adk_auth::{AccessDenied, AuthError};
use adk_auth::sso::TokenError;

// RBAC errors
match ac.check("user", &Permission::Tool("admin".into())) {
    Ok(()) => { /* access granted */ }
    Err(AccessDenied { user, permission }) => {
        eprintln!("Denied: {} cannot access {}", user, permission);
    }
}

// SSO errors
match provider.validate(token).await {
    Ok(claims) => { /* token valid */ }
    Err(TokenError::Expired) => { /* token expired */ }
    Err(TokenError::InvalidSignature) => { /* signature invalid */ }
    Err(TokenError::InvalidIssuer { expected, actual }) => { /* wrong issuer */ }
    Err(e) => { /* other error */ }
}

السابق: ← التقييم | التالي: إرشادات التطوير →