UIから簡単にS3操作！Storage Browser for Amazon S3を試してみた

この記事は、[Fusic Advent Calendar 2024](https://qiita.com/advent-calendar/2024/fusic) 14日目の記事です。
昨日は、 @yoshiki-mikami さんの TDD の記事でした。

https://qiita.com/yoshiki-mikami/items/7e1e7083925cfd4e4c9b

# はじめに
私は普段、AWS環境でのインフラ構築を中心に業務を行っています。
今回は、2024年12月1日に正式に一般公開された「Storage Browser for Amazon S3」を試してみたいと思います。
最近、一般のユーザーがS3にファイルをアップロードできる環境を作成しました。
その際、S3に静的ページをホスティングして、lambdaを使用してS3へのアップロードを実行するという形で実装しました。
この「Storage Browser for Amazon S3」を使えば、よりシンプルにそのような機能が実装できたのではないかと思い、試してみることにしました。

# Storage Browser for Amazon S3とは

https://aws.amazon.com/jp/about-aws/whats-new/2024/12/storage-browser-amazon-s3/

公式発表をざっくりまとめると、「S3に保存されているファイルをウェブアプリから簡単に操作できるツール」です。
AWS環境でアプリケーションを構築する際、ファイルストレージとしてS3を使うことは一般的です。しかし、AWSに慣れていないユーザーに「S3にファイルをアップロードしてください」と依頼するのは難しい場面もあるでしょう。また、「渡したいファイルはS3で管理しているので、そこから直接ダウンロードしてください」と指示するのも現実的ではありません。
「Storage Browser for S3」を活用すれば、エンドユーザーがS3にデータをアップロードしたり、保存されたファイルを確認したりする操作を簡単に実現できます。

# 対象読者
- エンドユーザー向けにS3アップロードツールを簡単に作成したい方
- AWS Amplifyを使って、認証機構やS3でのデータ管理機能を組み込みたいと考えている方

# 構築手順
## 1. Amplifyのデプロイとローカルでの開発環境の構築
「Storage Browser for Amazon S3」は、Amplifyで利用できるReactコンポーネントとして提供されています。そのため、まずはAmplifyのアプリケーションをデプロイする必要があります。
Amplifyの公式ドキュメントを参考に、テンプレートからサンプルアプリを作成し、AWSコンソールのAmplifyページから新しいアプリを作成します。

https://docs.amplify.aws/nextjs/start/quickstart/nextjs-app-router-client-components/

テンプレートからリポジトリを作成して、AWSコンソールからAmplifyのサービスページを開き、新しいアプリを作成します。サンプルアプリのデプロイ方法やローカルでの開発環境構築の手順については、 @ayasamind さんのこちらの記事を参考にしました。

https://qiita.com/ayasamind/items/ecbdfb1da2f3e208ea64


## 2. パッケージのインストール
ローカルでの開発環境が整ったら、「Storage Browser for Amazon S3」の実装に必要なパッケージをインストールします。

```
$ npm i --save @aws-amplify/ui-react-storage aws-amplify
```

## 3. ストレージの作成
次に、「Storage Browser for Amazon S3」で利用するS3バケットを作成します。以下のドキュメントを参考に以下の手順を実施していきます。

https://docs.amplify.aws/nextjs/build-a-backend/storage/set-up-storage/

まずは、ストレージを定義するためのファイルを作成します。
```
mkdir amplify/storage
touch amplify/storage/resource.ts
```
次に、作成したファイルにストレージを定義します。
```ts:amplify/storage/resource.ts
import { defineStorage } from '@aws-amplify/backend';

export const storage = defineStorage({
  name: 'amplifyTeamDrive'
});
```

最後に定義したストレージをbackendに追加します。

```ts: amplify/backend.ts

import { defineBackend } from '@aws-amplify/backend';
import { auth } from './auth/resource.js';
import { data } from './data/resource.js';
import { storage } from './storage/resource'; // 追加

defineBackend({
  auth,
  data,
  storage, // 追加
});
```

これでバックエンドの準備が整いました。

## 4. 認証の設定
次に、エンドユーザーがどのS3バケットやフォルダーにアクセスできるかを制御するための認証設定を行います。「Storage Browser for Amazon S3」では、ユースケースに合わせて3つの認証オプションが用意されています。

### 1. AWS Amplify Auth の使用
- 顧客やサードパーティーのパートナーに Amazon S3 のデータへのアクセスを提供したい場合に最適
- ファイルのアクセスコントロールとセキュリティを管理するために、デフォルトで AWS Amplify Auth を使用する Amplify Storage を設定でき、Amazon Cognito を利用したユーザー登録、サインイン、サインアウトフローを実装するための事前構築済みの UI コンポーネントを利用できる

### 2. AWS IAM アイデンティティセンターの使用
- よりスケーラブルなソリューション (会社全体にデータアクセスを提供するなど) を実現する場合に最適
- IAM Identity Center との統合により、既存のユーザーディレクトリを使用して認証することができる

### 3. IAM ロールと Amazon S3 Access Grants の併用
- AWSアカウントやIAMユーザー、IAMロールを直捨管理したい場合に最適
- S3 バケットとプレフィックスの権限を指定されたIAM IDにマッピングする S3 Access Grants インスタンスを作成する必要がある

各オプションの詳細については、下記ドキュメントを参考にいただければと思います。

https://docs.aws.amazon.com/AmazonS3/latest/userguide/setup-storagebrowser.html

ユースケースに合わせて、それぞれのオプションを選択すればいいかなと思います。
今回は、Amplify Authを使って認可を設定していきます。Amplify Authを使うと、さまざまなユーザータイプに対して、認証をカスタマイズすることができます。
ユーザータイプの種類とそれぞれのユーザータイプに許可できるアクションは以下になります。

### ユーザータイプの種類
|ユーザータイプ|対象となるスコープ|
|:-:|:-:|
|guest|すべてのユーザー|
|authenticated| 認証済みのユーザー|
|entity|ファイルの所有者|
|groups|グループ化されたユーザー<br>（一般ユーザーと管理者ユーザーなど）|
|resource|ユーザー以外<br>（自動化処理のための関数など）|

 ### 許可できるアクション
|アクション名|許可するアクション|
|:-:|:-:|
|read|データのダウンロードと一覧の確認|
|get|データのダウンロード|
|list|一覧の確認|
|write|フォルダやファイルの作成、コピー|
|delete|フォルダやファイルの削除|

:::note warn
read はgetとlistの組み合わせであるため、getまたはlistが存在する場合には定義できないのでご注意ください。
:::

ユーザーごとのフォルダの見え方や権限周りも確認するため、以下のように設定してみます。

```ts:amplify/storage/resource.ts
import { defineStorage } from '@aws-amplify/backend';

export const storage = defineStorage({
  name: 'amplifyTeamDrive',
  access: (allow) => ({
    "public/*": [
      allow.guest.to(["read", "write", "delete"]),
      allow.authenticated.to(["read", "write", "delete"]),
    ],
    "public_readonly/*": [
      allow.guest.to(["read"]),
      allow.authenticated.to(["read", "write", "delete"]),
    ],
    "authenticated/*": [
      allow.authenticated.to(["read"]),
    ],
    "private/{entity_id}/*": [
      allow.entity("identity").to(["read", "write", "delete"]),
    ],
  }),
});
```

## 5. フロントエンドの修正
いよいよ、「Storage Browser for Amazon S3」を導入していきます。
「Storage Browser for Amazon S3」の導入には、StorageBrowserコンポーネントを利用します。
アプリケーションのトップページでコンポーネントを宣言します。
```tsx:app/page.tsx
"use client";

import { Amplify } from "aws-amplify";
import { 
  createAmplifyAuthAdapter,
  createStorageBrowser,
} from "@aws-amplify/ui-react-storage/browser";
import "@aws-amplify/ui-react-storage/styles.css";
import outputs from "@/amplify_outputs.json";

Amplify.configure(outputs);

export const { StorageBrowser } = createStorageBrowser({
  config: createAmplifyAuthAdapter(),
});

export default function App() {
  return (
    <div className="p4">
      <h1>Storage Browser</h1>
      <div className="mt-4">
        <StorageBrowser/>
      </div>
    </div>
  );
}

```

このままだと画面デザインが崩れてしまうので、デフォルトでimportされているcssをコメントアウトしておきます。

```ts:app/layout.tsx
import type { Metadata } from "next";
import { Inter } from "next/font/google";
// import "./app.css"; このcssをコメントアウトする
```

開発環境（localhost:3000）で動作を確認します。開発環境にアクセスしてみると、以下のように画面が表示されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1382306/5ceedee2-6c49-9699-03cd-4936af3f28d8.png)

