AWS Cognitoとは?

AWSが提供する認証・認可基盤です。通常は、IAMユーザーのアクセスキーや、インスタンスに対するIAMロールを使用して認証します。
なぜCognitoを使うのか?
・クライアントアプリ(SPAやスマホのネイティブアプリ)より直接AWSリソースへアクセスしたい要件が増えてきている中で、扱いに困るのがIAMユーザーのアクセスキーやシークレットキーの扱いです。
特に、SPAのようなJavaScriptを使用したアプリケーションは、容易にブラウザのデバックツールより抜き取ることが可能なため、セキュリティ上問題があります。
また、仮になんらかの方法で、ファイルを難読化したとしても、永続的に権限を付与し続けることになるため、健全な運用ではありません。
そこで、Cognitoを使用してクライアントアプリからの認証を行い、IAMロールを使用して権限を払い出す仕組みを実現しています。
Cognitoを使う理由について
Cognitoてなに?
Cognitoとは、認証、承認、およびユーザー管理機能を提供するAWS(Amazon Web Service)のサービスです。Cognitoの主な機能は、以下の通りです。
- ユーザープール
Cognitoの認証機能です。ユーザー管理、サインイン、サインアップを提供します。 - IDプール
Cognitoの認証機能です。一時的なAWS認証情報を発行することで他のAWSサービスへのアクセスを許可させることができます。IDプールはユーザープールと統合する必要があります。
Cognitoを使う3つの理由
ログイン画面作成にCognitoを利用すべき3つの理由について説明します。
- パスワードなどのユーザーデータを保持しないため、安心
ユーザー管理における重要事項は、パスワードなどの機密性の高いユーザー情報を安全に保存することです。Cognitoでユーザー管理を行うと、ユーザーデータを開発者側で保持する必要がないため、安心です。 - GoogleやFacebook、AppleなどのID・パスワードでもログイン可能
Cognitoのユーザー認証方法には、以下の2つがあります。独自の認証情報を使用しなくてもGoogleやFacebookなどサードパーティーを通じてサインインできるため、ユーザーが使いやすいログイン画面が作成できます。
・独自のID・パスワードを利用した認証
Cognitoに認証情報(ユーザーID、パスワードなど)を保存する必要があります
・外部プロパイダーを利用した認証
Cognitoに認証情報を保存する必要はなく、Google、Facebook、Amazon、Apple経由、
または SAML / OpenID Connect 経由でログインを行います - ログイン画面の作成が簡単
AWS Amplify(以下、Amplify)のフレームワークを利用する前提の場合、簡単にログイン画面の作成が可能です。
カスタマイズも簡単なので、用意されているフォーマットから必要ない機能を削除することも可能です。
※参考記事: ログイン画面の作成に、Amazon Cognitoを使うべき3つの理由とは?
用語について
Cognitoで使用される用語をまとめてみました。
- フェデレーティッドアイデンティティ
どのようにして、認証を行うかの設定を行います。ソーシャルIDプロバイダー(FB、Twitter etc)の指定や、認証後の使用可能なAWSリソースのIAMロール設定等を行います。
- ユーザプール
「フェデレーティッドアイデンティティ」で作成されたIDプールに対してユーザの紐付けを行います。その際に使用するのが、ユーザプールです。
どのアプリケーションに対して、どのような認証を行い(メール認証の有無や、MFA等)、パスワードポリシーの設定や、ユーザのアクティベーション等もあります。
どうやって使うのか
AWS SDK for JavaScriptを使用して、Cognito経由でDynamoDBへアクセスしてみます。
未認証でとりあえず使ってみる
まずは、フェデレーティッドアイデンティティを新規に作成して、未認証でも権限の払い出しをしてもらい、どんな感じになるか試します。
1. フェデレーテッドアイデンティティを作成する
- 「フェデレーテッドアイデンティティの管理」-> 「新しいIDプールの作成」
- ID プール名: 今回は、demo_cognito_unauthenticated
- 「認証されていない ID に対してアクセスを有効にする」をチェックし、「プールの作成」
- 「Your Cognito identities require access to your resources」は「許可」

