Skip to content
エンジニアリング

BYOKアーキテクチャ:JieGouがデータを見ずにLLM呼び出しをルーティングする方法

Bring Your Own Keyシステムの技術的ウォークスルー——AES-256-GCM暗号化、呼び出しごとのプロバイダールーティング、サーキットブレーカー、同時実行制御、fail-open設計哲学。

JT
JieGou Team
· · 2 分で読めます

JieGouのLLMレイヤーを設計した際、ほとんどのプラットフォームにはない制約がありました:顧客が独自のAPIキーを使用でき、保存時に平文のキーを見ることがないようにする必要がありました。この記事では、Bring Your Own Key(BYOK)システムの仕組み、暗号化スキーム、プロバイダールーティングアーキテクチャ、そしてすべてを信頼性高く動作させるガードレールについて説明します。

BYOKが重要な理由

ほとんどのAIプラットフォームは、独自のAPIキーを通じて呼び出しをプロキシします。これにより、データは各社のアカウントを経由し、使用量は各社のレート制限に従い、どのモデルやエンドポイントが使用されるかを制御できません。

BYOKでは、各顧客が独自のAnthropic、OpenAI、またはGoogle APIキーを接続します。呼び出しは顧客の認証情報を使用してプロバイダーに直接送信されます。JieGouはworkflowをオーケストレーションしますが、BYOKキーが使用されている場合、リクエストやレスポンスのペイロードを見ることはありません。

キー暗号化:AES-256-GCM

APIキーは、12バイトの初期化ベクトルと16バイトの認証タグを使用したAES-256-GCMで保存時に暗号化されます。暗号化キーは環境変数として保存された64文字の16進数文字列から導出された256ビット値です——データベースに触れることはありません。

保存形式はIV + authTag + ciphertextのBase64エンコードされた連結です。ユーザーが復号化せずにどのキーが保存されているかを識別できるよう、表示用に8文字の安全なプレフィックス(「sk-proj…」)も一緒に保存します。

キーはFirestoreのaccount_api_keysコレクションに、アカウントID、プロバイダー名、暗号化キーブロブ、有効性フラグのフィールドとともに保存されます。

キー解決フロー

workflowステップがLLMを呼び出す必要がある場合、キーリゾルバーは以下のシーケンスを実行します:

  1. プランゲーティング — アカウントのサブスクリプションがBYOKを許可しているか確認(10分のTTLでRedisにキャッシュ)。
  2. Redisキャッシュ検索 — 復号化されたキーは5分間キャッシュされます。センチネル値(__none__)は、以前検索されたキーが存在しないことを示し、Firestoreの繰り返し読み取りを回避します。
  3. Firestore検索 — キャッシュミスの場合、account_api_keysから取得。
  4. 有効性チェック — 自動無効化システムによって無効とマークされたキーをスキップ。
  5. 復号化 — AES-256-GCM復号化がオンザフライでメモリ内で行われます。
  6. Fail-open — いずれかのステップで問題が発生した場合、プラットフォーム自体のAPIキーにフォールバック。ユーザーエクスペリエンスを決して劣化させません。

fail-open設計は意図的です。Redisがダウンしている場合、復号化が失敗した場合、Firestoreの読み取りがエラーになった場合——workflowは引き続き実行され、プラットフォームキーを使用します。ユーザーは暗号的なエラーを受け取るのではなく、作業が完了するのを見ます。

プロバイダールーティング

LLMレイヤーは、Anthropic、OpenAI、Googleをサポートするプロバイダー抽象化を備えたVercel AI SDK上に構築されています。各プロバイダーには2つのインスタンス化パスがあります:

プラットフォームキー(シングルトン) — 起動時に作成される共有インスタンスで、無料ティアのアカウントまたはBYOKフォールバックとして使用されます。

BYOK(エフェメラル) — 顧客の復号化されたキーを使用して呼び出しごとに作成される新しいプロバイダーインスタンス。このインスタンスはキャッシュされません——1つのリクエストに使用されてから破棄されるため、復号化されたキーがメモリに残留しません。

