AmplifyCLIのオーバーライド機能まとめ

本記事は [AWS AmplifyとAWS×フロントエンド #AWSAmplifyJP Advent Calendar 2023](https://qiita.com/advent-calendar/2023/amplify)の19日目の記事です。

# はじめに
最近発表のあったAmplifyのGen2についてまだ詳しく情報収集はできていませんが、開発方法が大きく変わり、Gen1では手が届かなかった痒いところにも手が届きやすくなって開発体験はより良くなりそうな印象です。

近い将来にはAmplifyのGen2がベターな方法になって行くかとは思いますが、まだプレビューのお試し状態ですので、本番運用で使うAmplifyについてはまだしばらくGen1が続きそうです。

そんなGen1をまだまだ現役として少しでも快適に使うために今回は、AmplicyCLIのオーバーライド機能について簡単に書いていきたいと思います。

# Amplifyのオーバライド機能
AmplifyCLIの対話方式では設定ができない細かいバックエンドの設定をAmplify管理の中で行うことができる機能です。

初期の頃は、Amplifyによって自動生成されるCloudFormationのファイルを直接触って設定を行うなんてこともしていましたが、色々大変でしたので、こうやって1つ1つ改善されて言っていることを改めて感じます。

現状オーバーライドに関してはproject/api/auth/storageの4つが用意されています。

# プロジェクトレベルのオーバライド
Amplifyが生成したプロジェクトレベルのIAMリソースの設定が行えます。

```console
$ amplify override project
```

参考
[Override Amplify-generated project-level IAM resources](https://docs.amplify.aws/javascript/tools/cli/project/override-iam/)
[AWS::IAM::Role](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-iam-role.html)

## authRoleポリシーに特定の権限を追加

```ts:override.ts
import { AmplifyRootStackTemplate } from "@aws-amplify/cli-extensibility-helper";

export function override(resources: AmplifyRootStackTemplate) {
  const authRole = resources.authRole;

  const basePolicies = Array.isArray(authRole.policies)
    ? authRole.policies
    : [authRole.policies];

  authRole.policies = [
    ...basePolicies,
    {
      policyName: "amplify-permissions-custom-resources",
      policyDocument: {
        Version: "2012-10-17",
        Statement: [
          // 追加したいリソースの権限を追加
          {
            Resource: "<ARN of Geo>",
            Action: ["geo:CalculateRoute*"],
            Effect: "Allow",
          },
        ],
      },
    },
  ];
}

```

参考
[GraphQL override not working](https://github.com/aws-amplify/amplify-cli/issues/10054)

# APIのオーバーライド設定
Amplifyで作成したAppSyncやDynaamoDBの設定の上書きができます。

```console
$ amplify override api
```
参考
[Modify Amplify-generated resources](https://docs.amplify.aws/javascript/build-a-backend/graphqlapi/modify-amplify-generated-resources/)
[AWS AppSync resource type reference](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/AWS_AppSync.html)

## 本番環境だけポイントインタイムリカバリを有効化

```ts:override.ts
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper'
import { ModelDirectiveStack } from '@aws-amplify/cli-extensibility-helper/lib/types/api/amplify-api-resource-stack-types'

type Models =
  | 'TargetTable1'
  | 'TargetTable2'
  | 'TargetTable3'

export function override({ models }: AmplifyApiGraphQlResourceStackTemplate) {
  const modelNames: Models[] = ['TargetTable1', 'TargetTable2', 'TargetTable3']
  const modelsMap = models as Partial<Record<Models, ModelDirectiveStack>>
  // 環境名の取得 // https://qiita.com/naniwadari/items/7944b31ce52f85646e2c
  const amplifyMetaJson = require('../../../amplify-meta.json')
  const prodEnv = amplifyMetaJson.providers.awscloudformation.StackName
    .split('-')
    .find((part) => part === 'prod')

  if (prodEnv) {
    modelNames.forEach((modelName) => {
      const model = modelsMap[modelName]
      if (model) {
        prepareForExport(model)
      }
    })
  }
}

function prepareForExport(model: ModelDirectiveStack) {
  model.modelDDBTable.pointInTimeRecoverySpecification = {
    pointInTimeRecoveryEnabled: true,
  }
}

```

参考
[GraphQL override not working](https://github.com/aws-amplify/amplify-cli/issues/10054)
[Amplifyのoverride.tsで環境名を取得する](https://qiita.com/naniwadari/items/7944b31ce52f85646e2c)

##  X-Rayのトレースを有効化

```ts:override.ts
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper';

export function override(resources: AmplifyApiGraphQlResourceStackTemplate) {
  resources.api.GraphQLAPI.xrayEnabled = true
}
```

参考
[AWS::AppSync::GraphQLApi](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-appsync-graphqlapi.html#cfn-appsync-graphqlapi-xrayenabled)


## TTLを有効化

```ts:override.ts
import { AmplifyApiGraphQlResourceStackTemplate } from '@aws-amplify/cli-extensibility-helper'
import { ModelDirectiveStack } from '@aws-amplify/cli-extensibility-helper/lib/types/api/amplify-api-resource-stack-types'

type Models =
  | 'TargetTable1'
  | 'TargetTable2'
  | 'TargetTable3'

export function override({ models }: AmplifyApiGraphQlResourceStackTemplate) {
  const modelNames: Models[] = ['TargetTable1', 'TargetTable2', 'TargetTable3']
  const modelsMap = models as Partial<Record<Models, ModelDirectiveStack>>

  modelNames.forEach((modelName) => {
    const model = modelsMap[modelName]
    if (model) {
      prepareForExport(model)
    }
  })
}

function prepareForExport(model: ModelDirectiveStack) {
  model.modelDDBTable.timeToLiveSpecification = {
    attributeName: "ttl",
    enabled: true
  }
}

```

参考
[AWS::DynamoDB::Table TimeToLive](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-dynamodb-table-timetolivespecification.html)


# Authのオーバーライド設定
Amplifyで作成したCognitoの設定の上書きができます。

```console
$ amplify override auth
```
参考
[Amazon Cognito resource type reference](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/AWS_Cognito.html)

## デバイス情報を常に記憶する

```ts:override.ts
import { AmplifyAuthCognitoStackTemplate } from '@aws-amplify/cli-extensibility-helper'

export function override(resources: AmplifyAuthCognitoStackTemplate) {
 resources.userPool.deviceConfiguration = {
    challengeRequiredOnNewDevice: true,
  }
}
```
参考
[AWS::Cognito::UserPool DeviceConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpool-deviceconfiguration.html)

## SESを使ったメール送信設定


```ts:override.ts
import { AmplifyAuthCognitoStackTemplate } from '@aws-amplify/cli-extensibility-helper'

export function override(resources: AmplifyAuthCognitoStackTemplate) {
  resources.userPool.emailConfiguration = {
    replyToEmailAddress: 'test@example.com', // 返信の宛先メールアドレス
    emailSendingAccount: 'DEVELOPER', // SES使用を指定
    from: 'example.com <support@example.com>', // Fromの表示設定
    sourceArn: 'arn:aws:ses:xxxx:000:identity/yyy', // SESで検証済みドメインのarn
  }
}
```
参考
[AWS::Cognito::UserPool EmailConfiguration](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpool-emailconfiguration.html)

## ユーザー名の小文字大文字判定

```ts:override.ts
import { AmplifyAuthCognitoStackTemplate } from '@aws-amplify/cli-extensibility-helper'

export function override(resources: AmplifyAuthCognitoStackTemplate) {
  resources.userPool.usernameConfiguration = {
    caseSensitive: true,
  }
}

```
参考
[AWS::Cognito::UserPool UsernameConfiguration
](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpool-usernameconfiguration.html)

## パスワード設定の上書き

```ts:override.ts
import { AmplifyAuthCognitoStackTemplate } from '@aws-amplify/cli-extensibility-helper';

export function override(resources: AmplifyAuthCognitoStackTemplate) {
  resources.userPool.policies = {
    passwordPolicy: {
      ...resources.userPool.policies["passwordPolicy"], // 現在の設定を展開
      // 上書きしたい設定
      minimumLength: 12, // 最小数
      requireLowercase: true, // 小文字必須
      requireNumbers: true, // 数字必須
      requireSymbols: true, // 記号必須
      requireUppercase: true, // 大文字必須
      temporaryPasswordValidityDays: 2 // 一時的なパスワードの有効日数
    }
  }
}
```

参考
[AWS::Cognito::UserPool PasswordPolicy](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpool-passwordpolicy.html)

## 管理者のみにユーザーの作成を許可

```ts:override.ts
import { AmplifyAuthCognitoStackTemplate } from '@aws-amplify/cli-extensibility-helper'

export function override(resources: AmplifyAuthCognitoStackTemplate) {
  resources.userPool.adminCreateUserConfig = {
    allowAdminCreateUserOnly: true
  }
}

```

参考
[AWS::Cognito::UserPool AdminCreateUserConfig](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-cognito-userpool-admincreateuserconfig.html)

## トークンの設定

```ts:override.ts
import { AmplifyAuthCognitoStackTemplate } from '@aws-amplify/cli-extensibility-helper'

export function override(resources: AmplifyAuthCognitoStackTemplate) {
  // 各トークンの有効期限
  resources.userPoolClientWeb.accessTokenValidity = 30;
  resources.userPoolClientWeb.idTokenValidity = 30;
  resources.userPoolClientWeb.refreshTokenValidity = 30;
  // 各トークンの有効期限の単位
  resources.userPoolClientWeb.tokenValidityUnits = {
    accessToken: 'hours',
    idToken: 'hours',
    refreshToken: 'hours'
  };
}
```
参考
[AWS::Cognito::UserPoolClient](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpoolclient.html)

# Storageのオーバーライド設定
Amplifyで作成したS3などの設定の上書きができます。

```console
$ amplify override storage
```

参考
[Modify Amplify-generated resources](https://docs.amplify.aws/javascript/build-a-backend/storage/modify-amplify-generated-resources/)
[Amazon Simple Storage Service (Amazon S3) resource type reference](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/AWS_S3.html)

## バージョニングの設定

```ts:override.ts
import { AmplifyS3ResourceTemplate } from '@aws-amplify/cli-extensibility-helper';

export function override(resources: AmplifyS3ResourceTemplate) {
  resources.s3Bucket.versioningConfiguration = {
    status: 'Enabled',
  };
}
```
参考
[AWS::S3::Bucket VersioningConfiguration](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-versioningconfiguration.html)

## ライフサイクルポリシーの設定

```ts:override.ts
import { AmplifyS3ResourceTemplate } from '@aws-amplify/cli-extensibility-helper';

export function override(resource: AmplifyS3ResourceTemplate): void {
  resource.s3Bucket.lifecycleConfiguration = {
    rules: [
      {
        status: 'Enabled',
        noncurrentVersionExpiration: {
          noncurrentDays: 30, // 30日で削除
          newerNoncurrentVersions: 10, // 最新のオブジェクト10個は保持
        },
      },
    ],
  };
}
```

参考
[AWS::S3::Bucket LifecycleConfiguration](https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket-lifecycleconfiguration.html)
[AmplifyのOverride機能を使って、S3にバージョニングとライフサイクルポリシーを設定する方法](https://zenn.dev/ncdc/articles/9ffabe33a25dbc)

# おわりに
オーバーライド機能によって、Amplify管理の中でより細かい設定も行えるようになったので、開発規模が大きくなっても対応しやすくなってきました。

ただ、そもそも各AWSサービスの基礎知識がなければ設定のしようもないので、より踏み込んだ開発を行うためには、各AWSサービスの学習をもっとしなければ、と感じている今日このごろです。

引き続きAmplifyの今後の動向にもチェックしながら、今後のさらなる発展に期待です。

良きAmplifyライフを！