AWS Cognito(5)スロットリング

スロットリングとは

AWSは各サービスにサービス制限(スロットリングを行っており、各アカウントごとに使えるリソースの上限が設定されている。例えば、EC2は初期状態では最大20台までしかインスタンスを起動できない設定となっている。フルマネージドのサービスに対してもこれらの制限が設定されており、「フルマネージド」という名称でありながら負荷に合わせて際限なくスケールするわけではない。また、サービスによっては、サービス制限一覧にこの上限値が明記されていないものもある。

上限値以上にリソースを使用する場合はサポートプランに加入の上、サポートに必要なリソース数とその理由を付けて上限値の引き上げや撤廃を申請する必要がある。上限値の変更が必要な理由が不明確であったり必要以上のリソースを要求すると、要望が叶えられないこともあるので注意が必要である。理由を明確にした上で申請する必要がある。

なお基本的にAWSのマネージドサービスは、「定常的な利用」や「一時的なサービスを簡単に作成するため」に提供するシステムであるという考え方のようで、バースト的なアクセスや複雑な処理、定常的に大きな負荷が掛かる処理については、EC2上にシステムを構築して利用すべきであるというのがAmazonの方針のようである。大きな負荷の掛かる処理の場合は、上限引き上げ申請するだけでなく、EC2を用いて実現できないかについても検討すべきであろう。

Cognitoのスロットリング

AWSのサービスは日々拡張されていっているので、スロットリングの値は随時変更されている可能性がある。その前提のもと現時点で、

  • Cognito Identity: 数百/毎秒程度
  • Cognito Sync : 数千/毎秒程度

でスロットリングされており、それ以上の負荷が掛かる可能性があったりそれ以上のリソースを必要とする場合は、サポートに上限引き上げの申請を行う必要があるようだ。また、申請を行ったとしても標準値の数倍程度までしか拡張できないようである。Cognitoは昨年の9月に東京リージョンにきたばかりのサービスであるので、用意されているリソースにも限りがあるのかもしれない。今後のリソース拡張に期待したい。

AWS Cognito(4)Cognitoストリーム

Cognitoストリームとは

Cognito Datasetに蓄積されたデータを取得するためには、Cognitoストリームを設定してKinesis経由でデータを出力する必要がある。Cognitoストリームを設定すると、Cognito Datasetに変更が生じる度にKinesisにそのデータを入力することができる。

Cognitoストリームの設定

  • Cognitoのダッシュボードから「Edit identity pool」をクリックし、Cognito Streamの項目を編集する

Cognitoストリームの設定

  • Kinesis stream名とシャード数を設定する
    — 「Create stream」をクリック
    — シャードとはKinesisの入出力処理のパイプの太さを表す

Kinesisストリームの作成

  • ロール設定を行う
    –「Create role」をクリック
    — ロール名が自動入力されるので、作成ウィザードで登録を行う

ロールの設定

  • 有効化する
    — 「StreamStatus」を「Enabled」に設定することで、Cognito Streamが有効化される
  • 設定変更を実行する
    — また、上記の設定を行った上で「Save Changes」をクリックしてもストリーム名、シャード、ロールなどがきちんと反映されていない場合があるので、反映されているか確認することが重要である

  • ユーザのロール設定と同様に、先ほど作成したロールのポリシーを確認する

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "kinesis:PutRecord"
      ],
      "Resource": [
        "arn:aws:kinesis:ap-northeast-1:172664222583:stream/STREAM_NAME"
      ]
    }
  ]
}

なお、Bulk publishをクリックすることでこれまで蓄積されたCognito DatasetをKinesisに一括で送り出すことが可能だが、24時間に1回しか実行できないことに注意が必要である。

ストリームレコード

CognitoからKinesisへは、以下のフォーマットでレコードが送信される。

{
  "identityPoolId" : "Pool Id"
  "identityId" : "Identity Id "
  "dataSetName" : "Dataset Name"
  "operation" : "(replace|remove)"
  "kinesisSyncRecords" : [
    { 
      "key" : "Key",
      "value" : "Value",
      "syncCount" : 1,
      "lastModifiedDate" : 1424801824343,
      "deviceLastModifiedDate" : 1424801824343,
      "op": "(replace|remove)"
    },
    ...
  ],
  "lastModifiedDate": 1424801824343,
  "kinesisSyncRecordsURL": "S3Url",
  "payloadType" : "(S3Url|Inline)",
  "syncCount" : 1
 }

AWS CLI経由でコマンドを入力することで、Cognitoから正常にレコード入力されているかの確認を行うことが可能である。

AWS Cognito(3)OpenID Connectとの連携

OpenID Connect Provider Identifierの登録

AWS CognitoはOpenID Connectによる認証に対応している。OpenID ConnectのIdentifierを登録することで、FacebookやGmailなどの既存のパブリックログインプロバイダに加えて利用できる。

