アクセス制御

adk-authを使用し、AIエージェント向けのエンタープライズグレードのアクセス制御を提供します。

概要

adk-authは、ADKエージェント向けの監査ログとSSOサポートを備えたrole-based access control (RBAC)を提供します。これにより、どのユーザーがどの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」を除くすべてのToolにアクセスできます

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")); // → Denied

4. 認証と認可の分離

  • 認証 (SSO): ユーザーが誰であるかを検証します (JWT経由)
  • 認可 (RBAC): ユーザーが何にアクセスできるかを決定します
// 認証: JWTを検証し、claimsを抽出します
let claims = provider.validate(token).await?;

// 認可: 特定のPermissionをチェックします
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),     // 名前による特定のTool
    AllTools,         // ワイルドカード: すべてのTool
    Agent(String),    // 名前による特定のAgent  
    AllAgents,        // ワイルドカード: すべてのAgent
}

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

Toolを自動パーミッションチェックでラップします。

use adk_auth::ToolExt;

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

// 実行時、実行前にパーミッションをチェックします
protected.execute(ctx, args).await?;

AuthMiddleware

複数のToolを一括保護します。

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

SSO連携

サポートされているプロバイダー

プロバイダーコンストラクタ発行者
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}/
GenericOidcProvider::from_discovery(issuer, client)Any OIDC provider

TokenClaims

検証済みJWTから抽出されるクレーム:

pub struct TokenClaims {
    pub sub: String,              // サブジェクト(ユーザーID)
    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テナントID
    // ...その他の標準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認証

セキュリティのベストプラクティス

プラクティス説明
デフォルトで拒否明示的に必要な権限のみを付与する
明示的な拒否危険な操作には拒否ルールを追加する
すべてを監査コンプライアンスのためにログ記録を有効にする
サーバーサイドで検証常にサーバー上でJWTを検証する
HTTPSを使用JWKSエンドポイントには安全な接続が必要
キーのローテーションJWKSキャッシュは1時間ごとに自動更新される
トークンの有効期間を制限短命なアクセストークンを使用する

エラーハンドリング

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 */ }
}

前へ: ← 評価 | 次へ: 開発ガイドライン →