AWS Cognitoを実践で使うときのハマりどころ

この記事は Retty Advent Calendar 21日目です。

昨日は、[@ebonyeye](http://qiita.com/ebonyeye)さんの [手のひらスパコンでKeras-Tensorflowを使ってみる](http://qiita.com/ebonyeye/items/78f3139968ecb23b920a)でした。
最近の機械学習ライブラリはいろんなところで動きますね。

# Cognito
![screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/40572/cc7e5c98-abe5-07d7-0ac0-b78385bb4241.png "screenshot.png")

## Cognitoって何？
https://aws.amazon.com/jp/cognito/
AWSのサービスで、ユーザー認証や情報を取り扱うサービスです。
大きな機能は2つ

- ユーザー認証
	FacebookやTwitterなどのソーシャルログインを一括管理してくれます。
	その他にもゲストユーザーや独自ログインなどを作成することもできます。

- ストレージ
	管理しているユーザーに対して個別にストレージを提供できます。
	Firebaseなんかにあるのと同じよくあるやつです。

## Cognitoを使うと何がうれしい？

#### セキュア

- パスワードや個人情報の管理をCognitoにまかせることができる
- 自前でやろうとすると大変な2段階認証がお手軽に実装できる

#### AWSとのサービス連携

- 認証したユーザーに対して、IAMポリシーを利用してサービスを利用することが可能
- 認証フローの各所でLamdaを呼び出すことができる(すばらしいですね！)

## 独自ログイン

- User Poolという機能が追加
- 7月にbetaがとれたところ
- 自前の認証サービスをサーバレス、DBレスで作ることができる
- メール認証やSMSによる2段階認証もサポート(SNS経由)

こんな素晴らしいことばっかりなCognitoさんですが、独自ログインを実際に使おうとすると様々なハマりどこがありました。

# User Poolの設定

初期設定などはすでにいろんなところで書かれていますのでそちらを参照してください。

## attributes
![screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/40572/6e7f0b0c-a85c-d06e-58b6-2f260b538fe1.png "screenshot.png")

デフォルトでこのようなattributesが用意されています。
作る時にattributesを追加したり、後でも出来ます。

### <font color="Red">ハマりどころその1 あとから変えられない</font>
#### Required(必須項目)は最初だけしか設定できない
一度作った後変更することができません。
間違うと、イチから作り直しになります。サービス開始してから気がついたら悲劇ですね。 

#### Aliasも同じ
Aliasはチェックをつけると、登録したメールアドレスや電話番号などでもログインできるようになる今時な機能です。
しかしこちらも最初しか設定できないので注意が必要です。
もう一点注意があります。当たり前ですがエイリアスを設定した場合usernameにエイリアスに合致するパターンが入力できなくなります。

#### 2段階認証(MFA)の必須も同じ
![screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/40572/5596ae9d-4abf-9931-2f20-00ae16543d11.png "screenshot.png")
必須にするかオプションにするか作成時に選べますが、Requiredが選べるのは最初だけなので忘れないように。
も1つ罠があり、作成後うっかりOptionalにしてしまうとRequiredには戻せません。
alertもでてくれません。
本番運用開始したらくれぐれも注意しましょう。
もう一点めんどくさいのですが、SMSを使うためにはIAMロールをUserPoolごとに作成しないといけません。使い回しができない。
権限持っていない場合はTry and Errorが非常に辛いことになります。

http://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/user-pool-settings-attributes.html#user-pool-settings-aliases


### <font color="Red">解決策</font>
- 開発用UserPoolを作ってじっくり繰り返し設計する
- Required、Aliasの設定は最小限にしてアプリケーション側でコントロールする

## Aliasログイン

ログインを試す場合はiOSの[サンプルアプリ](https://github.com/awslabs/aws-sdk-ios-samples/tree/master/CognitoYourUserPools-Sample/Objective-C)が公開されています。
その他のものも[こちら](https://github.com/search?q=org%3Aawslabs+Cognito)から探せばあるとおもいます。

### <font color="Red">ハマりどころその2 Aliasが使えない</font>
先ほどAliasにチェックを入れておけばログインIDとして使えると書きましたが、とある条件をクリアしないと使えないという罠があります。
取り敢えず適当に作ってやってみると使えたり使えなかったりする場合があります。

### <font color="Red">解決策</font>

#### クリア条件 verification
メールアドレスや電話番号でのログインはverificationが完了しないとログインIDとしては使用できません。
SNSを経由して認証コードが送られますが、メール認証した場合はメールアドレスがIDとしてしよう可に、SMSでやった場合は電話番号でログインが可能になります。

![screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/40572/785a7b2f-786c-3138-185f-db5326b0fe45.png "screenshot.png")

<font color="Red">このような設定がありますが、メールと電話番号の両方でverificationする設定にしておいて、SMS経由で届いた認証コードでアカウントアクティベートすると電話番号をIDとして使用できますが、メールアドレスではログイン出来ません。</font>
ちなみに両方チェック入れるとSMSにしかそもそも届かないという罠も追加であります。
>
ユーザーが電話番号とメールアドレスの両方にサインアップし、ユーザープール設定で両方の属性の確認が必要な場合は、確認コードが SMS 経由で電話に送信されます。E メールアドレスが検証されていません。 アプリは GetUser を呼び出して、メールアドレスが認証を待っているかどうかを確認できます。認証を待っている場合、アプリは GetUserAttributeVerificationCode を呼び出して E メール確認フローを開始し、VerifyUserAttribute を呼び出して確認コードを送信する必要があります。

メールアドレスでもAliasを有効にしたい場合は別途メールアドレスのverificationを行わないといけません。
利便性を考えると、Aliasはメールアドレスか電話番号のどちらかにしておくほうがよさそうです。

http://docs.aws.amazon.com/ja_jp/cognito/latest/developerguide/user-pool-settings-email-phone-verification.html


# SMS(SNS)によるMFA認証

これで無事設定もすんで開発を進められる、とおもいきやまだ罠があります。

### <font color="Red">ハマりどころその3 SMSが届かない</font>

最初は問題ないのですが、突然とどかなくなります
体感値としては数十通ぐらいでとどかなくなります
しかし数日たつと届いたりもします

### <font color="Red">解決策</font>

これはCognitoではなくSNSの設定が原因です。
SMSは金額上限が設定されており、それを超えると送れなくなります。

![screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/40572/ec535a33-f117-d289-356c-4ef75a66f557.png "screenshot.png")

さて、初期状態では上限はいくらなんでしょうか？

>
Q: アカウントレベルおよびメッセージレベルの支出限度とは何ですか? また、どのように機能しますか?
>
支出限度は AWS アカウントに対して、および個別のメッセージに対して指定でき、SMS メッセージの送信コストにのみ適用されます。アカウントあたりの支出制限はデフォルトで (指定されていない場合) 00.00 USD/月です。デフォルトの支出制限を引き上げるには、こちらを参照して制限の拡大リクエストを入力してください。Amazon SNS では、SMS トラフィックにより発生する暦月のコスト合計が支出制限以下である間、お客様の発行する SMS が送信されます。支出制限を超過すると、支出制限が引き上げられるか、新しい暦月の開始まで、Amazon SNS からメッセージが配信されなくなります。同様に、個別のメッセージに対して支出制限を指定することもできます。コストが制限以下である場合にのみ、Amazon SNS からメッセージが送信されます。アカウントレベルの支出制限が超過した場合、メッセージレベルの支出制限が超過したかどうかにかかわらず、Amazon SNS から SMS メッセージが送信されなくなります。

<font color="Red">00.00 USD/月です</font>

https://aws.amazon.com/jp/sns/faqs/#sms-related-questions

よくわからないんですが、1ドル分ぐらいは送れたのでそのぐらいになにかあるっぽいです…

ちなみにデフォルトではSMSのログは見れないのでCloudWatchで見れるようにしておくことをおすすめします。
送信成功、失敗ログが見れるようになります。

![screenshot.png](https://qiita-image-store.s3.amazonaws.com/0/40572/a934456b-3d44-42b0-a8e4-f6b66df1c49e.png "screenshot.png")

No quota left for account が失敗理由ですね。

### <font color="Red">ハマりどころその4 SMSが届かないpart2</font>

設定を見つけてlimitを上げてさあこれで送れるはず！と思うのですがこれが届きません！
たまに届くこともあります！

### <font color="Red">解決策</font>
limitの反映は即時ではない模様。
反映されてるかどうかはSMSを送信後のログから確認できます。
翌日やったら届いたので一日余裕を見たほうが良さそうです。

デフォルトの課金上限は50ドル。
それ以上似あげたい場合には申請が必要なのでサービスのリリース前には早めに余裕を持って上げておいたほうが良さそうです。
ログインできないはシャレにならないですからね。

# さいごに
いろいろ罠も多いけれど、お手軽にMFA認証付きの認証基盤が使えるのは素晴らしいことです。
パスワードや個人情報の取扱に困っている方は是非検討してみてはいかがでしょうか？