特定条件下の CognitoでSMSのSenderを外部サービスに置き換える

## そもそも Cognito でSMSを送る設定をするには (おまけ)

### 以下の2つが必要とされている

- Amazon SNS の使用量の上限の引き上げをリクエストする
- Amazon Pinpoint 発信元アイデンティティを設定 ※CustomSMSSender を利用する場合は当然不要

### Amazon SNS の使用量の上限の引き上げをリクエストする
AWS サポートセンター > ケースの作成 > [サービスの制限緩和をお探しですか?](https://support.console.aws.amazon.com/support/home?region=ap-northeast-1#/case/create?issueType=service-limit-increase) より

`制限タイプ： SNS Text Messaging`
を選択し、文書を送信。
``` 文書
Cognito ユーザープールにて SMS による認証コードの送信を行いたいため、引き上げをしたい次第です。
金額は $1 -> $10 へ引き上げ予定です。
何卒よろしくお願いいたします。
```
3時間ほどで許可が得られ、引き上げ完了。
その後、以下の手順で SMS の上限金額を変更する。
https://docs.aws.amazon.com/sns/latest/dg/sms_preferences.html

### Amazon Pinpoint 発信元アイデンティティを設定

これは日本国内を対象としたサービスなら設定不要です。


## 本題：特定条件下のCognitoでSMSのSenderを外部サービスに置き換えるには

- 特定条件とは `AttributesRequireVerificationBeforeUpdate` が設定されている場合です

### `AttributesRequireVerificationBeforeUpdate` とは
- ログインに必要なEmailなどを変更した場合に、本人確認する前にその属性が変わってしまうという問題に対応した設定項目です。以下が参考になります。

https://dev.classmethod.jp/articles/cognito-changeemail/

### カスタム SMS 送信者の Lambda トリガー を使う

- トリガーについての公式は[こちら](https://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/user-pool-lambda-custom-sms-sender.html)

### 手順

1. Lambda関数を作成
2. KMSでキーの作成
3. Lambdaを作成
4. cognitoにLambdaへアクセス件を付与
5. update-user-pool で 利用するLambdaを指定


### 1,2,3 はこちらの記事を参照

https://qiita.com/kiwi26/items/0ed9e51c9089cf6e7ca9

### 4. cognitoにLambdaへアクセス件を付与

``` 4. cognitoにLambdaへアクセス件を付与
aws lambda add-permission \
  --function-name arn:aws:lambda:ap-northeast-1:xxxxxxxxxx:function:xxxxxCustomSmsSenderTrigger \
  --statement-id "CognitoLambdaInvokeAccess" \
  --action lambda:InvokeFunction \
  --principal cognito-idp.amazonaws.com
```

当然ですが、↑これが無いと トリガーが発火される際に以下のようなエラーが出ます。
(コンソールからトリガーを設定するとこの辺り自動で設定されるのですが、CustomSmsSenderトリガーは自分で操作しないといけません)
```
An error occurred (UnexpectedLambdaException) when calling the SignUp operation: CustomSMSSender invocation failed due to error AccessDeniedException.
```

### 5. update-user-pool で 利用するLambdaを指定

``` 5. update-user-pool 
aws cognito-idp update-user-pool \
  --user-pool-id ap-northeast-1_00000000 \
  --auto-verified-attributes phone_number \
  --sms-configuration "SnsCallerArn=arn:aws:iam::xxxxxxxxx:role/service-role/xxxxxxxxxRole,ExternalId=0000000-0000-0000-0000-000000000000" \
  --lambda-config "CustomSMSSender={LambdaVersion=V1_0,LambdaArn=arn:aws:lambda:ap-northeast-1:xxxxxxxxx:function:xxxxxxCustomSmsSenderTrigger},KMSKeyID=arn:aws:kms:ap-northeast-1:xxxxxxxxx:key/0000000-0000-0000-0000-000000000000"
```

こちらがはまりどころで、注意点がいくつかあります。


#### `AttributesRequireVerificationBeforeUpdate` を設定している場合

`--auto-verified-attributes` を指定していないと、以下のエラーが発生。

```
An error occurred (InvalidParameterException) when calling the UpdateUserPool operation: All attributes in AttributesRequireVerificationBeforeUpdate must exist in AutoVerifiedAttributes
```

#### `--auto-verified-attributes phone_number` が指定されている場合

`--sms-configuration` が無いと `update-user-pool` が以下のエラーを出して失敗します。初見では何の設定か分からずかなり時間を浪費してししまいました。

```
 when calling the UpdateUserPool operation: SMS configuration is required when phone_number is selected for auto verification
```

#### `--sms-configuration`を指定する場合

`ExternalId`が指定されていないと、コンソールのサインアップエクスペリエンスの編集画面で更新ボタンが押せなくなる場合があります。

外部のSMSSenderを利用するので ExternalIdは不要なのですが、 **ダミーでも良いので** UUID　を指定して入力しておかないと、
コンソールからの操作ができなくなります。


## まとめ

以上です！
上記の一連のはまりどころは `AttributesRequireVerificationBeforeUpdate` に起因する問題が主だと思われますが、
同じように手間取った人の助けになれば幸いです！