こんにちは、広野です。
2024年の re:Invent で、アプリから Amazon S3 バケットのオブジェクトを操作できるようにするための UI モジュールがリリースされました。
今回は実際に既存アプリに組み込んでみたので、その方法を紹介します。
そもそも何が嬉しいのか
- 開発したアプリから、S3 のオブジェクトをマネジメントコンソールの UI 風に操作できる。例えば RAG アプリに必要な独自ドキュメントを S3 に格納している場合、アプリの管理画面に S3 操作用 UI を組み込み、メンテすることができるようになる。このニーズはかなりあったはず!これまでは手作りしていた方が多かったのでは?
- UI だけでなく、アップロード、削除、変更、フォルダ作成などの機能がモジュールに組み込まれている。アクセス権限制御もそこそこいける。すなわち、開発者がそういったベーシックな機能を開発しなくて済む。超絶楽!
- AWS 純正モジュールなので、AWS がサポートしてくれる。安心!
このアップデートは神すぎます。もともと、9月にアルファリリースされていて早期の GA を期待していたのですが、re:Invent に間に合わせてくれて嬉しいです。AWS Amplify がリリースされたのと同じぐらいの衝撃を今受けております。
実際につくってみたもの
UI はデフォルトのままにしました。カスタマイズも若干できそうです。
- Home デフォルトで表示されます。カスタマイズ可能です。
- 指定したバケットおよびフォルダの一覧が表示されます。ここに表示されたフォルダ配下のオブジェクトをメンテナンスできます。
- 権限は Read / Write / Delete が選択できそうです。
- Amazon Cognito でアプリにログインしたユーザにのみ、権限を与えています。
フォルダ名を押すと、その詳細が表示されます。ここでは bot1 を選択します。
今時点、オブジェクトがないので No Files と表示されます。
3点リーダーボタンを押すと、操作可能なメニューがハイライトされます。ここでは Upload をします。
右上の Add files ボタンを押すとファイル選択ウィンドウが表示されますが、ダイレクトに枠内に複数のアップロード対象ファイルをドラッグアンドドロップすることも可能です。最後に右下の Upload ボタンを押します。
アップロードが完了すると、Completed のステータスに変わります。今回は省略しますが、転送の進捗がパーセント表示されます。AWS マネジメントコンソールでも、S3 バケットを確認したらきちんとファイルが入っていました。
削除もしてみます。オブジェクトを選択して、Delete を選択します。
削除対象オブジェクトがリストアップされます。
右下の Delete ボタンを押すと、削除されました。省略しますが、マネジメントコンソールの方でも削除されたことを確認できました。
アーキテクチャ
今回、既存のアプリに追加で組み込んでみました。
AWS のアーキテクチャは以下のブログ記事で紹介したものと全く同じですので、こちらをご覧ください。
簡単に説明しますと。
- Amazon Cognito ユーザープールでアプリの認証をする。
- その際に Amazon Cognito ID プールで、認証済みユーザーに任意の Amazon S3 バケットへのアクセス権限を付与する。
- アプリから Storage Browser でファイルを Amazon S3 と送受信する。
AWS リソースの設定
上記アーキテクチャが実現できている前提で、以下の作業が必要です。
- 対象の Amazon S3 バケットに CORS 設定をする。Storage Browser が REST API で S3 にアクセスするため。
- Amazon Cognito ID プールで Cognito ログイン済みユーザーに割り当てる IAM ロール (認証されたロール) に、対象の Amazon S3 バケットへのアクセス権限を定義する。
Amazon S3 バケットへの CORS 設定
以下の AWS 公式ドキュメントに書いてある通りです。Allowed Origins に、アクセス元アプリの URL を追加するとよりセキュアです。
Amazon Cognito ID プールの認証されたロールの設定
これです。Amazon Cognito ID プールの設定の中に、認証されたロールという設定があります。
ここに、該当の Amazon S3 バケットへの権限を設定します。
AWS が標準として紹介しているのが、Cognito ユーザー単位で権限を制御できるようにしている方法です。
私はそこまでこだわる理由がなかったので、バケット単位で権限を付与しました。
React アプリのコード
React 18.3.1 と Vite を使用している前提です。(Next.js と AWS Amplify は使用していません)
おそらく今時点では React 19 はモジュールの Dependency エラーが出るのでお勧めできません。
モジュールは、公式ドキュメント通り以下をインストールしておきます。
npm install --save @aws-amplify/ui-react-storage aws-amplify
App.jsx
Vite を使用するとソースコードのルートが main.jsx になると思うのですが、私は create-react-app の名残で App.jsx に Amplify.configure を記述していました。AWS ドキュメントには、Amplify.configure はルートに書けとありましたが直すのが面倒なのでそのままにしています。
以下の例のように、Amplify.configure を記述する必要があります。Amplify で環境をデプロイしていないので、設定はマニュアル作成です。※具体的な値は VITE_ から始まる環境変数をビルド時に持ってきます。
import { Authenticator, useAuthenticator } from '@aws-amplify/ui-react';
import { Amplify } from 'aws-amplify';
import Loggedin from './Loggedin.jsx';
import Notloggedin from './Notloggedin.jsx';
//Cognito, S3, AppSync 連携設定
Amplify.configure({
Auth: {
Cognito: {
userPoolId: import.meta.env.VITE_USERPOOLID,
userPoolClientId: import.meta.env.VITE_USERPOOLWEBCLIENTID,
identityPoolId: import.meta.env.VITE_IDPOOLID
}
},
Storage: {
S3: {
bucket: import.meta.env.VITE_S3BUCKETNAMEAMPLIFYSTG,
region: import.meta.env.VITE_REGION,
buckets: {
amplifystorage: {
bucketName: import.meta.env.VITE_S3BUCKETNAMEAMPLIFYSTG,
region: import.meta.env.VITE_REGION
},
kbdatasource: {
bucketName: import.meta.env.VITE_S3BUCKETNAMEKBDATASRC,
region: import.meta.env.VITE_REGION,
paths: {
"bot1/*": {
authenticated: ["write", "get", "list", "delete"]
},
"bot2/*": {
authenticated: ["write", "get", "list", "delete"]
}
}
}
}
}
},
API: {
GraphQL: {
endpoint: import.meta.env.VITE_APPSYNC,
region: import.meta.env.VITE_REGION,
defaultAuthMode: 'userPool'
}
}
});
//ログインチェック
function Authcheck() {
const { authStatus } = useAuthenticator((context) => [context.authStatus]);
return (authStatus === "authenticated") ? <Loggedin /> : <Notloggedin />;
}
export default function App() {
return (
<Authenticator.Provider>
<Authcheck />
</Authenticator.Provider>
);
}
少し解説します。
ベースは、以下の公式ドキュメントの通りなのですが、それだけでは動きませんでした。
対象の S3 バケット内のパス (フォルダ) を、指定する必要があります。仕様として、そのフォルダより上位のオブジェクトにはアクセスできません。また、そのフォルダ内のオブジェクトにどの操作を許可するかの定義をします。
以下の paths: の部分です。※これが、ドキュメントには載っていない
kbdatasource: {
bucketName: import.meta.env.VITE_S3BUCKETNAMEKBDATASRC,
region: import.meta.env.VITE_REGION,
paths: {
"bot1/*": {
authenticated: ["write", "get", "list", "delete"]
},
"bot2/*": {
authenticated: ["write", "get", "list", "delete"]
}
}
}
kbdatasource というのは適当に付けた名前なので、ここは任意の名称で問題なさそうです。他の設定と紐づいてはいません。
設定すれば複数 S3 バケットも操作できると思います。少なくとも paths が設定されているバケット、フォルダでないと操作ができなそうです。
Storage Browser の実装
これは公式ドキュメント通りでした。
デフォルトの UI 設定であれば、以下だけで実装できます。私の場合は Amplify でリソースをデプロイしていないので、Storage Browser を実装したい画面のコードに以下を追加しました。
import "@aws-amplify/ui-react-storage/styles.css"; import { createAmplifyAuthAdapter, createStorageBrowser } from '@aws-amplify/ui-react-storage/browser'; //中略 //Storage Browser const { StorageBrowser } = createStorageBrowser({ config: createAmplifyAuthAdapter() }); //中略 //returnの中で、画面内、表示させたい箇所にこれを差し込む {/* S3 Storage Browser */} <StorageBrowser />
CSSはインポートしておかないと、UI デザインが崩れると思います。
コードはほんの数行なのに、S3 バケット内を操作できる UI が実装できるって、凄すぎませんか!?
まとめ
いかがでしたでしょうか。
既存 Amazon S3 バケットに Storage Browser からアクセスする方法は公式ドキュメントには載っていない情報だったのと、GA 直後で情報が少なかったのもあって、調べるのに苦労しました。ちゃんとは言い忘れましたが、AWS Amplify は一切使わず、Amazon CloudFront、Amazon S3 のホスティング環境に AWS CodePipeline 等でビルド、デプロイしています。そんな環境でも Amplify ブランドの UI モジュールは使えますので、ご安心ください。
本記事が皆様のお役に立てれば幸いです。