上記の画面から以下のことが確認できます。
- guestユーザーには、read権限が設定されているpublicとpublic_readonlyフォルダが表示されている
- authenticated、privateフォルダにはread 権限が設定されていないため、表示されていない

また、それぞれのフォルダにアクセスしてみると、public_readonlyのフォルダは何もできない（ファイルがあればダウンロードできる）が、publicのフォルダはフォルダの作成や、ファイルのアップロード、ファイルやディレクトリの削除なんかもできるようになっていて、適切に権限管理が行われていることが確認できました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1382306/c6c0f27d-a5d6-ffb3-b9a5-3f48acba6934.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1382306/a68eb237-7bd3-db93-f316-775b10bc06de.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1382306/972da268-5f87-69ca-f42c-8b83426cefda.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1382306/30abc943-852e-96a1-18b0-be1d8df9980f.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1382306/f882b3ef-d63a-78d7-06b7-00024291cfcb.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1382306/c7e006a0-2fef-e87e-c847-1fe8f203eaab.png)
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1382306/3ad04321-a548-acd3-7ab6-b39e1fb0edb9.png)

## 6. 認証画面の実装
次に、認証ユーザーの権限を確認するために認証画面を実装します。
Amplify AuthではAmazon Cognitoを利用しており、認証機構はAuthenticatorコンポーネントで簡単に実装できます。Authenticatorでアプリケーションを囲むだけで、ユーザーのサインイン・サインアウトのフローが簡単に導入できます。