2. IAMロールの編集
DynamoDBへのアクセス許可の設定を追加します。
IAMから、ロールをクリックすると、以下のようなIAMロールが作成されて
いるはずです。
oneClick_Cognito_[ID プール名]Auth_Role_XXXXXXXXXXX
oneClick_Cognito_[ID プール名]UnAuth_Role_XXXXXXXXXXX
編集するロールを選択 -> 「ポリシーの編集」で以下のようにDynamoDBの権限を追加してください。
ここでは、oneClick_Cognito_demo_cognito_unauthenticatedAuth_Role_XXXXXXXXXXX
を指定します
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"mobileanalytics:PutEvents",
"cognito-sync:*",
"cognito-identity:*"
],
"Resource": [
"*"
]
},
{ // 追加します。(コメントは追加時には削除しましょう。書式チェックで怒られます)
"Effect": "Allow",
"Action": [
"dynamodb:BatchGetItem",
"dynamodb:BatchWriteItem",
"dynamodb:DeleteItem",
"dynamodb:GetItem",
"dynamodb:PutItem",
"dynamodb:Query",
"dynamodb:Scan",
"dynamodb:UpdateItem"
],
"Resource": [
"arn:aws:dynamodb:ap-northeast-1:XXXXXXXXXXXX:table/demo_cognito_table", // DynamoDBのARNを指定
]
}
]
}
3. DynamoDBにアクセスする
「AWS SDK for JavaScript」を使用すると、IdentityId
を取得することが出来ます。こちらのIDは、SDKがよろしく保持してくれるので、こちらで管理する必要はありません。
poolIdには、「フェデレーテッドアイデンティティ」のプールIDを指定します。プールIDにはユーザプールIDもあるので、ちょっと紛らわしいですね・・
以下は、DynamoDBのテーブルからのデータ取得例です。
var aws = require('aws-sdk');
var config = {
poolId: 'ap-northeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
region: 'ap-northeast-1'
};
aws.config.region = config.region;
aws.config.credentials = new aws.CognitoIdentityCredentials(
{IdentityPoolId: config.poolId});
aws.config.credentials.get(function(err) {
if (!err) {
console.log("Cognito Identify Id: " + aws.config.credentials.identityId);
// DynamoDBへ接続
var dynamoDB = new aws.DynamoDB();
var docClient = new aws.DynamoDB.DocumentClient({service:dynamoDB});
var params = {
TableName : 'demo_cognito_table',
Key: {
'id': '1'
}
};
docClient.get(params, function(err, data) {
if (!err){
console.log(data);
} else {
console.log(err);
}
});
}
});
実行するとDynamoDBにアクセスして、データ取得できました。
$ node unauth.js
Cognito Identify Id: ap-northeast-1:xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
{ Item: { id: '1', username: 'katekichi' } }
DynamoDB周りのAPI仕様は別途ご確認ください。
未認証アクセスの用途としては、認証画面が存在しないアプリケーションで直接クライアントからAWSリソースに対してアクセスした場合等に使用することになると思います。
Cognitoユーザによる認証
ソーシャルIDプロバイダー(FB、Twitter etc)で認証することが実際の用途としては多いかなと思いますが、今回は、Cognitoの認証プロバイダを使用してみます。
Cognitoの認証プロバイダは、メールやSMSを使用したアクティベーションも可能です(アクティベーションメールのテンプレートもあります)が、諸々用意するのが大変なので、今回はnodeから直接認証のみを実施してみます(こちらを参考にさせて頂きました)。
1. Cognitoユーザーを作成
上記、記事の「2.AWS cognitoでユーザー作成」に沿って作成します。