登録方法

OpenID Connectのプロバイダの登録はCognito設定画面上ではなく、IAMで行う。IAMから「Identity Provider」をクリックすると登録画面が現れるので、新規で作成する場合は「Create Provider」をクリックする。

OpenID Connect プロバイダの登録

認証プロバイダは「SAML」と「OpenID Connect」から選択可能であるので、「OpenID Connect」を選択。

プロバイダタイプの選択

OpenID Connectによる認証を追加する場合は、「Provider URL」と「audience」の情報が必要となる。

OpenID Connectの設定

Yahoo! Japan(YConnect)との連携

ここで試しに、Yahoo! Japanが提供している認証サービス「YConnect」をCognitoに登録してみる。日本でOpenID Connectによる認証に対応している有名処はYahoo! Japanの他に、mixiやIIJなども存在するようである。

プロバイダーの設定エラー

プロバイダーの設定エラー

しかし、登録の際に問題が生じる。

YConnectのOpenID Provider Configuration DocumentのURLは、
https://auth.login.yahoo.co.jp/yconnect/v1/.well-known/openid-configuration

一方で、このOpenID Provider Configuration Document内のissuerのURLは、
https://auth.login.yahoo.co.jp

となっている。

OpenID Connect Discovery 1.0 incorporating errata set 1には、issuerのURLに.well-known/openid-configurationを付加したURLがOpenID Provider Configuration DocumentのURLとなると記述があるが、YConnectでは両者のURL間にズレが生じている。その結果として、IAMに登録する際に以下のエラーメッセージが表示されてしまう。

Please check .well-known/openid-configuration of provider: https://auth.login.yahoo.co.jp/yconnect/v1/ is valid.

ということで、YConnectのCognitoへの登録は断念。

IIJなどはきちんとCognitoに登録できるので、YConnectがOpenID Connectの仕様に準拠していないのが原因か。Cognitoの設定は、なかなか一筋縄にはいかない。

AWS Cognito(2)JavaScriptによるクライアントの実装

前回のCognitoのAWS側の設定に続いて、今回はWebコンテンツ側でCognito認証を利用する際のJavascript SDKを用いた実装方法について確認する。AWS Javascript SDKを用いたCognitoの認証はサーバ側にスクリプトを用意する必要がなく、S3などを用いて安価にWebサーバを構築することが可能である。

なお、AWSの認証情報とパブリックログインプロバイダから取得したトークンは、一定期間後に認証切れとなる。Cognitoはトークンの再取得についての機能は提供していないが、多くのパブリックログインプロバイダはリフレッシュトークンを用いたトークンの再取得をサポートしている。

Javascriptによる実装

