API GatewayのIAM認証をCOGNITOユーザプールで試してみた

API GatewayのIAM認証をCOGNITOユーザプールで試してみた:

こんにちは。

インフラ・エンジニアです。

AWS API Gateway のIAM認証を試してみました。

IAM認証で使用するロールは、COGNITOユーザープールに作成したグループに設定し、

このロールでAPIが実行できるか試してみました。

検証環境の構築は、CloudFormation でやってみたので、手順を紹介します。

ここでは、ソースなどの細かい説明は割愛していますので、

参考にしたサイトやAWSマニュアルの説明など、他のよくできたページを見てください。

■前提

・作業はMACで実施

・awscliが作業用のMACにインストール済み。 コマンド実行時は profileを指定。

$ python --version 
Python 2.7.15 
$ aws --version 
aws-cli/1.16.17 Python/2.7.15 Darwin/17.7.0 botocore/1.12.7 
■参考にしたサイト

https://qiita.com/ykarakita/items/f58f861165db5b81aea0

https://aws.amazon.com/jp/blogs/mobile/building-fine-grained-authorization-using-amazon-cognito-user-pools-groups/

https://forums.aws.amazon.com/thread.jspa?threadID=255584


1. API Gateway の構築

API Gatewayを構築します。

IAM認証のGETメソッドをMOCで1つ作成して、デプロイします。

GETメソッドのレスポンスはJSONです。

CloudFormationのソースは以下の通り。

SandboxApiGateay.yaml
AWSTemplateFormatVersion: 2010-09-09 
Description: API Gateway Sandbox 
 
