Cognitoユーザー認証によるS3 のAccess制御をAmplifyとReactとDropzoneを使って実装する。(その2)

Cognitoで認証されたユーザーの権限を設定します。

AWS Serviceを利用する事に対する権限の設定にはIAM UserとIAM Roleの2種類があります。IAM Userは、UserがManagement ConsoleにLoginしてAWS Serviceを利用するための権限設定と言えます。Management Consoleを操作できない仮想のUserを設定することも可能です。個人的な理解はIAM UserはAWS Serviceを外側から利用することを想定した権限設定です。IAM Roleは、AWS Serviceが他のAWS Serviceを利用するための権限設定と言えます。こちらは、AWS Serviceを内側から利用することを想定した権限設定と理解しています。
IAM UserもIAM Roleも個々の権限を直に記述して設定することができます。また、IAM Policyに権限の設定を記述し、複数のIAM PolicyをIAM UserやIAM RoleにAttachして権限を構成することもできます。

Cognitoユーザー認証で認証されたユーザーは、Cognitoで設定されたIAM Roleの権限でAWS Serviceを利用することになります。今回は、Congintoの設定時に生成されたIAM RoleにS3 Accessに必要な権限をIAM Policyに設定し、IAM RoleにAttachします。

Management ConsoleからIAMを開き、「ポリシー」をクリックします。「ポリシーのフィルタ」に「S3」を入力すると、S3の名前を含んだIAM Policyが表示されます。AmazonS3FullAccessの▶をクリックして、ポリシーの書き方を確認します。

「ポリシーの作成」をクリックして、 「JOSN」タブを開き、 ポリシーを設定します。 (その1)で作成したBucketだけにAccess出来るように、(その1)で確認したARNは「arn:aws:s3:::upload.hacya.com」なので、次のJSONのTemplateの{enter bucket name}に「upload.hacya.com」を入れます。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:GetObject",
                "s3:PutObject",
                "s3:DeleteObject"
            ],
            "Resource": [
                "arn:aws:s3:::{enter bucket name}/public/*",
                "arn:aws:s3:::{enter bucket name}/protected/${cognito-identity.amazonaws.com:sub}/*",
                "arn:aws:s3:::{enter bucket name}/private/${cognito-identity.amazonaws.com:sub}/*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:PutObject"
            ],
            "Resource": [
                "arn:aws:s3:::{enter bucket name}/uploads/*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:GetObject"
            ],
            "Resource": [
                "arn:aws:s3:::{enter bucket name}/protected/*"
            ],
            "Effect": "Allow"
        },
        {
            "Condition": {
                "StringLike": {
                    "s3:prefix": [
                        "public/",
                        "public/*",
                        "protected/",
                        "protected/*",
                        "private/${cognito-identity.amazonaws.com:sub}/",
                        "private/${cognito-identity.amazonaws.com:sub}/*"
                    ]
                }
            },
            "Action": [
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::{enter bucket name}"
            ],
            "Effect": "Allow"
        }
    ]
}

「ポリシーの確認」をクリックし、ポリシーの確認をします。
ポリシーの確認では、「名前」を設定します。今回は「CognitoS3UploadPolicy」としました。「ポリシーの作成」をクリックし、ポリシーを作成します。

ポリシーが作成できたら、左側の「ロール」をクリックします。ロールが表示されるので、CognitoのUser Poolを作成する時に作成した「Cognito_UserPoolAuth_Role」をクリックします。「ポリシーをアタッチします」をクリックし、「ポリシーのフィルタ」に「S3」を入力し、先ほど作成した 「CognitoS3UploadPolicy」の左側のチェックボックスをクリックしてチェックを入れます。「ポリシーのアタッチ」をクリックして、ポリシーをアタッチします。

これで、Cognitoの認証ユーザーが持つRoleに、S3のAccessに必要な権限を追加したことになります。

Cognitoユーザー認証によるS3 のAccess制御をAmplifyとReactとDropzoneを使って実装する。(その1)

今回は、ユーザーから提供されるFileに対して何かしらの処理を行うことを想定したWeb Serviceの実現の為、File Upload機能を実装します。使うComponentは、今までとほぼ同じく、Cloud側のFile ServiceにS3、ユーザー認証にCognito、Client側はAmplify、Reactを使い、最後にDropZoneによるDrag&Dropを追加します。これにより、Cognitoユーザー認証された 特定多数のUserに対し、S3 BucketにFileをUploadできる機能を実現します。

まずは、File Upload用のS3 Bucketを準備します。Management ConsoleからS3を開きます。前回作成したBucketが見えると思います。「Bucketを作成する」をクリックしてBucketを作成します。 その後のStepは、
1. 「名前とリージョン」タブでバケット名を入力します。バケット名は、FQDN形式で入力します。AWS全体で重複のない名前を指定する必要があります。今回は、”upload.hacya.com”としました。リージョンは”アジアパシフィック(東京)”を選んでおきましょう。
2. 「オプションの設定」タブでは、タグを付けておきましょう。他はデフォルトのままで良いです。
3. 「アクセス許可の設定」タブは、デフォルトのままで良いです。今回は認証されたユーザーにのみ、中身を公開します。
4. 「確認」タブで、内容を確認して「バケットを作成」ボタンをクリックしてBucketを作成します。

作成したBucketのPropertyを見ておきましょう。作成したBucketの左側のチェックボックスをクリックしてチェックを付けると、右側にPop-up Windowが開きPropertyが表示されます。Pop-up Windowsの上の方の「バケットARNをコピーする」をクリックしてARNをクリップボードにコピーし、テキストエディターなどに貼り付け、バケットARNを書き留めておきます。あとで、Policyを作成するときに使います。

次に、作成したBucketにCORSを設定します。CORSは、Cross-Origin Resource Sharingの略で、通常ブラウザは異なるドメインからのデータを読み込めないように設定されています。CORSを設定することで、ブラウザが異なるドメインのデータを読み込めるようにすることができます。例えば、local環境でテストする場合、ReactのApplicationのDefaultでは、http://localhost:3000がOriginとなり、そこからS3のデータを参照する際、例えば東京リージョンのS3のURL、https://s3-ap-northeast-1.amazonaws.comは異なるドメインという事になります。
作成したBucketをクリックして、「アクセス権限」タブをクリック、「CORSの設定」をクリックします。 CORS 構成エディター に、下記の設定を入力し、「保存」をクリックします。

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>*</AllowedOrigin>
    <AllowedMethod>HEAD</AllowedMethod>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>PUT</AllowedMethod>
    <AllowedMethod>POST</AllowedMethod>
    <AllowedMethod>DELETE</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <ExposeHeader>x-amz-server-side-encryption</ExposeHeader>
    <ExposeHeader>x-amz-request-id</ExposeHeader>
    <ExposeHeader>x-amz-id-2</ExposeHeader>
    <ExposeHeader>ETag</ExposeHeader>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>

これで、S3の設定は完了です。