amplify の権限設定とエラー回避

# はじめに

この記事は、完全に自分のための備忘録ですが、もし同じエラーに遭遇した人のために記録しておくことにします。

## 何が起きたのか

React アプリを作成していて、ホスティングをどうしようかなやんでいたところ、AWS Amplify が便利そうだったので早速以下の記事を参考にしてホスティングのテストをしてみました。

[AWS Amplify Console で素の React アプリをホスティングしてみよう](https://aws.amazon.com/jp/builders-flash/202005/amplify-react-hosting/?awsf.filter-name=*all)

めちゃくちゃ簡単そう！

## IAM のアクセス権

手順通りにやっていくと、途中で IAM ユーザを作ることになります。専用に IAM ユーザを作るのはいいのですけど、アクセス権限をどうするかが悩みどころ。`AdministratorAccess` はさすがに躊躇するので、Amplify に特化したアクセス権はないかと探してみると、`AdministratorAccess-Amplify` ってのがありました。

```json:AdministratorAccess-Amplify
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "CLICloudformationPolicy",
            "Effect": "Allow",
            "Action": [
                "cloudformation:CreateChangeSet",
                "cloudformation:CreateStack",
                "cloudformation:DeleteStack",
                "cloudformation:DescribeChangeSet",
                "cloudformation:DescribeStackEvents",
                "cloudformation:DescribeStackResource",
                "cloudformation:DescribeStackResources",
                "cloudformation:DescribeStacks",
                "cloudformation:ExecuteChangeSet",
                "cloudformation:GetTemplate",
                "cloudformation:UpdateStack"
            ],
            "Resource": [
                "arn:aws:cloudformation:*:*:stack/amplify-*"
            ]
        },
        {
            "Sid": "CLIManageviaCFNPolicy",
            "Effect": "Allow",
            "Action": [
                "iam:CreateRole",
                "iam:ListRoleTags",
                "iam:TagRole",
                "iam:AttachRolePolicy",
                "iam:CreatePolicy",
                "iam:DeletePolicy",
                "iam:DeleteRole",
                "iam:DeleteRolePolicy",
                "iam:DetachRolePolicy",
                "iam:PutRolePolicy",
                "iam:UpdateRole",
                "iam:GetRole",
                "iam:GetPolicy",
                "iam:GetRolePolicy",
                "iam:PassRole",
                "iam:ListPolicyVersions",
                "appsync:CreateApiKey",
                "appsync:CreateDataSource",
                "appsync:CreateFunction",
                "appsync:CreateResolver",
                "appsync:CreateType",
                "appsync:DeleteApiKey",
                "appsync:DeleteDataSource",
                "appsync:DeleteFunction",
                "appsync:DeleteResolver",
                "appsync:DeleteType",
                "appsync:GetDataSource",
                "appsync:GetFunction",
                "appsync:GetIntrospectionSchema",
                "appsync:GetResolver",
                "appsync:GetSchemaCreationStatus",
                "appsync:GetType",
                "appsync:GraphQL",
                "appsync:ListApiKeys",
                "appsync:ListDataSources",
                "appsync:ListFunctions",
                "appsync:ListGraphqlApis",
                "appsync:ListResolvers",
                "appsync:ListResolversByFunction",
                "appsync:ListTypes",
                "appsync:StartSchemaCreation",
                "appsync:UpdateApiKey",
                "appsync:UpdateDataSource",
                "appsync:UpdateFunction",
                "appsync:UpdateResolver",
                "appsync:UpdateType",
                "appsync:TagResource",
                "appsync:CreateGraphqlApi",
                "appsync:DeleteGraphqlApi",
                "appsync:GetGraphqlApi",
                "appsync:ListTagsForResource",
                "appsync:UpdateGraphqlApi",
                "apigateway:DELETE",
                "apigateway:GET",
                "apigateway:PATCH",
                "apigateway:POST",
                "apigateway:PUT",
                "cognito-idp:CreateUserPool",
                "cognito-identity:CreateIdentityPool",
                "cognito-identity:DeleteIdentityPool",
                "cognito-identity:DescribeIdentity",
                "cognito-identity:DescribeIdentityPool",
                "cognito-identity:SetIdentityPoolRoles",
                "cognito-identity:GetIdentityPoolRoles",
                "cognito-identity:UpdateIdentityPool",
                "cognito-idp:CreateUserPoolClient",
                "cognito-idp:DeleteGroup",
                "cognito-idp:DeleteUserPool",
                "cognito-idp:DeleteUserPoolClient",
                "cognito-idp:DescribeUserPool",
                "cognito-idp:DescribeUserPoolClient",
                "cognito-idp:ListTagsForResource",
                "cognito-idp:ListUserPoolClients",
                "cognito-idp:UpdateUserPoolClient",
                "cognito-idp:CreateGroup",
                "cognito-idp:DeleteGroup",
                "cognito-identity:TagResource",
                "cognito-idp:TagResource",
                "cognito-idp:UpdateUserPool",
                "lambda:AddPermission",
                "lambda:CreateFunction",
                "lambda:DeleteFunction",
                "lambda:GetFunction",
                "lambda:GetFunctionConfiguration",
                "lambda:InvokeAsync",
                "lambda:InvokeFunction",
                "lambda:RemovePermission",
                "lambda:UpdateFunctionCode",
                "lambda:UpdateFunctionConfiguration",
                "lambda:ListTags",
                "lambda:TagResource",
                "lambda:UntagResource",
                "lambda:DeleteFunction",
                "lambda:AddLayerVersionPermission",
                "lambda:CreateEventSourceMapping",
                "lambda:DeleteEventSourceMapping",
                "lambda:DeleteLayerVersion",
                "lambda:GetEventSourceMapping",
                "lambda:GetLayerVersion",
                "lambda:ListEventSourceMappings",
                "lambda:ListLayerVersions",
                "lambda:PublishLayerVersion",
                "lambda:RemoveLayerVersionPermission",
                "dynamodb:CreateTable",
                "dynamodb:DeleteItem",
                "dynamodb:DeleteTable",
                "dynamodb:DescribeContinuousBackups",
                "dynamodb:DescribeTable",
                "dynamodb:DescribeTimeToLive",
                "dynamodb:ListStreams",
                "dynamodb:PutItem",
                "dynamodb:TagResource",
                "dynamodb:ListTagsOfResource",
                "dynamodb:UpdateContinuousBackups",
                "dynamodb:UpdateItem",
                "dynamodb:UpdateTable",
                "dynamodb:UpdateTimeToLive",
                "s3:CreateBucket",
                "s3:ListBucket",
                "s3:PutBucketAcl",
                "s3:PutBucketCORS",
                "s3:PutBucketNotification",
                "s3:PutBucketPolicy",
                "s3:PutBucketWebsite",
                "s3:PutObjectAcl",
                "cloudfront:CreateCloudFrontOriginAccessIdentity",
                "cloudfront:CreateDistribution",
                "cloudfront:DeleteCloudFrontOriginAccessIdentity",
                "cloudfront:DeleteDistribution",
                "cloudfront:GetCloudFrontOriginAccessIdentity",
                "cloudfront:GetCloudFrontOriginAccessIdentityConfig",
                "cloudfront:GetDistribution",
                "cloudfront:GetDistributionConfig",
                "cloudfront:TagResource",
                "cloudfront:UntagResource",
                "cloudfront:UpdateCloudFrontOriginAccessIdentity",
                "cloudfront:UpdateDistribution",
                "events:DeleteRule",
                "events:DescribeRule",
                "events:ListRuleNamesByTarget",
                "events:PutRule",
                "events:PutTargets",
                "events:RemoveTargets",
                "mobiletargeting:GetApp",
                "kinesis:AddTagsToStream",
                "kinesis:CreateStream",
                "kinesis:DeleteStream",
                "kinesis:DescribeStream",
                "kinesis:PutRecords"
            ],
            "Resource": "*",
            "Condition": {
                "ForAnyValue:StringEquals": {
                    "aws:CalledVia": [
                        "cloudformation.amazonaws.com"
                    ]
                }
            }
        },
        {
            "Sid": "CLISDKCalls",
            "Effect": "Allow",
            "Action": [
                "appsync:GetIntrospectionSchema",
                "appsync:GraphQL",
                "appsync:UpdateApiKey",
                "appsync:ListApiKeys",
                "s3:PutObject",
                "s3:GetObject",
                "s3:ListBucket",
                "s3:ListBucketVersions",
                "s3:DeleteBucket",
                "s3:DeleteBucketPolicy",
                "s3:DeleteBucketWebsite",
                "s3:DeleteObject",
                "s3:GetBucketLocation",
                "s3:ListAllMyBuckets",
                "sts:AssumeRole",
                "iam:PutRolePolicy",
                "iam:CreatePolicy",
                "iam:AttachRolePolicy",
                "mobiletargeting:*",
                "amplify:CreateApp",
                "amplify:CreateBackendEnvironment",
                "amplify:GetApp",
                "amplify:GetBackendEnvironment",
                "amplify:ListApps",
                "amplify:ListBackendEnvironments",
                "amplify:CreateBranch",
                "amplify:GetBranch",
                "amplify:UpdateApp",
                "amplify:ListBranches",
                "amplify:ListDomainAssociations",
                "amplify:DeleteBranch",
                "amplify:DeleteApp",
                "amplify:DeleteBackendEnvironment",
                "amplifybackend:*",
                "cognito-idp:AdminAddUserToGroup",
                "cognito-idp:AdminCreateUser",
                "cognito-idp:CreateGroup",
                "cognito-idp:DeleteGroup",
                "cognito-idp:DeleteUser",
                "cognito-idp:ListUsers",
                "cognito-idp:AdminGetUser",
                "cognito-idp:ListUsersInGroup",
                "cognito-idp:AdminDisableUser",
                "cognito-idp:AdminRemoveUserFromGroup",
                "cognito-idp:AdminResetUserPassword",
                "cognito-idp:AdminListGroupsForUser",
                "cognito-idp:ListGroups",
                "cognito-idp:AdminDeleteUser",
                "cognito-idp:AdminListUserAuthEvents",
                "cognito-idp:AdminDeleteUser",
                "cognito-idp:AdminConfirmSignUp",
                "cognito-idp:AdminEnableUser",
                "cognito-idp:AdminUpdateUserAttributes",
                "cognito-idp:DescribeIdentityProvider"
            ],
            "Resource": "*"
        }
    ]
}
```

なんかめっちゃ色々設定されているけど、とりあえずこれでいってみましょう。

## amplify init で色々エラー

しかし、この状態で`amplify init`を実行するとなにやらエラーがでてしまう。
![スクリーンショット 2021-06-08 9.38.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/9add9504-6ba9-95ac-addc-482e48f6dfc1.png)

メッセージの内容を見ると、S3 とか、IAM あたりでのエラーっぽい。
しょうがないので、アクセス権限に以下の２つを追加しましょう。

- IAMFullAccess
- AmazonS3FullAccess

多分、FullAccessなんていらないと思うんですけど、細かく調べるのも面倒なのでね。
さて、これでもう一度 `amplify init` を実行してみます。

![スクリーンショット 2021-06-08 9.51.27.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/5f62fbbd-9cec-581a-a44e-f237276c26d6.png)

うまくいきましたね。パチパチ。

## amplify publish でエラー

では先程の手順に従って`amplify add hosting`をやってみます。

![スクリーンショット 2021-06-08 9.54.03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/f58af979-62e1-44f6-10d0-82e03f23ae0b.png)

いいですね。うまくいったようです。
では、さっそくパブリッシュしてみましょう。

`amplify publish`

![スクリーンショット 2021-06-08 11.49.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/c15a2875-bb95-0d5f-fd74-81f404e7345c.png)

あー、最後の最後にエラーになりますね。

```sh
An error occurred during the publish operation: User: （省略）
```

色々調べてみると、パブリッシュするためには、Amplify の権限が足りないみたいです。
なので、インラインポリシーでAmplify のすべての権限を付与してみましょう。

![スクリーンショット 2021-06-08 11.42.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/accdeb7d-63e4-6b45-0543-d4db761045ab.png)

さっそくパブリッシュ！
しかし、これだと状況は変わりませんでした。
色々悩んだところ、どうも一度`amplify init`しちゃっているとアクセス権を変えてもだめっぽい。
なので、一度`amplify delete`でアプリを消して、再度`amplify init`からやり直して、無事にパブリッシュができるようになりました（違っているかもしれないので、違っていたら教えて下さい）。

最終的なアクセス権限はこんな感じになりました。
![AmplifyPolicy.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/86046/dea1242a-a152-f61f-16a7-efd3880d9f08.png)

とりあえず、同じ事象にハマっている人のためになれば。