Resources: 
 
  # Rest API 
  RestAPI: 
    Type: 'AWS::ApiGateway::RestApi' 
    Properties: 
      Description: sandbox 
      Name: !Ref 'AWS::StackName' 
      EndpointConfiguration: 
        Types: 
          - REGIONAL 
 
  # GET on the /. MOCK json response 
  RestAPIMockGET: 
    Type: 'AWS::ApiGateway::Method' 
    Properties: 
      ApiKeyRequired: false 
      AuthorizationType: AWS_IAM 
      HttpMethod: GET 
      Integration: 
        IntegrationHttpMethod: GET 
        PassthroughBehavior: WHEN_NO_MATCH 
        Type: MOCK 
        RequestTemplates: 
          application/json: | 
              { 
                "statusCode": 200 
              } 
        IntegrationResponses: 
          - StatusCode: 200 
            ResponseParameters: 
              method.response.header.Content-Type: "'application/json'" 
            ResponseTemplates: 
              application/json: | 
                  { 
                    "message": "hello!" 
                  } 
      MethodResponses: 
        - StatusCode: 200 
          ResponseModels: 
            text/html: Empty 
          ResponseParameters: 
            method.response.header.Content-Type: true 
      ResourceId: !GetAtt RestAPI.RootResourceId 
      RestApiId: !Ref RestAPI 
    DependsOn: 
      - RestAPI 
 
  # Deploy 
  ApiDeployment: 
    Type: 'AWS::ApiGateway::Deployment' 
    Properties: 
      RestApiId: !Ref RestAPI 
      Description: sandbox deployment 
    DependsOn: 
      - RestAPIMockGET 
 
  # create stage01 
  ApiStage01: 
    Type: 'AWS::ApiGateway::Stage' 
    Properties: 
      RestApiId: !Ref RestAPI 
      DeploymentId: !Ref ApiDeployment 
      StageName: stage1 
      MethodSettings: 
        - ResourcePath: /* 
          HttpMethod: '*' 
aws-cli で、このソースコードをチェックします。

$ aws cloudformation validate-template --profile sandbox --template-body file://`pwd`/SandboxApiGateway.yaml 
{ 
    "Description": "API Gateway Sandbox",  
    "Parameters": [] 
} 
エラーが表示されなければ、aws-cli でスタックを作成します。

スタック名がAPIGatewayのAPI名になります。

$ aws cloudformation create-stack --profile sandbox --stack-name SandboxApi --template-body file://`pwd`/SandboxApiGateway.yaml 
AWSコンソールでCloudFormationの実行結果を確認します。 [状況]が CREATE_COMPLETE であればOKです。

20181122_01.png

AWSコンソールでAPI Gatewayのエンドポイント確認します。



20181122_02.png


curlコマンドでAPIを実行してみます。

認証してないのでエラーになります。

以下のようにエラーメッセージが表示されたらOKです。

$ curl -XGET https://2037kuo2d5.execute-api.ap-northeast-1.amazonaws.com/stage1/ 
{"message":"Missing Authentication Token"} 


2. COGNITOの構築


2.1. 動的マッピング用の Lambda関数を登録

COGNITOのIDプールをCloudFormationで構築しますが、

認証プロバイダの設定で、CloudFormationのカスタムリソースを使用します。

ここでは、カスタムリソースで使用するLambda関数を登録します。

CloudFormationのソースコードは以下の通り。

SandboxCognitoMapping.yaml
AWSTemplateFormatVersion: "2010-09-09" 
Description: Custom resource for cognito role mapping. 
Resources: 
  DynamicMapTransformLambda: 
    Type: AWS::Lambda::Function 
    Properties: 
      Description: Transform to generate maps with computed keys 
      Handler: index.handler 
      Role: !GetAtt LambdaExecutionRole.Arn 
      Runtime: nodejs6.10 
      Code: 
        ZipFile: !Sub | 
          const { send, SUCCESS, ERROR } = require('cfn-response'); 
          exports.handler = (event, context, callback) => { 
            console.log(JSON.stringify(event, null, 2)); 
            const { RequestType, ResourceProperties: props = { } } = event; 
            const { Entries: entries = [ ], AttributeName: attName } = props; 
 
            switch(RequestType) { 
              case 'Create': 
              case 'Update': 
                const result = { }; 
                for (let i = 0; i < entries.length; i++) { 
                  const { Key, Value } = entries[i] 
                  if (Key) { 
                    result[Key] = Value 
                  } 
                } 
                send(event, context, SUCCESS, { [attName]: result }); 
                break; 
              case 'Delete': 
                send(event, context, SUCCESS); 
                break; 
            } 
          }; 
  LambdaExecutionRole: 
    Type: AWS::IAM::Role 
    Properties: 
      AssumeRolePolicyDocument: 
        Version: '2012-10-17' 
        Statement: 
        - Effect: Allow 
          Action: "sts:AssumeRole" 
          Principal: 
            Service: lambda.amazonaws.com 
      Path: "/" 
      Policies: 
      - PolicyName: root 
        PolicyDocument: 
          Version: '2012-10-17' 
          Statement: 
          - Effect: Allow 
            Action: "logs:*" 
            Resource: "arn:aws:logs:*:*:*" 
Outputs: 
  TransformLambda: 
    Description: The CloudFormation Custom ServiceToken Function Arn 
    Value: !GetAtt DynamicMapTransformLambda.Arn 
    Export: 
      Name: TransformLambda 
aws-cli でスタックを作成します。

$ aws cloudformation create-stack --profile sandbox --stack-name SandboxCognitoMap --template-body file://`pwd`/SandboxCognitoMapping.yaml --capabilities CAPABILITY_IAM 


2.2. COGNITOのIDプール、ユーザプール構築とユーザ登録

ここでは、COGNITOのIDプール、ユーザプールを作成し、ユーザ/グループを登録します。

また、APIGatewayのAPI実行を許可するロールを作成して、グループに紐つけます。

ユーザの作成時に使用するメールアドレスは、メール受信可能なものを使用します。

あとで、仮パスワードをメールするので、仮パスワードを変更してユーザをアクティブにします。

CloudFormationのソースコードは以下の通り。

SandboxCognito.yaml
AWSTemplateFormatVersion: "2010-09-09" 
Description: "Cognito Identity Pool and User Pool." 
Resources: 
 
  # Cognito User Pool 
  UserPool: 
    Type: AWS::Cognito::UserPool 
    Properties: 
      UserPoolName: !Sub "${AWS::StackName}Users" 
      AliasAttributes: 
        - email 
      AutoVerifiedAttributes: 
        - email 
      Schema: 
        - AttributeDataType: "String" 
          Name: email 
          Required: True 
  UserPoolClient: 
    Type: AWS::Cognito::UserPoolClient 
    Properties: 
      ClientName: !Sub "${AWS::StackName}Users-client" 
      GenerateSecret: false 
      ExplicitAuthFlows: 
        - ADMIN_NO_SRP_AUTH 
      RefreshTokenValidity: 7 
      UserPoolId: 
        Ref: UserPool 
 
  # Cognito Identity Pool 
  IdentityPool: 
    Type: AWS::Cognito::IdentityPool 
    Properties: 
      AllowUnauthenticatedIdentities: true 
      IdentityPoolName: !Sub "${AWS::StackName}Id" 
      CognitoIdentityProviders: 
      - ClientId: !Ref UserPoolClient 
        ProviderName: !GetAtt UserPool.ProviderName 
  UnauthenticatedRole: 
    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": unauthenticated 
      Path: "/" 
      Policies: 
      - PolicyName: cognito 
        PolicyDocument: 
          Version: "2012-10-17" 
          Statement: 
            - Effect: Allow 
              Action: 
                - mobileanalytics:PutEvents 
                - cognito-sync:* 
              Resource: 
                - "*" 
      - PolicyName: api 
        PolicyDocument: 
          Version: "2012-10-17" 
          Statement: 
            - Effect: Deny 
              Action: 
                - execute-api:Invoke 
              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 
      Path: "/" 
      Policies: 
        - PolicyName: cognito 
          PolicyDocument: 
            Version: "2012-10-17" 
            Statement: 
              - Effect: Allow 
                Action: 
                  - mobileanalytics:PutEvents 
                  - cognito-sync:* 
                  - cognito-identity:* 
                Resource: 
                  - "*" 
  IdentityPoolRoleAttachmentMapping: 
    Type: Custom::DynamicMapTransform 
    Properties: 
      ServiceToken: !ImportValue TransformLambda 
      AttributeName: RoleMappings 
      Entries: 
        - Key: !Sub ${UserPool.ProviderName}:${UserPoolClient} 
          Value: 
            Type: Token 
            AmbiguousRoleResolution: Deny 
  RoleAttachment: 
    Type: AWS::Cognito::IdentityPoolRoleAttachment 
    Properties: 
      IdentityPoolId: !Ref IdentityPool 
      Roles: 
        unauthenticated: !GetAtt UnauthenticatedRole.Arn 
        authenticated: !GetAtt AuthenticatedRole.Arn 
      RoleMappings: !GetAtt IdentityPoolRoleAttachmentMapping.RoleMappings 
 
  # Cognito User / Group 
  UserPoolGroup: 
    Type: AWS::Cognito::UserPoolGroup 
    Properties: 
      GroupName: exgroup 
      RoleArn: !GetAtt GroupRole.Arn 
      UserPoolId: !Ref UserPool 
      Precedence: 0 
  UserPoolUser: 
    Type: AWS::Cognito::UserPoolUser 
    Properties: 
      DesiredDeliveryMediums:  
        - EMAIL 
      UserAttributes:  
        - Name: email 
          Value: loco-shiroma@example.com 
        - Name: email_verified 
          Value: true 
      MessageAction: SUPPRESS 
      Username: exuser 
      UserPoolId: !Ref UserPool 
  UserGroupAttach: 
    Type: AWS::Cognito::UserPoolUserToGroupAttachment 
    Properties: 
      GroupName: exgroup 
      Username: exuser 
      UserPoolId: !Ref UserPool 
    DependsOn: 
      - UserPoolGroup 
      - UserPoolUser 
  GroupRole: 
    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 
      Path: "/" 
      Policies: 
        - PolicyName: api 
          PolicyDocument: 
            Version: "2012-10-17" 
            Statement: 
            - Effect: Allow 
              Action: 
                - execute-api:Invoke 
                - execute-api:InvalidateCache 
              Resource: 
                - "*" 
aws-cliでスタックを作成します。

$ aws cloudformation create-stack --profile sandbox --stack-name SandboxCognito --template-body file://`pwd`/SandboxCognito.yaml --capabilities CAPABILITY_IAM 
AWSコンソールを開いて、API実行に必要な値を確認してメモしておきます。

まず、IDプールのIDを確認します。



20181127-02.png


ユーザプールのIDを確認します。



20181127-03.png


アプリクライアントのIDを確認します。



20181127-04.png



2.3 仮パスワードの変更

上記2.2でユーザが登録されますが、下図のようにステータスが、FORCE_CHANGE_PASSWORDと表示されます。



20181127-01.png


このままでは、ユーザを使用できないので、パスワードを変更します。

まず、ユーザプールのIDを指定して、 以下のように aws-cli を実行して仮パスワードをメールします。

$ aws cognito-idp admin-create-user --user-pool-id ${uid} --username exuser --message-action RESEND --profile sandbox 
{ 
    "User": { 
        "Username": "exuser",  
        "Enabled": true,  
        "UserStatus": "FORCE_CHANGE_PASSWORD",  
        "UserCreateDate": 1543298193.167,  
        "UserLastModifiedDate": 1543300350.554,  
        "Attributes": [ 
            { 
                "Name": "sub",  
                "Value": "e105d2dc-4f76-4ad1-99e0-5d55be36986a" 
            },  
            { 
                "Name": "email_verified",  
                "Value": "true" 
            },  
            { 
                "Name": "email",  
                "Value": "loco-shiroma@example.com" 
            } 
        ] 
    } 
} 
下図のようにメールが届きます。

ピリオドは、パスワードに含みません。



スクリーンショット 2018-11-27 15.34.18.png


メールでもらったパスワードでログインします。

$ aws cognito-idp admin-initiate-auth --user-pool-id ${uid} --client-id ${cid} --auth-flow ADMIN_NO_SRP_AUTH --auth-parameters "USERNAME=exuser,PASSWORD=${pwd}" --profile sandbox 
{ 
    "ChallengeName": "NEW_PASSWORD_REQUIRED",  
    "ChallengeParameters": { 
        "USER_ID_FOR_SRP": "exuser",  
        "requiredAttributes": "[]",  
        "userAttributes": "{\"email_verified\":\"true\",\"email\":\"loco-shiroma@example.com\"}" 
    },  
    "Session": "jOaPpSiBKzxV0UU8qtkgGCscprHzrerFFefuugP7km_jvYrZpgidrF5H1GxyHfhKj3pROwGxFlt2fzlQjhfvomKyUW-Sy-Q1LvY8gyW2UkDRN1CaPap_Kkh7wGVa_PeXNlp1uAhDqc0Jro-Ga3c5Hucruvkp5oZKt30c3iIyULwTNdBL619HEUWQhFACjkxn1NZSLQUI_dhszdB_M4bCG-7BaRDBcD1ZQazmONtWuMDjReK1vg_HVVWiXMRs-0ZKva_hdKt7NwJyCBysUAjS3LxSHNOFywfhJ4XWMLuU7oq0w7_7Z1U1_sEhDLJzwFLKe-PIG9ihFJkkf-UVvFUQG2EElewFY9xmuRNySjQQ-gHgB2J80gAK8n6EyCluT8TTLfPfeC-Vpe1XGTOMYbv9GLvl8CBlrVvIBfhKuZp-5fA4AQZcnns75oi69Qgwxw6rRdq2T-cweYaXHMi3Z7c8flf6DAurCRKEdhed2YQ6BI0m4GDr_qFa0Mdb9V5Zi9tsiVg9y7qX3N05GIV2c_OIby_SqETHWRRqXaNiJGTRgxCYdd-1jkt5VUz8DVqgtQEJTH04tFH6d-tagtScBaP5ERB1Bkfs0GXobRSHP7PhaFG7EgShqpZ1Eq_jMeJywqIIlH8HLcaBpcCITKMU-_QUY-fghrvQ4QLVO17-MlquTvfJL58XBc-KUaZju1RJPYtVNgxtbJhPUEz7CVJVnda19_-FUibf93fLV6klLoZr-AozPyti40UDCcPOX-ArZi6f2HRBjGZ3mDsbkQm495FuHPzbEsIMMlDdivJKy-MBxrc6BfvxeAcXaE6_bPDlcclvet5zxpXQ2n5FB2FrWNEQKQ" 
} 
上記コマンドで表示された Sessionの値を使用してパスワードを変更します。

$ aws cognito-idp admin-respond-to-auth-challenge --user-pool-id ${uid} --client-id ${cid} --challenge-name NEW_PASSWORD_REQUIRED --challenge-responses NEW_PASSWORD='Passw0rd!',USERNAME=exuser --session "jOaPpSiBKzxV0UU8qtkgGCscprHzrerFFefuugP7km_jvYrZpgidrF5H1GxyHfhKj3pROwGxFlt2fzlQjhfvomKyUW-Sy-Q1LvY8gyW2UkDRN1CaPap_Kkh7wGVa_PeXNlp1uAhDqc0Jro-Ga3c5Hucruvkp5oZKt30c3iIyULwTNdBL619HEUWQhFACjkxn1NZSLQUI_dhszdB_M4bCG-7BaRDBcD1ZQazmONtWuMDjReK1vg_HVVWiXMRs-0ZKva_hdKt7NwJyCBysUAjS3LxSHNOFywfhJ4XWMLuU7oq0w7_7Z1U1_sEhDLJzwFLKe-PIG9ihFJkkf-UVvFUQG2EElewFY9xmuRNySjQQ-gHgB2J80gAK8n6EyCluT8TTLfPfeC-Vpe1XGTOMYbv9GLvl8CBlrVvIBfhKuZp-5fA4AQZcnns75oi69Qgwxw6rRdq2T-cweYaXHMi3Z7c8flf6DAurCRKEdhed2YQ6BI0m4GDr_qFa0Mdb9V5Zi9tsiVg9y7qX3N05GIV2c_OIby_SqETHWRRqXaNiJGTRgxCYdd-1jkt5VUz8DVqgtQEJTH04tFH6d-tagtScBaP5ERB1Bkfs0GXobRSHP7PhaFG7EgShqpZ1Eq_jMeJywqIIlH8HLcaBpcCITKMU-_QUY-fghrvQ4QLVO17-MlquTvfJL58XBc-KUaZju1RJPYtVNgxtbJhPUEz7CVJVnda19_-FUibf93fLV6klLoZr-AozPyti40UDCcPOX-ArZi6f2HRBjGZ3mDsbkQm495FuHPzbEsIMMlDdivJKy-MBxrc6BfvxeAcXaE6_bPDlcclvet5zxpXQ2n5FB2FrWNEQKQ" --profile sandbox 
{ 
    "AuthenticationResult": { 
        "ExpiresIn": 3600,  
        "IdToken": "eyJraWQiOiJnajkwencxK2VLZE53a09xNVJHNU5Ma3hic1pkNXBvSG1Db3F3bTZBcGhvPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJlMTA1ZDJkYy00Zjc2LTRhZDEtOTllMC01ZDU1YmUzNjk4NmEiLCJjb2duaXRvOmdyb3VwcyI6WyJleGdyb3VwIl0sImVtYWlsX3ZlcmlmaWVkIjp0cnVlLCJjb2duaXRvOnByZWZlcnJlZF9yb2xlIjoiYXJuOmF3czppYW06OjM1MzYzNjUxNzQxNzpyb2xlXC9TYW5kYm94Q29nbml0by1Hcm91cFJvbGUtMUlEMDBIQkZURVgwQSIsImlzcyI6Imh0dHBzOlwvXC9jb2duaXRvLWlkcC5hcC1ub3J0aGVhc3QtMS5hbWF6b25hd3MuY29tXC9hcC1ub3J0aGVhc3QtMV9BdFJzTUZUcTAiLCJjb2duaXRvOnVzZXJuYW1lIjoiZXh1c2VyIiwiY29nbml0bzpyb2xlcyI6WyJhcm46YXdzOmlhbTo6MzUzNjM2NTE3NDE3OnJvbGVcL1NhbmRib3hDb2duaXRvLUdyb3VwUm9sZS0xSUQwMEhCRlRFWDBBIl0sImF1ZCI6IjNpNjduYTU2Z3ZlaWk3cWtmMGxpa3NwdGw4IiwiZXZlbnRfaWQiOiJmZDI1ZmZmNi1mMjBlLTExZTgtODFmMC1iZmY1MjZiNTcxZmQiLCJ0b2tlbl91c2UiOiJpZCIsImF1dGhfdGltZSI6MTU0MzMwMDY4MiwiZXhwIjoxNTQzMzA0MjgyLCJpYXQiOjE1NDMzMDA2ODIsImVtYWlsIjoicy5zaGlyb21hQGxvY28tcGFydG5lcnMuY29tIn0.MPiuA6x-MnnzB55JWrZT8y1zuwWVNBxCNgLAz8NtNL6Lt_EbJVeNzjS3WgaPQhihXbeOxCSoQeoV_RGilGJblW7kfHeIyMOY3pA1Bl7uykyTI2gt8iiOvwufCjYGhU5prNAZYUbsmzkvoZDfs1QGjQi2CciRqSkxVzDxj_g3d6KFqYceUuPbjyWUXX-VswH-Kj12pQo6ns6yMjI-PC3-LjuFbMSjR9vJPOl8OzVvDSnIKxfSCNGk1K4gF4P3me8bXCarCRYol6oTRBjxbFbPip9kh7nue2lnxQcOV-MWkkqial1m9JxxaKis_2b8GJzpyR2NI8LhZPFXb5T-8DJ1Jw",  
        "RefreshToken": "eyJjdHkiOiJKV1QiLCJlbmMiOiJBMjU2R0NNIiwiYWxnIjoiUlNBLU9BRVAifQ.kgfFVsor_rztEd7KmBWDd_9VbYAG-aZ_Tk5VBX9kmXee3ih3urmNRuNfs2Hw3NYhuLXqRJngbm5NhIl1Z_-b3A6VpgNWxLo6HhGemklmbnrrqP-SXGRF_Dyfu4CnADTch57LKQzLhCy0aJLE4AS6kZo9a7PdLWGJFSkZBaz1O-PE2oRSoYELMkS9DUQsHT67sBEWI-nxXIsQXj-KCGGBmjJZ9BTdJYUb4nWS3tOGU30OMbfYeTAqHMUVJm5SI9BC-ptnRj2P6uQ1ilZz6rHo7BjPgVTMevptAaHwO9xYSeFOSU9SQeUTlVc690qPEqRNgV_SdTaolu30VPqROZkhIQ.W6RfvwSCJMGzNgmI.PidWCSwDwI1Jp8gRvPuBBFXHLeg4nWn0IIKQw-1yFlBpely_uCmcpRa5b1YE5dPDtuRlZCzcAHfYy_CBPTmS1Uui_ea7l96GmGFhfbM_lTu3vcxgCULWAZgWKopC-jk1cqCk2VY_nGekpandGq9A7Nv7aYyu89jwKxfpb_Rg8xyhfYpz3CrQc35W0CqrVVd2G0WWPyWl2XwPnKl1LF8NgzVE4xqfJlVKtS1Kqgc93huVdwqEjwZuBY6tDgpdDJtQcJDEAF_SmXO8RYPCaUoY8TAquSrSRRLlqBLlvN47iyWwLr6NpXNhJgmED8sTi9NP2kcR1Q0nH-XGsrJnEh2cZSesXTVnUOWEs0zeDGP9OuNPqrI7-aO_rlEqnQQUsLMYAJepRYOW40rd3yPEKnaZnnZCgBKOHhoXxfFDCKVHnKR9NHm-ziGuRv-3TrIr7pGNZWI-Ow4KyRZKF5wTz5vDV9ck74PR2M9JR-OOdIcHaCbDWEOm2jBJoK1hu1wFDBoG8_WO9dliEFvtkw2U4JToigadsxKm8ghnsepU0b423P0QLiab0wErAUITZpccebuLmvzZWGkQSMW8o9SERxgXLpNPIEAz6e1XHfaCByEYLfNXKw9TVBeEOQOWVX3wR6eYUSRGtspVSmKFrmGvPARGkiuojmqjy-pvZx7TczVwh0FAHtLWjyxX3wFfRiEaj00zwYncAZluGR2vPqEcW4t20gnbNk65ZQbJkxc4TRYvz5pKThtXPA68xQJ83RNv_542yXBdV_cMnj_NIW4gqTVHfKrjhDINgr4PoeHME_PByrFm2dwNAiTXolCYkw5R4pfKZKdcGo161B3PpdM43B80_r2HtPa92hfVvKtTvOVPVqG7jVZZqOhx-wjSM4jhme6TMK8MF6huZ1W4GKNe2CqeGcsGAxcS1bT-vlJKQgjPw3kxzMY2p4O157teLzbY3pd2lBmNOESDcMiI1r2DZByekeW6wYh813lv9TEYrRIctUB4mJsmrDlHQ3KIyIxjJGwqJ3OQ2AqXztEExz5aAfovfCcLnFlTDFMVE7Lamu10h_8Zmn-42lU4Rxj49xyQ8xdS8GvLHzCVIsR7Rkp5nKDaMe-9d9oDGPmPD1a7QVr4z2EBoLCH2NidUvkxgxVgjOovc_-wOKOlC_cUmocpK4WrbsXrkxe8iz6EbOqVTUHvfYA0UlXTQdw2TVx68EN6Ts5yMtlzlcWPq9TePR-xtOwP35MQtvHTs-vrQMurDYN2StGy_rlNli8G2Wi0wKG9R9hkiiSXEmVrhRTGJi-zpIu4rG0.pB5sY6GN0fUMJsFLEIuEWQ",  
        "TokenType": "Bearer",  
        "AccessToken": "eyJraWQiOiJIeHJhTTlvdThuMHdPakxtb0FDM3F5ZWowNFNKbyt6UEk4bXN3Qmt1enRnPSIsImFsZyI6IlJTMjU2In0.eyJzdWIiOiJlMTA1ZDJkYy00Zjc2LTRhZDEtOTllMC01ZDU1YmUzNjk4NmEiLCJjb2duaXRvOmdyb3VwcyI6WyJleGdyb3VwIl0sImV2ZW50X2lkIjoiZmQyNWZmZjYtZjIwZS0xMWU4LTgxZjAtYmZmNTI2YjU3MWZkIiwidG9rZW5fdXNlIjoiYWNjZXNzIiwic2NvcGUiOiJhd3MuY29nbml0by5zaWduaW4udXNlci5hZG1pbiIsImF1dGhfdGltZSI6MTU0MzMwMDY4MiwiaXNzIjoiaHR0cHM6XC9cL2NvZ25pdG8taWRwLmFwLW5vcnRoZWFzdC0xLmFtYXpvbmF3cy5jb21cL2FwLW5vcnRoZWFzdC0xX0F0UnNNRlRxMCIsImV4cCI6MTU0MzMwNDI4MiwiaWF0IjoxNTQzMzAwNjgyLCJqdGkiOiI4NDFlYTRiMS00MTJmLTQyMWMtODVhZi1kY2M3N2E4MWZiZjkiLCJjbGllbnRfaWQiOiIzaTY3bmE1Nmd2ZWlpN3FrZjBsaWtzcHRsOCIsInVzZXJuYW1lIjoiZXh1c2VyIn0.NoY2xt4Eed8OtwsASIM8wBUHk1BEOsMf1nh0lbo68Vz0MGigYe5m-y9bl8rrdyYFkVdnnbQeCsx8V3kHLfaFI70FnYy42lyu6Nwq48tiheRKyraEeHR6vuf6j8J7AklsMraU9mDUTCfvgitQjhmQn2OMK1qwZaaDYkKPS9ICCh-CsHzXDaETb-wnIgtYGG7u6h0geyONdb4Yr2Y92ACYDKTo_LjG6U8xhdTZJafUWu0EyI1QPpi5BA80FtS2Gg6tt04lsrdc3jo4qZJ6dGXyvmdoMGVyjehzRtg13syi9t0twSWCVF7LB31JJKduA5cBR7vwONNSbp8Y4vw45KRM9g" 
    },  
    "ChallengeParameters": {} 
} 
AWSコンソールでユーザのステータスを確認して、CONFIRMED になっていたらOKです。



20181127-05.png



3. API動作確認


3.1 クライアントアプリケーションの用意

APIを実行するアプリケーションをPythonで作成しました。

ソースコードは以下の通り。

api_request.py
import requests 
import boto3 
from warrant.aws_srp import AWSSRP 
from requests_aws_sign import AWSV4Sign 
 
USERNAME = 'exuser' 
PASSWORD = 'Passw0rd!' 
ACCOUNT_ID = "123456789012" 
REGION = "ap-northeast-1" 
API_ENDPOINT = "https://2037kuo2d5.execute-api.ap-northeast-1.amazonaws.com/stage1" 
USER_POOL_ID = "ap-northeast-1_AtRsMFTq0" 
CLIENT_ID = "3i67na56gveii7qkf0liksptl8" 
IDENTITY_POOL_ID = "ap-northeast-1:e0794416-2b06-4abc-907e-130a4ac2b89f" 
 
def main(): 
    aws = AWSSRP(username=USERNAME, password=PASSWORD, pool_id=USER_POOL_ID, client_id=CLIENT_ID) 
    tokens = aws.authenticate_user() 
    id_token = tokens['AuthenticationResult']['IdToken'] 
 
    logins = {'cognito-idp.' + REGION + '.amazonaws.com/' + USER_POOL_ID : id_token} 
    client = boto3.client('cognito-identity', region_name=REGION) 
    cognito_identity_id = client.get_id( 
        AccountId=ACCOUNT_ID, 
        IdentityPoolId=IDENTITY_POOL_ID, 
        Logins=logins 
    ) 
    id_credentials = client.get_credentials_for_identity( 
        IdentityId=cognito_identity_id['IdentityId'], 
        Logins=logins 
    ) 
 
    session = boto3.session.Session( 
        aws_access_key_id=id_credentials['Credentials']['AccessKeyId'], 
        aws_secret_access_key=id_credentials['Credentials']['SecretKey'], 
        aws_session_token=id_credentials['Credentials']['SessionToken'], 
        region_name=REGION 
    ) 
    credentials = session.get_credentials() 
    service = 'execute-api' 
    auth = AWSV4Sign(credentials, REGION, service) 
 
    headers = {"Content-Type": "application/json"} 
    request_path = '/' 
    url = API_ENDPOINT + request_path 
    response = requests.request('GET', url, auth=auth, headers=headers) 
 
    print('GET', request_path, response.status_code) 
    print(response.headers) 
    print(response.text) 
 
    return 
 
if __name__ == '__main__': 
    main() 
AWSSRP は、 以下のようにしてインストールします。

$ pip install warrant 
AWSV4Sign は、GitHUB から取得して、 requests-aws-sign ディレクトリを上記の api_request.py と同じ場所に格納します。


3.2 API実行

APIを実行してみます。

うまくいけば、以下のように表示されます。

レスポンスステータスが200で、APIGatewayのMOCで定義したレスポンス(JSON)が表示されます。

$ python ./api_request.py 
('GET', '/', 200) 
{'x-amzn-RequestId': '895b2387-f210-11e8-a22c-8f58e6559e46', 'Content-Length': '26', 'x-amz-apigw-id': 'RAlTgH3_NjMFpFQ=', 'Connection': 'keep-alive', 'Date': 'Tue, 27 Nov 2018 06:49:07 GMT', 'Content-Type': 'application/json'} 
{ 
  "message": "hello!" 
} 

コメント

このブログの人気の投稿

投稿時間:2021-06-20 02:06:12 RSSフィード2021-06-20 02:00 分まとめ(3871件)

投稿時間:2021-04-30 23:37:32 RSSフィード2021-04-30 23:00 分まとめ(42件)

投稿時間:2023-02-05 02:09:04 RSSフィード2023-02-05 02:00 分まとめ(9件)