JamJet

エンタープライズセキュリティ

JamJetのマルチテナント分離、PII編集、OAuth委譲、mTLSフェデレーション、データ保持ポリシー

エンタープライズセキュリティ

JamJetのエンタープライズ機能はRustランタイム層で強制されます — 慣習でもなく、追加を忘れる可能性のあるミドルウェアでもありません。

マルチテナント分離

すべてのストレージをテナントIDで分割します。ワークフロー定義、実行状態、イベントログ、監査証跡、スナップショットはすべてテナントごとにスコープされます。


# 同じワークフロー、異なるテナント — 完全に分離

jamjet run workflow.yaml \
  --input '{"invoice_id": "INV-001", "amount": 2500}' \
  --tenant acme

jamjet run workflow.yaml \
  --input '{"invoice_id": "INV-042", "amount": 75000}' \
  --tenant globex

ランタイムの TenantScopedSqliteBackend は、すべてのストレージクエリを WHERE tenant_id = ? でラップします。ワークフロー定義テーブルは複合主キー (tenant_id, workflow_id, version) を使用します。


PII編集

ワークフローに data_policy を宣言します。ランタイムは状態が監査ログに到達する前にそれを適用します。

data_policy:
  pii_detectors: [email, ssn, phone, credit_card, ip_address]
  pii_fields: ["$.email", "$.ssn", "$.credit_card"]
  redaction_mode: mask        # または: hash, remove
  retain_prompts: false       # 監査ログからプロンプトを削除
  retain_outputs: false       # 監査ログからモデル出力を削除
  retention_days: 90          # 90日後に自動削除

3つの編集モード:

モード動作
maskデバッグ用の部分表示***-**-6789
hash分析用のSHA-256疑似匿名化a3f2c91b...e71b
removeフィールドの完全削除(フィールド削除済み)

Python SDK同等機能:

@workflow(
    id="customer-onboarding",
    version="0.1.0",
    data_policy={
        "pii_detectors": ["email", "ssn", "phone", "credit_card"],
        "pii_fields": ["$.email", "$.ssn"],
        "redaction_mode": "mask",
        "retain_prompts": False,
        "retain_outputs": False,
        "retention_days": 90,
    },
)
class CustomerOnboarding:
    ...

データ保持

retention_days は、すべての監査ログエントリに expires_at タイムスタンプを設定します。ランタイムの purge_expired() メソッドはバックグラウンドタスクとして実行され、有効期限を過ぎたエントリを削除します。

追加コントロール:

  • retain_prompts: false — 書き込み前に監査エントリからモデルプロンプトを削除
  • retain_outputs: false — モデル出力についても同様

監査ログはコンテンツなしでメタデータ(ノードID、トークン数、タイムスタンプ)を保持します。


OAuth 2.0 委任

RFC 8693 トークン交換。ユーザーのトークンを、スコープを絞ったエージェントトークンに交換します。

oauth:
  token_endpoint: "${JAMJET_OAUTH_TOKEN_ENDPOINT}"
  grant_type: "urn:ietf:params:oauth:grant-type:token-exchange"
  client_id: "${JAMJET_OAUTH_CLIENT_ID}"
  client_secret: "${JAMJET_OAUTH_CLIENT_SECRET}"
  requested_scopes: ["expenses:read", "expenses:write"]

スコープの絞り込み

エージェントの有効なスコープは、エージェントが要求するものとユーザーが持つものの交差です。交差が空の場合、ランタイムは OAuthError::ScopeNarrowingFailed を返します。

ステップごとのスコープ設定

異なるノードは異なるスコープ要件を宣言できます:

nodes:
  authenticate:
    oauth_scopes:
      required_scopes: ["expenses:read"]

  submit-expense:
    oauth_scopes:
      required_scopes: ["expenses:read", "expenses:write"]

ランタイムはワークフロー開始時ではなく、各ノード実行前にスコープを解決します。

トークンの有効性

check_token_validity() は、すべてのツールとモデル呼び出しの前に実行されます。期限切れまたは失効したトークンは、明確なエラー(OAuthError::TokenExpiredOAuthError::TokenRevoked)を生成し、人間にエスカレーションします。


mTLS と A2A フェデレーション

組織間エージェント通信の場合:

トランスポート: 相互 TLS。両側が証明書を提示し、両側が検証します。

export JAMJET_TLS_CERT=/etc/certs/agent.pem
export JAMJET_TLS_KEY=/etc/certs/agent-key.pem
export JAMJET_TLS_CA_CERT=/etc/certs/ca.pem
export JAMJET_MTLS_REQUIRED=true

アプリケーション: 機能スコープ付き Bearer トークンとエージェント許可リスト。

federation:
  require_auth: true
  public_agent_card: true
  tokens:
    - token: "tok-alpha"
      name: "Research Agent"
      agent_id: "agent-alpha"
      scopes: ["read", "write"]
  allowed_agents: ["agent-alpha"]
  method_scopes:
    "tasks/send": ["write"]
    "tasks/get": ["read"]

federation_auth_layer ミドルウェアは、すべての受信 A2A リクエストを検証します。未承認のリクエストは、ハンドラに到達する前に JSON-RPC エラーを受け取ります。


プラガブルなシークレットバックエンド

優先順位付けで複数のシークレットソースを連鎖できます:

バックエンドユースケース
環境変数ローカル開発、CI
ファイルベースKubernetes シークレット、マウントボリューム
HashiCorp Vault本番シークレット管理
AWS Secrets ManagerAWS ネイティブデプロイ

ランタイムは起動時に、バックエンドを優先順にチェックしてシークレットを解決します。


実装例

各エンタープライズ機能の実行可能なサンプル:

git clone https://github.com/jamjet-labs/examples
cd examples/multi-tenant       # テナント分離
cd examples/data-governance    # PII編集 + 保持ポリシー
cd examples/oauth-delegation   # OAuth 2.0 + スコープ制限

ヒント: 詳細な解説記事:データガバナンスとPII編集OAuth委譲とフェデレーション認証

On this page