■概要
GenU(Generative AI Use Cases)はAWSが公開している生成AI活用アプリです。
オリジナルのGenUには管理者専用の機能はありませんが、場合によっては欲しくなることもあるかもしれません。
この記事では、Cognito UserPoolに管理者用のグループを追加して、管理者グループに所属しているユーザーのみが利用可能な機能(画面とバックエンドAPI)をGenUに追加してみます。
GenUは"MIT-0"ライセンスで公開してくれているので独自のカスタマイズを加えて公開できます。
当記事ではオリジナルのGenUのソースコード(v5.4.0時点)をベースに、下記の独自カスタマイズを加えています。
- フロントエンドのカスタマイズ
- Cognitoグループによる表示分けの実装
- 管理者専用の画面を追加
- 管理者専用APIの呼び出しを追加
- バックエンドのカスタマイズ
- 管理者専用APIの実装(Lambda関数)を追加
- API Gatewayに管理者専用APIのパス追加
カスタマイズ版ソースコードは私のGitHubリポジトリで公開しています。
※ AWSのオリジナルGenUのリポジトリからForkしたものをベースに独自変更を加えたフィーチャーブランチです。
■ 事前準備(グループの作成)
ここでは管理者グループ名は"admin"としています。
AWS管理コンソールからGenUのリソースのCognito UserPoolの設定を開き、"admin"グループを作成して確認対象のユーザーをメンバーに追加します。
■フロントエンドのカスタマイズ
前提としてGenUはReact+Typescript+Viteでフロントエンドアプリが実装されていますので、Reactのコードにカスタマイズを加えることになります。
ソースコードは"packages/web"配下にあります。
Cognitoグループによる表示分けの実装
ログインユーザーが管理者グループに所属する場合のみ、メニュー下部に管理者専用画面への導線となるアイコンを表示させます。
メニュー表示用のコンポーネント「DrawerBase」に手を入れます。
--- a/packages/web/src/components/DrawerBase.tsx
+++ b/packages/web/src/components/DrawerBase.tsx
@@ -4,7 +4,7 @@ import { Link } from 'react-router-dom';
import useSWR from 'swr';
import useVersion from '../hooks/useVersion';
import IconWithDot from './IconWithDot';
-import { PiChartBar, PiGear } from 'react-icons/pi';
+import { PiChartBar, PiGear, PiSquaresFour } from 'react-icons/pi';
import { fetchAuthSession } from 'aws-amplify/auth';
import useUserSetting from '../hooks/useUserSetting';
import { useTranslation } from 'react-i18next';
@@ -27,6 +27,9 @@ const DrawerBase: React.FC<Props> = (props) => {
const email = useMemo<string>(() => {
return (data?.tokens?.idToken?.payload.email ?? '') as string;
}, [data]);
+ const groups = useMemo<string[]>(() => {
+ return (data?.tokens?.idToken?.payload['cognito:groups'] ?? []) as string[];
+ }, [data]);
const hasUpdate = getHasUpdate();
@@ -45,6 +48,11 @@ const DrawerBase: React.FC<Props> = (props) => {
<div className="truncate text-xs">{email}</div>
)}
<div className="grow" />
+ {groups.includes('admin') && (
+ <Link to="/admin-only" title="AdminOnly">
+ <PiSquaresFour className="text-lg" />
+ </Link>
+ )}
<Link to="/stats" title={t('stat.title')}>
<PiChartBar className="text-lg" />
</Link>
ポイントはユーザー認証後に参照できるIDトークン(OIDC)に含まれる"cognito:groups"クレームを使って"/admin-only"のパスの画面への導線となるアイコンの表示有無を制御していることです。
"admin"グループのユーザーでのログインのみ、画面メニュー表示下部に下のようにアイコンが追加表示されるようにします。

