CloudFormationでCognito User Pool（E メールアドレスおよび電話番号）

# CloudFormationでCognito
最近では、ALBの組み込み認証など、AWS Cognitoを使う場面が増えてきた気がします。
ユーザ管理をマネージドでできるのは利点だと思います。
今回は、CloudFormationで、Cognito User PoolやIndentity Pool等を作成します。
なお、User Poolを作成する際に、「E メールアドレスおよび電話番号 - ユーザーは、E メールアドレスまたは電話番号を「ユーザー名」として使用してサインアップおよびサインインできます。」を指定します。
これは、2018年7/5現在、Cognito User Poolの日本語ドキュメントに書かれていないようで、いい感じの日本語の記事がなかったので記述します。

英語ドキュメントには書かれています。
[AWS::Cognito::UserPool](https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-cognito-userpool.html#cfn-cognito-userpool-usernameattributes)

マネージドコンソールでいうと、次のやつを選択した状態です。
<img width="738" alt="スクリーンショット 2018-07-06 22.03.37.png" src="https://qiita-image-store.s3.amazonaws.com/0/152325/c5bce7fd-9738-1458-e4c4-d0c766cf8e7d.png">

以下、CFnのテンプレートです。
今回は、E メールアドレスでログインを想定しています。
ポイントは、UserPoolの`UsernameAttributes:`です。
今回は、 `email`を指定しています。
電話番号でログインする場合は、`phone_number` です。

その他、
UserPoolClinetは、javascript等から使用する想定でシークレットを無効にしています。
UserPool以外は、そのままですが、IdentityPoolを作成し、払い出す権限のRole等を記述しています。

実行は次の通りです。
`$ aws cloudformation deploy --template ./cognito.yaml --stack-name Test --capabilities CAPABILITY_IAM`


```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: "Cognito Identity Pool and User Pool."
Resources:
  UserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      UserPoolName: !Sub "${AWS::StackName}Users"
      AdminCreateUserConfig:
        AllowAdminCreateUserOnly: false
      UsernameAttributes:
        - email
      AutoVerifiedAttributes:
        - email
      Policies:
        PasswordPolicy:
          MinimumLength: 8
      Schema:
        - Name: email
          AttributeDataType: String
          DeveloperOnlyAttribute: false
          Mutable: true
          Required: true
  UserPoolClient:
    Type: AWS::Cognito::UserPoolClient
    Properties:
      ClientName: !Sub "${AWS::StackName}Users-client"
      GenerateSecret: false
      RefreshTokenValidity: 7
      UserPoolId:
        !Ref UserPool
  IdentityPool:
    Type: AWS::Cognito::IdentityPool
    Properties:
      AllowUnauthenticatedIdentities: false
      IdentityPoolName: !Sub "${AWS::StackName}Users"
      CognitoIdentityProviders:
        - ClientId: !Ref UserPoolClient
          ProviderName: !Sub "cognito-idp.${AWS::Region}.amazonaws.com/${UserPool}"
  AuthenticatedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action:
              - mobileanalytics:PutEvents
              - cognito-sync:*
              - cognito-identity:*
            Resource:
              - "*"
  AuthenticatedRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Action: "sts:AssumeRoleWithWebIdentity"
            Principal:
              Federated: cognito-identity.amazonaws.com
            Condition:
              StringEquals:
                "cognito-identity.amazonaws.com:aud": !Ref IdentityPool
              ForAnyValue:StringLike:
                "cognito-identity.amazonaws.com:amr": authenticated
      ManagedPolicyArns: 
        - !Ref AuthenticatedPolicy
  RoleAttachment:
    Type: AWS::Cognito::IdentityPoolRoleAttachment
    Properties:
      IdentityPoolId: !Ref IdentityPool
      Roles:
        authenticated: !GetAtt AuthenticatedRole.Arn

Outputs:
  UserPoolId:
    Value: !Ref UserPool
    Export:
      Name: !Sub "${AWS::StackName}-UserPool"
  UserPoolArn:
    Value: !GetAtt UserPool.Arn
    Export:
      Name: !Sub "${AWS::StackName}-UserPoolArn"
  UserPoolClientId:
    Value: !Ref UserPoolClient
    Export:
      Name: !Sub "${AWS::StackName}-UserPoolClient"
  IdentityPoolId:
    Value: !Ref IdentityPool
    Export:
      Name: !Sub "${AWS::StackName}-IdentityPool"
```