2. フェデレーテッドアイデンティティを作成する
– 「フェデレーテッドアイデンティティの管理」-> 「新しいIDプールの作成」
– ID プール名: 今回は、demo_cognito_authenticated
– 「認証されていない ID に対してアクセスを有効にする」をチェックを外し、「プールの作成」
– 「Your Cognito identities require access to your resources」は「許可」
3. Amazon Cognito Identity SDK for JavaScriptのインストール
AWS SDK for JavaScriptと合わせて、
Amazon Cognito Identity SDK for JavaScriptを使用します。
$ npm install amazon-cognito-identity-js --save
4. DynamoDBにアクセスする
先程のDynamoDBアクセスを認証ありで行います。
var aws = require('aws-sdk');
var aws_cognito = require('amazon-cognito-identity-js');
var config = {
poolId: 'ap-northeast-1:xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx',
region: 'ap-northeast-1'
};
// ユーザープール設定
var user_pool = new aws_cognito.CognitoUserPool({
UserPoolId : 'xxxxxxxx', // 1.で作成したユーザプールID
ClientId : 'XXXXXXXXXXXXXXXXXXXX' // 1.で作成したアプリクライアント ID
});
// ユーザー決定
const cognito_user = new aws_cognito.CognitoUser({
Username: 'XXXXX', // 1.でユーザに作成したユーザ名
Pool: user_pool,
});
// パスワードの設定
const authentication_details = new aws_cognito.AuthenticationDetails({
Password: 'XXXXXX', // 1.でユーザに設定した仮パスワード
});
// ユーザープール/ユーザー/パスワードを使って認証
cognito_user.authenticateUser(authentication_details, {
// 成功時
onSuccess(result){
aws.config.region = config.region;
aws.config.credentials = new aws.CognitoIdentityCredentials(
{IdentityPoolId: config.poolId,
Logins: {
'cognito-idp.ap-northeast-1.amazonaws.com/<YOUR_USER_POOL_ID>': result.getIdToken().getJwtToken()
}
});
// DynamoDBへ接続
var dynamoDB = new aws.DynamoDB();
var docClient = new aws.DynamoDB.DocumentClient({service:dynamoDB});
var params = {
TableName : 'demo_cognito_table',
Key: {
'id': '1'
}
};
docClient.get(params, function(err, data) {
if (!err){
console.log(data);
} else {
console.log(err);
}
});
},
onFailure(err){
console.error(err);
},
// 初回認証時のパスワード変更を仮パスワードで使いまわす。
newPasswordRequired(user_attributes, required_attributes){
cognito_user.completeNewPasswordChallenge(authentication_details.password, user_attributes, this);
},
});
実行すると無認証時と同じく、DynamoDBにアクセスして、データ取得できました。
$ node auth.js
Cognito Identify Id: ap-northeast-1:xxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
{ Item: { id: '1', username: 'katekichi' } }
Cognitoで認証後に取得したトークンと、IAMからCredentialを払い出すために繋ぎ込みは分かりずらいですので、そんな時は、AWSのドキュメントを参照すれば良いと思います。
参考記事
※参考記事: ログイン画面の作成に、Amazon Cognitoを使うべき3つの理由とは?
Cognito User Pools x ログイン認証 x API認証
LambdaもAPI Gatewayも不要。AWS Amplify Frameworkを使ってブラウザ側のコードだけでWebアプリを作る。
Amazon CognitoをJavaScriptから使ってみる
Amazon CognitoのUser Groupを利用した権限管理について本気出して考えてみた。
AWS Amplify+IAMで未認証ユーザでもAppSyncを使えるようにする
AWS AmplifyでサーバレスWebアプリの構築(Cognito + API Gateway + IAM認証)
AWS Cognito IDプール(フェデレーティッドアイデンティティ)で詰まりがちな用語
- Cognitoのサインイン時に取得できる、IDトークン・アクセストークン・更新トークンを理解する
- APIGatewayのIAM認証付きのAPIをJavascriptから叩く
- Cognitoユーザープールを使ってみました
- ロールベースアクセスコントロール
- Amazon Cognito グループ、およびきめ細かなロールベースのアクセス制御