AWS Javascript SDKを用いたCognitoの認証とデータ同期の実装は以下の通り。

  • AWS Javascript SDK のインポート
    — Cognitoを含むAWSの基本機能をサポートしている
    https://sdk.amazonaws.com/js/aws-sdk-2.2.6.min.jsをインポート
  • Amazon Cognito Sync Manager for JavaScript の取得とインポート
    — Cognito Sync(データセットの同期)処理をライブラリで提供している
    Github からライブラリファイルを取得し、配置する

    <script src="https://sdk.amazonaws.com/js/aws-sdk-2.2.6.min.js"></script>
    <script src="amazon-cognito.min.js"></script>
    

  • Credentials Objectを初期化する
    AWS.CognitoIdentityCredentialsクラス を利用する
    — オブジェクト初期化には、Cognito Identity Pool IDとパブリックログインプロバイダのトークンを用いる

    // Cognito認証を行う
    // 
    // @param {String} provider provider name
    // @param {String} token token
    // @param {Object} data data
    function getIdentityId(provider, token, data){
    
    		var logins = {};
    		// insert key of associative array in a variable
    		logins[provider] = token;
    		log("You have SUCCESSFULLY logged in. provider: " + provider + " token:" + token);
    		// region (tokyo)
    		AWS.config.region = 'ap-northeast-1';
    		// authentication providers
    		if(provider!=null && token!=null){
    			AWS.config.credentials = new AWS.CognitoIdentityCredentials({
        				// identity pool id
        				IdentityPoolId: 'ap-northeast-1:**********',
        				// provider name and token
        				Logins: logins // object (associative array)
    			});
    		// unauthenticated identities
    		}else{	
    			AWS.config.credentials = new AWS.CognitoIdentityCredentials({
        				IdentityPoolId: 'ap-northeast-1:**********',
    			});
    		}
    		//
    		// 以下に続く
    		//
    	}
    

  • 作成したCredentials Objectを用いて、Cognito IDを取得する
    AWS.config.credentials.get()
    — Cognito IDは、 AWS.config.credentials.identityIdで取得できる

    		AWS.config.credentials.get(function(err) {
            		if (!err) {
                			//
                			// データセット処理
                			//
            		}else{
                			log("Error Occurred: " + err);
            		}
    		});
    

  • データの保管と同期を行う( Amazon Cognito Sync Manager
    syncClient.openOrCreateDataset()
    dataset.put()
    dataset.synchronize()

    		AWS.config.credentials.get(function(err) {
            		if (!err) {
                			log("Cognito Identity Id: " + AWS.config.credentials.identityId);
    				var syncClient = new AWS.CognitoSyncManager();
    				if(data != null){
    					// open or create dataset
    					syncClient.openOrCreateDataset(provider, function(err, dataset) {
    						$.each(data, function (key, val) {
    							dataset.put(key, val, function(err, record){
                    						log("Put Dataset: { " + key + ": " + val + " }");
    							});
    						});
    						// synchronize dataset
    						dataset.synchronize({
    							onSuccess: function(data, newRecords) {	
                    						log("Syncronize Dataset: { " + provider + " }");
    							},
    							onFailure: function(err) {
                    						log("Error Occurred: " + err);
    							}
    						});
    					});
    				}else{
    					log("NOT Syncronize Dataset: no data");
    				}
    			}else{
    				log("Error Occurred: " + err);
    			}
    		});
    

Cognitoには各ユーザごとに保存領域が用意されており、各ユーザごとに複数のデータセット(テーブル)を持つことができる。ユーザデータは一旦ローカル上に保管されるため、通信状況には影響しない。ローカルに保存されたデータセットは、明示的に同期メソッドを実行した際にAWSと同期される。同期の際にデータが衝突した場合は、ローカルを優先するかAWSを優先するか選択することができる。詳細は、Amazon Cognito Sync Manager for JavaScriptに記述されている。

AWS Cognito(1)Cognitoを設定する

Cognitoとは

Facebookなどのパブリックログインプロバイダ認証を元に、AWSの認証を得ることのできるサービス。このサービスを利用することで、例えば特定のSNSアカウントに紐づけられたユーザにのみS3へのアクセスを許可するなど、AWSリソースへのアクセスを設定することができる。また、各ユーザごとにkey, Value型のデータを保存することが可能であるので、例えばゲームの設定情報やスコア情報などを、デバイス間で共有することやバックアップすることも可能である。

アプリケーションユーザーの認証

  • 対応しているパブリックログインプロバイダ
    — Facebook
    — Google
    — Amazon
    — OpenID Connect
    — Twitter
    — Gigits

  • パブリックログインプロバイダから返されるOAuth や OpenID Connect のトークンを渡すと、Cognito IDと呼ばれる一意のIDが割り振られる

  • Cognito IDによって、AWSのリソースにアクセスすることが可能となる
  • パブリックログインプロバイダ認証は自分で実装する必要がある
    — Cognitoはプロバイダ認証の結果を受けて、プロバイダのトークンの確認やCognito IDとの紐づけを行う
  • AWSリソースへのアクセス権限はIAMで指定する
  • 未認証ゲストをサポートすることもできる

アプリケーションデータの保存

  • 各ユーザのデータ(データセット)は一度ユーザーのローカルデバイスに保存され、その後 AWS クラウドと同期される
    — アプリケーションデータを同期する際は、同期メソッドを明示的に呼び出す必要がある
  • データセットの取得や解析には、Kinesisストリームを利用する

課金

  • ストア容量とデータ同期回数に基づいて課金を行う
  • 1 か月につき 10 GB の同期ストア容量と 100 万回の同期オペレーションまでは無料枠が設定されている

Cognitoの設定

1. Identity Poolを作成する

  • 「Create new identity pool」をクリックする

Create new identity poolをクリック

Identity pools – Amazon Cognito – Amazon Web Services

2. 名称とプロバイダ情報を入力する

  1. 東京リージョンを選択する
  2. identity pool名を入力する
  3. 各種プロバイダ情報を入力する
  4. 登録を実行する

名称とプロバイダ情報を入力
New identity pool

3. ユーザのロールを設定

  • ダッシュボードから「Edit identity pool」をクリック
    — ダッシュボードには、各種データが表示される

ダッシュボード

  • 「Unauthenticated role」の「Create new role」をクリック
  • 「Authenticated role」の「Create new role」をクリック

Create new role

  • ロール名が自動入力されるので、作成ウィザードで登録を行う
    — Unauthenticated role
    Unauthenticated role
    –Authenticated role
    Authenticated role

  • IAMのロール一覧を開き、先ほど作成したロールを選択する
    IAM Management Console
    IAMロール

  • 作成済みのロールポリシーを確認する

    {
        "Version": "2012-10-17",
        "Statement": [
            {
                "Effect": "Allow",
                "Action": [
                    "mobileanalytics:PutEvents",
                    "cognito-sync:*"
                ],
                "Resource": [
                    "*"
                ]
            }
        ]
    }
    

次回は、JavaScriptを用いたコンテンツ側の実装を確認する。