一般公開するアプリケーションを構築する場合は、システムに保存されているデータを保護することが非常に重要です。LLM の場合、モデルが必要なデータにのみアクセスし、ツール呼び出しが LLM を呼び出すユーザーに適切にスコープ設定され、フローが無効なクライアント アプリケーションによってのみ呼び出されるように、特別な注意が必要です。
Firebase Genkit には、承認ポリシーとコンテキストを管理するためのメカニズムが用意されています。Firebase で実行されるフローでは、認証ポリシーのコールバック(またはヘルパー)を使用できます。また、Firebase は、独自のチェックを行うことができるフローへの認証コンテキストも提供します。Functions 以外のフローの場合、認証はミドルウェアを介して管理および設定できます。
フロー内で承認する
フローでは、2 つの方法で認可を確認できます。リクエスト バインディング(Cloud Functions for Firebase の onCallGenkit
や express
など)で認可を適用するか、これらのフレームワークで認証ポリシーをフロー自体に渡します。この場合、フロー内で管理されている認証情報にフローからアクセスできます。
import { genkit, z, UserFacingError } from 'genkit';
const ai = genkit({ ... });
export const selfSummaryFlow = ai.defineFlow( {
name: 'selfSummaryFlow',
inputSchema: z.object({ uid: z.string() }),
outputSchema: z.string(),
}, async (input, { context }) => {
if (!context.auth) {
throw new UserFacingErrorError('UNAUTHENTICATED', 'Unauthenticated');
}
if (input.uid !== context.auth.uid) {
throw new UserFacingError('PERMISSION_DENIED', 'You may only summarize your own profile data.');
}
// Flow logic here...
});
この場合、context.auth
に値を設定するのはリクエスト バインディング次第です。たとえば、onCallGenkit
には context.auth
(Firebase Authentication)、context.app
(Firebase App Check)、context.instanceIdToken
(Firebase Cloud Messaging)が自動的に入力されます。フローを手動で呼び出す場合は、独自の認証コンテキストを手動で追加できます。
// Error: Authorization required.
await selfSummaryFlow({ uid: 'abc-def' });
// Error: You may only summarize your own profile data.
await selfSummaryFlow.run(
{ uid: 'abc-def' },
{
context: { auth: { uid: 'hij-klm' } },
}
);
// Success
await selfSummaryFlow(
{ uid: 'abc-def' },
{
context: { auth: { uid: 'abc-def' } },
}
);
Genkit 開発 UI で実行する場合は、[Auth JSON] タブに JSON を入力して Auth オブジェクトを渡すことができます。{"uid": "abc-def"}
ai.currentContext()
を呼び出すことで、フロー内の任意の時点でフロー認証コンテキストを取得することもできます。これは、フローによって呼び出される関数でも行えます。
import { genkit, z } from 'genkit';
const ai = genkit({ ... });;
async function readDatabase(uid: string) {
const auth = ai.currentContext()?.auth;
// Note: the shape of context.auth depends on the provider. onCallGenkit puts
// claims information in auth.token
if (auth?.token?.admin) {
// Do something special if the user is an admin
} else {
// Otherwise, use the `uid` variable to retrieve the relevant document
}
}
export const selfSummaryFlow = ai.defineFlow(
{
name: 'selfSummaryFlow',
inputSchema: z.object({ uid: z.string() }),
outputSchema: z.string(),
authPolicy: ...
},
async (input) => {
await readDatabase(input.uid);
}
);
Genkit デベロッパー ツールでフローテストを行う場合は、UI でこの認証オブジェクトを指定するか、--context
フラグを使用してコマンドラインで指定できます。
genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"email_verified": true}}'
Cloud Functions for Firebase の使用を承認する
Cloud Functions for Firebase SDK は、Firebase Auth / Google Cloud Identity Platform との統合や、Firebase App Check の組み込みサポートなど、Genkit をサポートしています。
ユーザー認証
Firebase Functions ライブラリが提供する onCallGenkit()
ラッパーには、Cloud Functions for Firebase のクライアント SDK のサポートが組み込まれています。これらの SDK を使用する場合、アプリ クライアントが Firebase Auth SDK も使用している限り、Firebase Auth ヘッダーが自動的に含まれます。Firebase Auth を使用して、onCallGenkit()
で定義されたフローを保護できます。
import { genkit } from 'genkit';
import { onCallGenkit } from 'firebase-functions/https';
const ai = genkit({ ... });;
const selfSummaryFlow = ai.defineFlow({
name: 'selfSummaryFlow',
inputSchema: z.string(),
outputSchema: z.string(),
}, async (input) => {
// Flow logic here...
});
export const selfSummary = onCallGenkit({
authPolicy: (auth) => auth?.token?.['email_verified'] && auth?.token?.['admin'],
}, selfSummaryFlow);
onCallGenkit
を使用すると、context.auth
は、ユーザー ID の uid
と DecodedIdToken である token
を含むオブジェクトとして返されます。このオブジェクトは、前述のように ai.currentContext()
を使用していつでも取得できます。開発中にこのフローを実行する場合は、ユーザー オブジェクトを同じように渡します。
genkit flow:run selfSummaryFlow '{"uid": "abc-def"}' --context '{"auth": {"admin": true}}'
Cloud Functions をインターネットに公開する場合は、なんらかの認可メカニズムを使用して、自分のデータとユーザーのデータを保護することが不可欠です。ただし、コードベースの認可チェックなしで Cloud Functions をデプロイする必要がある場合があります(たとえば、関数は世界中で呼び出すことができず、代わりに Cloud IAM で保護されている場合など)。Cloud Functions for Firebase では、IAM アクセスを制御する invoker
プロパティを使用してこれを行うことができます。特別な値 'private'
を使用すると、関数はデフォルトの IAM 設定のままになります。つまり、Cloud Run 起動元のロールを持つ呼び出し元のみが関数を実行できます。代わりに、この関数を呼び出す権限を付与するユーザーまたはサービス アカウントのメールアドレスを指定できます。
import { onCallGenkit } from 'firebase-functions/https'
const selfSummaryFlow = ai.defineFlow({
name: 'selfSummaryFlow',
inputSchema: z.string(),
outputSchema: z.string(),
}, async (input) => {
// Flow logic here...
});
export const selfSummary = onCallGenkit({
invoker: 'private',
}, selfSummaryFlow);
クライアントの整合性
認証だけでもアプリを保護できますが、クライアント アプリのみが関数を呼び出すようにすることも重要です。genkit 用の Firebase プラグインには、Firebase App Check のファーストクラス サポートが含まれています。これを行うには、次の構成オプションを onCallGenkit()
に追加します。
import { onCallGenkit } from 'firebase-functions/https';
const selfSummaryFlow = ai.defineFlow({
name: 'selfSummaryFlow',
inputSchema: z.string(),
outputSchema: z.string(),
}, async (input) => {
// Flow logic here...
});
export const selfSummary = onCallGenkit({
// These two fields for app check. The consumeAppCheckToken option is for
// replay protection, and requires additional client configuration. See the
// App Check docs.
enforceAppCheck: true,
consumeAppCheckToken: true,
authPolicy: ...,
}, selfSummaryFlow);
Firebase 以外の HTTP 認可
Cloud Functions for Firebase の外部のサーバー コンテキストにフローをデプロイする場合は、組み込みのフローとともに独自の認可チェックを設定できる方法が必要です。
ContextProvider
を使用して、auth
などのコンテキスト値を入力し、宣言型ポリシーまたはポリシー コールバックを提供します。Genkit SDK は apiKey
などの ContextProvider
を提供します。プラグインでも公開される場合があります。たとえば、@genkit-ai/firebase/context
プラグインは、Firebase Auth 認証情報を検証してコンテキストに入力するためのコンテキスト プロバイダを公開します。
次のようなコードは、さまざまなアプリケーションで使用できます。
// Express app with a simple API key
import { genkit, z } from 'genkit';
const ai = genkit({ ... });;
export const selfSummaryFlow = ai.defineFlow(
{
name: 'selfSummaryFlow',
inputSchema: z.object({ uid: z.string() }),
outputSchema: z.string(),
},
async (input) => {
// Flow logic here...
}
);
シンプルな「フロー サーバー」Express アプリを保護するには、次のように記述します。
import { apiKey } from "genkit";
import { startFlowServer, withContext } from "@genkit-ai/express";
startFlowServer({
flows: [
withContext(selfSummaryFlow, apiKey(process.env.REQUIRED_API_KEY))
],
});
または、同じツールを使用してカスタム Express アプリケーションを構築することもできます。
import { apiKey } from "genkit";
import * as express from "express";
import { expressHandler } from "@genkit-ai/express;
const app = express();
// Capture but don't validate the API key (or its absence)
app.post('/summary', expressHandler(selfSummaryFlow, { contextProvider: apiKey()}))
app.listen(process.env.PORT, () => {
console.log(`Listening on port ${process.env.PORT}`);
})
ContextProvider
はウェブ フレームワークを抽象化するため、これらのツールは Next.js などの他のフレームワークでも機能します。以下に、Next.js で構築された Firebase アプリの例を示します。
import { appRoute } from "@genkit-ai/express";
import { firebaseContext } from "@genkit-ai/firebase";
export const POST = appRoute(selfSummaryFlow, { contextProvider: firebaseContext })
Express の使用方法については、Cloud Run の手順をご覧ください。