管理者専用の画面を追加
前述のアイコンクリックから遷移する先の画面(Pageコンポーネント)を追加します。
ここでは意味のある機能は実装せず、単に管理者用バックエンドAPIを呼び出すテスト用ボタンのみ実装しています。
AdminPageコンポーネントのソース(AdmimPage.tsx)
AdminPageとパス"/admin-only"の紐づけ追加(main.tsx)
管理者専用APIの呼び出しを追加
前述の画面の「Test Invoke」ボタンクリックから管理者専用バックエンドAPIを呼び出すための処理を実装します。
Reactのカスタムフック「useAdminOnlyApi」を追加して、AdminPageからHTTPリクエストを行っています。
ここではパス"admin-only/test-invoke"のAPIを呼び出していますが、呼び出し先のAPIは後述の「バックエンドのカスタマイズ」の方で追加実装しています。
■バックエンドのカスタマイズ
前提としてGenUはCDKでAWSリソース構成を管理しています。
ソースコードは"packages/cdk"配下にあります。
バックエンドAPIは基本的には(※)API GatewayとLambda関数(Nodejsランタイム)で構成されています。
API処理を実装するLambda関数を追加し、既存のAPI Gatewayリソースに"admin-only/test-invoke"パスのGETリクエストを追加したLambda関数に統合する設定を追加します。
※ (余談です)「基本的には」と上で書きましたが、例外としてチャット系機能でレスポンスのストリーミングが必要なバックエンドAPIのみ、(API Gatewayを使わずに)Lambda関数を直接呼び出す構成となっています。
これは当初はAPI Gatewayがレスポンスのストリーミングをサポートしていなかったためですが、2025年末に対応されているようで、GenUも将来的にはAPI Gatewayを使う方式に統一されるかもしれないですね(参考:Amazon API Gateway レスポンスストリーミングによる応答性の高い API の構築)。
管理者専用APIの実装(Lambda関数)を追加
APIのインターフェース定義を追加します。
リクエストに含まれる認証情報から、IDトークンの"cognito:groups"クレーム値を参照するための定義をしていることがポイントです。
※フロントエンドとバックエンドで共有する型定義は"packages/types"フォルダ下のソースで管理するルールのようです。
管理者専用APIのLambda関数を実装します。
event(TestInvokeByAdminEvent型)からグループの値を取得して"admin"が含まれていない場合に403(Forbidden)を返すようになっていることがポイントで、これにより管理者グループのユーザー以外からのリクエストはブロックされます。
フロントエンド側では表示の出し分けをしているだけなので、バックエンド側でもしっかりチェックを行うことが必要です。
API Gatewayに管理者専用APIのパス追加
CDKとしてのREST API関連のAWSリソース定義は"packages/cdk/lib/construct/api.ts"ファイルに実装されています。
前述のLambda関数のリソースを"api.ts"に追加します。
さらに、追加したLambda関数をAPI Gatewayリソースの"admin-only/test-invoke"パスのGETメソッドと紐づける設定を追加します。
--- a/packages/cdk/lib/construct/api.ts
+++ b/packages/cdk/lib/construct/api.ts
@@ -833,6 +833,15 @@ export class Api extends Construct {
table.grantReadData(getTokenUsageFunction);
props.statsTable.grantReadData(getTokenUsageFunction);
+ // Lambda function for admin-only actions
+ const adminOnlyFunction = new NodejsFunction(this, 'AdminOnlyFunction', {
+ runtime: LAMBDA_RUNTIME_NODEJS,
+ entry: './lambda/adminOnly.ts',
+ timeout: Duration.minutes(1),
+ vpc,
+ securityGroups,
+ });
+
// API Gateway
const authorizer = new CognitoUserPoolsAuthorizer(this, 'Authorizer', {
cognitoUserPools: [userPool],
@@ -1141,6 +1150,15 @@ export class Api extends Construct {
commonAuthorizerProps
);
+ // GET: /admin-only/test-invoke
+ const adminResource = api.root.addResource('admin-only');
+ const adminOnlyTestInvokeResorce = adminResource.addResource('test-invoke');
+ adminOnlyTestInvokeResorce.addMethod(
+ 'GET',
+ new LambdaIntegration(adminOnlyFunction),
+ commonAuthorizerProps
+ );
+
this.api = api;
this.predictStreamFunction = predictStreamFunction;
this.invokeFlowFunction = invokeFlowFunction;
■ デプロイ後の実行例
これらのカスタマイズを加えてGenUをデプロイすることで、管理者のみの画面表示や、管理者のみが呼び出せるAPIの追加ができました。
「Test Invoke」ボタンクリックでAPI呼び出しに成功するとログインユーザーのメールアドレスや所属グループ情報がバックエンドAPIから返されて画面表示されます。
※ メールアドレス部はいちおうマスクしています。

最後に
当記事は、前記事GenUのAI回答に対するフィードバックの運用について考えてみる(その1)から、次の記事(その2)に繋がる中間成果物としての意味合いを含めて作成しました。
「GenUのAI回答に対するフィードバックの運用について考えてみる(その2)」(※)では、AI回答に対するユーザーフィードバックの情報を管理者専用の画面から確認できるようにしてみようと思います。
※ "(その2)"はそのうち執筆予定。投稿したらこちらも更新します。