workflowはステップごとに異なるモデルを指定できます。コンテンツパイプラインではステップ1でニュアンスのあるライティングにClaude、ステップ2で構造化データの抽出にGPTを使用するかもしれません。プロバイダールーティングがこれを透過的に処理します。

自動無効化

LLM呼び出しが認証エラー(HTTP 401、402、または403、またはレスポンスボディが「invalid api key」や「unauthorized」などのパターンに一致)を返した場合、システムはそのキーをFirestoreで自動的に無効としてマークし、Redisキャッシュから削除します。

ユーザーには明確なメッセージが表示されます:「{Provider}のAPIキーが無効であるか、取り消されています。アカウント設定でAPIキーを更新してください。」後続の呼び出しは、ユーザーが新しいキーを提供するまでプラットフォームキーにフォールバックします。

プロバイダー間で11の既知のエラーパターンに対してチェックしています。ローテーションされたキー、取り消されたキー、支出制限を超えたキーをキャッチします。

サーキットブレーカー

各LLMプロバイダーにはプロバイダーごとのサーキットブレーカーがあります(アカウントごとではなく——1つのプロバイダーがダウンすると全員に影響します)。

ブレーカーは60秒のウィンドウ内で5回のエラー後にトリップします。オープンになると、単一のプローブリクエストを許可する前に30秒間オープンのままです(ハーフオープン状態)。プローブが成功するとサーキットがクローズします。

サーバーサイドの障害のみがカウントされます:5xxレスポンス、タイムアウト、接続エラー。無効なAPIキーなどのクライアントエラー(4xx)はブレーカーをトリップしません——これらは代わりに自動無効化で処理されます。

サーキットブレーカー自体もfail-openです。Redisが状態追跡に利用できない場合、すべてのリクエストが通過します。これは全体的な哲学と一致しています:インフラストラクチャが劣化した場合、ユーザーの作業を続行させます。

同時実行制御

各アカウントはRedisベースのセマフォを介して10の同時LLM呼び出しに制限されています。これにより、単一のアカウントの大規模バッチ実行がプロバイダーへの利用可能なすべての接続を消費することを防ぎます。

セマフォは5分のTTLセーフティネット付きのINCR/DECRを使用します(プロセスがデクリメントせずにクラッシュした場合、カウンターは自動的に期限切れになります)。容量超過時にはリークを避けるためにカウンターがすぐにデクリメントされます。他のすべてと同様に、Redisエラー時にはfail-openです。

学んだ教訓

**fail-openはオプション機能の正しいデフォルトです。**BYOKは拡張機能であり、要件ではありません。暗号化パイプライン、キャッシュレイヤー、またはキー解決が失敗した場合、ユーザーはworkflowを引き続き実行できるべきです。調査のために障害をログに記録しますが、実行をブロックすることはありません。

キャッシュセンチネル値がサンダリングハードを防ぎます。__none__センチネルがなければ、BYOKキーのないアカウントはすべてのLLM呼び出しでFirestoreにアクセスすることになります。否定的な結果を5分間キャッシュすることで、Firestoreの読み取りを予測可能に保ちます。

**エフェメラルプロバイダーインスタンスがキー漏洩を防ぎます。**呼び出しごとに新しいプロバイダーインスタンスを作成しガベージコレクションに任せることで、復号化されたキーがメモリに存在するウィンドウを最小化します。ハードウェアセキュリティモジュールほど強力ではありませんが、SaaSアプリケーションにとって攻撃対象面の有意な縮小です。

**プロバイダーごとのサーキットブレーカーとアカウントごとの同時実行が適切な粒度です。**プロバイダーの障害はグローバルイベントです。同時実行はテナントごとの関心事です。混合すると、攻撃的すぎる(1つのアカウントがブレーカーを壊すと全員に影響)か、寛容すぎる(プロバイダー全体の障害に対する保護なし)かのいずれかになります。

security byok architecture privacy encryption
この記事をシェアする

この記事はお役に立ちましたか?

ワークフローのヒント、製品アップデート、自動化ガイドをメールでお届けします。

No spam. Unsubscribe anytime.