```ts:app/page.tsx
"use client";

import { Amplify } from "aws-amplify";
import { 
  createAmplifyAuthAdapter,
  createStorageBrowser,
} from "@aws-amplify/ui-react-storage/browser";
import {
  Authenticator
} from "@aws-amplify/ui-react";
import "@aws-amplify/ui-react-storage/styles.css";
import outputs from "@/amplify_outputs.json";

Amplify.configure(outputs);

export const { StorageBrowser } = createStorageBrowser({
  config: createAmplifyAuthAdapter(),
});

export default function App() {
  return (
    <Authenticator>
      <div className="p4">
        <h1>Storage Browser</h1>
        <div className="mt-4">
          <StorageBrowser/>
        </div>
      </div>
    </Authenticator>
  );
}
```
開発環境（localhost:3000）に再度アクセスしてみると、以下のように認証の画面が表示されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1382306/1a36ba4c-0ca2-33de-cab4-59da9bb7069f.png)

アカウントを作成し、メールアドレスでの認証を実施するとサインインできます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1382306/ded5f1b4-5922-4fee-a36c-7cf7a04880c4.png)

サインイン後は、閲覧できるフォルダや権限が変わっていることが確認できます。
例えば、認証済みユーザーのみがアクセス可能なフォルダが表示されたり、特定の操作（ファイルのアップロード、削除など）が許可されたりします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1382306/aa4e3601-7857-5794-cbb9-062f95a3f906.png)

他にもページネーションやファイル・フォルダのフィルタリングと検索機能も備わっていて、データの操作や管理が非常に簡単に行えます。
また、ページデザインのカスタマイズも行えるので、興味がある方はやってみてください。

https://sto-bro-docs.ddzh7dd1jott2.amplifyapp.com/react/connected-components/storage/storage-browser

# まとめ
この記事では、「Storage Browser for Amazon S3」を導入し、エンドユーザー向けにS3バケットのデータ操作を簡単に実現できるかどうか試してみました。Storage Browser for Amazon S3を使うことで、Amazon S3上のファイルのアップロード、ダウンロード、閲覧、削除といった基本的な操作を直感的なUIで提供できます。
また、Amplify AuthとAmazon Cognitoを活用することで、認証機構を簡単に導入し、ユーザーごとのアクセス権限を柔軟に設定できることも確認できました。さらに、ページネーションや検索機能、デザインのカスタマイズ性も備わっているため、さらにカスタマイズすれば、エンドユーザー向けに提供できるという感想を持ちました。
また筆者はAmplifyを初めて触ったのですが、初めて触るユーザーでも公式ドキュメントや提供されるテンプレートを活用することで、スムーズに実装を進めることができ、これまでの実装方法に比べ、より簡単かつ効率的にシステムを構築できることもわかりました。
エンドユーザー向けにS3を活用する機会がある方は、ぜひ一度試してみてください。

---

明日の[Fusic Advent Calendar 2024](https://qiita.com/advent-calendar/2024/fusic) は、@shrimpfield さんが書きます。お楽しみに！

# 参考
https://aws.amazon.com/jp/blogs/news/connect-users-to-data-through-your-apps-with-storage-browser-for-amazon-s3/