ストレージバケットの認可ルールをカスタマイズ
ゲスト、認証済みユーザー、ユーザーグループのファイルパスへのアクセスを定義することで、ストレージバケットの認可をカスタマイズします。ストレージバケットへのアクセスが必要な関数に対しても、アクセスを定義できます。
以下の例を参照して、異なるユーザータイプに対して認可をさらにカスタマイズする方法を理解してください。
アクセスタイプ
Amplify Storageを継続して使用するには認証が必要です。まだ設定していない場合は、必ず設定してください - Authの設定に関するドキュメント
アプリケーションのすべてのゲスト(つまり、サインインしていない)ユーザーにmedia/配下のファイルへの読み取りアクセスを許可するには、以下のaccess値を使用します。
export const storage = defineStorage({ name: 'myProjectFiles', access: (allow) => ({ 'media/*': [ allow.guest.to(['read']) // ユースケースに応じて「write」や「delete」などの追加アクションを指定することができます ] })});アプリケーションのすべての認証済み(つまり、サインインしている)ユーザーにmedia/配下のファイルへの読み取りアクセスを許可するには、以下のaccess設定を使用します。
export const storage = defineStorage({ name: 'myProjectFiles', access: (allow) => ({ 'media/*': [ allow.authenticated.to(['read']) // ユースケースに応じて「write」や「delete」などの追加アクションを指定することができます ] })});defineAuthオブジェクトでauth設定時にユーザーグループを設定している場合、ストレージアクセスを特定のグループにスコープできます。この例では、adminグループとauditorグループを持つdefineAuth設定があると想定します。
import { defineAuth } from '@aws-amplify/backend';
export const auth = defineAuth({ loginWith: { email: true }, groups: ['admin', 'auditor']});以下のaccess定義を使用して、監査役はmedia/*への読み取り専用アクセス権を持ち、管理者はフルアクセス権を持つようにアクセス許可を設定できます。
export const storage = defineStorage({ name: 'myProjectFiles', access: (allow) => ({ 'media/*': [ allow.groups(['auditor']).to(['read']), allow.groups(['admin']).to(['read', 'write', 'delete']) ] })});複数のグループが同じアクション群を必要とする場合、これを単一のルールに組み込むことができます。
export const storage = defineStorage({ name: 'myProjectFiles', access: (allow) => ({ 'media/*': [ allow.groups(['auditor', 'admin']).to(['read', 'write']) ] })});場合によっては、ファイルのアップロード者だけが、そのファイルに対してアクションを実行できるようにしたい場合があります。たとえば、音楽共有アプリでは、誰でも曲を聴くことはできますが、その曲をアップロードした本人だけがそれを削除できます。
Amplify Storageでは、entity_idを使用してユーザーを表現し、ファイルを個別ユーザーにスコープすることで、これを実現できます。
entity_idは予約されたトークンで、ファイルがアップロードされるときにユーザーの識別子に置き換えられます。パスへのアクセスを定義するときに、allow.entity(<identification_method>).to([..]) のように識別方法を指定できます。
現在、Identity Poolが唯一の利用可能な識別方法です - allow.entity('identity').to([..])
以下のポリシーは、認証済みユーザーに、彼らのアイデンティティIDに一致するmedia/へのフルアクセスを許可します。
export const storage = defineStorage({ name: 'myProjectFiles', access: (allow) => ({ 'media/{entity_id}/*': [ // {entity_id} はユーザーのアイデンティティIDに置き換えられるトークンです allow.entity('identity').to(['read', 'write', 'delete']) ] })});アイデンティティIDがuser123のユーザーは、media/user123/*内のファイルに対して読み取り/書き込み/削除操作を実行できますが、他のパスにあるファイルに対してはアクションを実行できません。
同様に、アイデンティティIDがuserABCのユーザーは、media/userABC/*内のファイルに対してのみ読み取り/書き込み/削除操作を実行できます。このようにして、各ユーザーに、他のユーザーがアクセスできないストレージパスへのアクセスを許可できます。
以下の例は、誰でもプロフィール写真を表示できますが、所有者だけが修正/削除できるアクセスを定義する方法を示しています。
export const storage = defineStorage({ name: 'myProjectFiles', access: (allow) => ({ 'media/profile-pictures/{entity_id}/*': [ allow.entity('identity').to(['read', 'write', 'delete']), allow.guest.to(['read']), allow.authenticated.to(['read']) ] })});ゲスト、認証済みユーザー、ユーザーグループ、またはリソースのルールが{entity_id}トークンを含むパスに適用される場合、トークンはワイルドカード(*)に置き換えられます。これは、_任意の_ユーザーがアップロードしたファイルにアクセスが適用されることを意味します。上記のポリシーでは、書き込みと削除は所有者のみに制限されていますが、読み取りはmedia/profile-pictures/*/*内の任意のファイルについてゲストユーザーと認証済みユーザーに対して許可されています。
アプリケーションユーザーにストレージファイルへのアクセス権を付与するだけでなく、バックエンド関数にストレージファイルへのアクセス権を付与することもできます。これは、画像のサイズ変更や古いファイルの自動削除などのユースケースを実現するために使用できます。以下の設定は、関数アクセスを定義するために使用されます。
import { defineStorage, defineFunction } from '@aws-amplify/backend';
const demoFunction = defineFunction({});
export const storage = defineStorage({ name: 'myProjectFiles', access: (allow) => ({ 'media/*': [allow.resource(demoFunction).to(['read', 'write', 'delete'])] })});これにより、関数demoFunctionにmedia/*内のファイルを読み取り、書き込み、削除する機能が付与されます。
関数にストレージへのアクセス権が付与されると、ストレージで設定されたAmazon S3バケット名を含む環境変数も受け取ります。この環境変数は、ストレージバケットにAWS SDKコールを実行するために関数で使用できます。環境変数は<storage-name>_BUCKET_NAMEという名前です。上記の例では、myProjectFiles_BUCKET_NAMEという名前になります。
アクセス定義ルール
ストレージアクセス定義で同時に指定できるパスのタイプには、いくつかのルールがあります。
- すべてのパスは
/*で終わる必要があります。 - 1レベルのネスティングのみが許可されます。たとえば、
media/*とmedia/albums/*のアクセス制御を定義できますが、media/albums/photos/*では定義できません。同じパス沿いに他の2つの定義があるためです。 - ワイルドカードは
{entity_id}トークンと競合することはできません。たとえば、media/*とmedia/{entity_id}/*の両方を定義することはできません。最初のパスのワイルドカードが2番目のパスの{entity_id}トークンと競合するためです。 - パスは
{entity_id}トークンを持つ別のパスのプレフィックスにはなれません。たとえば、media/*とmedia/albums/{entity_id}/*は許可されていません。
あるパスが別のパスのサブパスである場合、サブパスのアクセス許可は_常に_親パスのアクセス許可をオーバーライドします。アクセス許可は親パスから「継承」されません。以下のアクセス定義の例を考えてみてください。
export const storage = defineStorage({ name: 'myProjectFiles', access: (allow) => ({ 'media/*': [allow.authenticated.to(['read', 'write', 'delete'])], 'media/profile-pictures/*': [allow.guest.to(['read'])], 'media/albums/*': [allow.authenticated.to(['read'])], 'other/*': [ allow.guest.to(['read']), allow.authenticated.to(['read', 'write']) ] })});このアクセス制御マトリックスはこの構成に対して次のようになります。
| パス | media/* | media/profile-pictures/* | media/albums/* | other/* |
|---|---|---|---|---|
| 認証済みユーザー | read, write, delete | なし | read | read, write |
| ゲストユーザー | なし | read | なし | read |
認証済みユーザーはmedia/*配下のすべてのファイルを読み取り、書き込み、削除できます。ただし、media/profile-pictures/*とmedia/albums/*はこの限りではありません。これらのサブパスについては、スコープダウンされたアクセスが親のmedia/*に付与されたアクセスをオーバーライドします。
利用可能なアクション
特定のパスへのアクセスを構成するときに、アクセスを1つ以上のCRUDLアクションにスコープできます。
| アクセス | 対応するライブラリAPI |
|---|---|
read | getUrl、downloadData、list、およびgetProperties |
get | getUrlおよびdownloadData |
list | listおよびgetProperties |
write | uploadData、copy |
delete | remove |
Gen 1のpublic、protected、およびprivateアクセスパターン用
Amplify Gen 2でdefineStorageを設定して、Gen 1のストレージカテゴリと同じ方法で動作するようにするには、以下の定義を使用できます。
export const storage = defineStorage({ name: 'myProjectFiles', access: (allow) => ({ 'public/*': [ allow.guest.to(['read']), allow.authenticated.to(['read', 'write', 'delete']), ], 'protected/{entity_id}/*': [ allow.authenticated.to(['read']), allow.entity('identity').to(['read', 'write', 'delete']) ], 'private/{entity_id}/*': [ allow.entity('identity').to(['read', 'write', 'delete']) ] })});