AWS Amplify

【AWS】AWS Amplify&Cognitoで認証・認可で「車輪の再発明」はやめてセキュリティ要件を一気にクリアしつつモダンなアプリ開発する方法を解説します。

投稿日: カテゴリー: AWS
Pocket

認証・認可で「車輪の再発明」はやめましょう

アプリケーション開発が容易なったのは、「質の部分」に時間をかけるためです。
以前であればただ動かすところまで開発することが大変で「質の部分」まで行き届かないことがありましたが、
現代では、ただ動くが当たり前になるほどハードルが低くなりました。
ドキュメントもレビューもなくとりあえず動くものを作っただけだと、日本の小学校で実施されるプログラムの授業の成果物よりレベルが低くなりかねません。
なんせ、先生のレビューがありドキュメントがありますから、
既存の部品の組み合わせに抵抗があり、どうしても自分で作りたがるエンジニアが一定数います。
志は素晴らしく、利用する原理を理解する意味では良いでしょう、しかし、本当にそこがあなたや所属する組織が「顧客を創造する決め手になる開発」でしょうか。
同じ機能は世界中で当たり前にあり、それらは世界中で検証され利用に耐え生き残ったプロダクトです。
独自性を出してかえって顧客の常識に逆らうことにならないでしょうか。
認証・認可は特に特別自前で実装する理由、例えば認証認可のサービスそのものを提供する場合などがない限り既存の仕組みを利用し、その動向に合わせ対応するようにしましょう。
とはいえ導入には、まず、「①Cognitoは何者で、どういう流れで何ができるかを説明し」、次に「②どんな要件を満たし、どんな点で有用かを示し」、最後に「③実装手段を明確化する」必要があります。
③の実装手段ではAWS Amplifyを用いたCognitoを利用したアプリケーションの開発の流れを紹介したいと思います。
ということで、実装からみたい方はこちらから飛んでください。

①Cognitoは何者で、どういう流れで何ができるか

Amazon Cognito User Pool(ユーザープール)とAmazon Cognito Identity Pool(IDプール)の違いを理解しましょう

Amazon CognitoはAmazon Cognito User Pool、Amazon Cognito Identity Pool、Cognito Syncの3つのサービスを取りまとめたものであることは、以前の投稿で説明させていただきました。

Amazon Cognito User Pool(ユーザープール)

認証を扱うサービスで、トークンを発行しAPI Gatewayなどの各種AWSサービスへアクセス可能にします。

Amazon Cognito Identity Pool(IDプール)

認可を扱うサービスで、Twitter, GoogleなどIDPの指定を柔軟に行えます。
・他要素認証(MFA)などのセキュリティ機能
・漏洩した認証情報のチェック
・アカウント乗っ取り保護

Amazon Cognito User Pool(ユーザープール)とAmazon Cognito Identity Pool(IDプール)の組み合わせの流れを確認しましょう

IDプールのIDPにユーザープールを指定可能なことを利用すると以下の流れでAWSサービスを利用した認証・認可を実現できます。

①ユーザープールへサインイン、ユーザープールトークンを取得
②IDプールでユーザープールトークンとIDプールトークンを交換
③AWS各種サービスにIDプールトークン付きのリクエストでアクセス

②どんな要件を満たし、どんな点で有用かを示し

>Sign In with Appleをはじめとする各種認証方法への対応

Amazon Cognito User Poolsはgoogle,twitter,facebookに加え昨年突如、自社以外のログイン方法を提供する場合に必須になったSign In with Appleに対応しました(Apple Developerでの設定が必要)
Firebaseが対応しているGitHubやPlayゲームログインには対応していません。一方、OpenID ConnectやSAMLはFirebaseに比べアドバンテージになります。
Amazon Cognitoは多要素認証 (MFA)へも対応しています。

コンプライアンスプログラムのサポート状況

ISO 9001、ISO/IEC 27001、ISO/IEC 27017、ISO/IEC 27018、PCI DSS、HIPAA、SOCに対応しています。現状IDaaSの中では最も準拠率は高いのではないでしょうか。

ログの取得・追跡性の問題

ログイン試行やパスワード変更に関してはCloudTrailを有効にしていれば取得可能です。しかし、認証ログとういうのは識別が正しかったかを検証した結果が重要となるためlambdaを連携し結果を外に出す必要があります。これに伴いアカウントブロックなどの取得も可能になります。
しかし、ログアウトのログは現状は取れません。ログアウトのログについてエンドポイントは決まっているためログアウト試行までは取れます。今後追加される公算は高いですが、セッションを十分に短くするか他の機構で担保するかもし要件にある場合は工夫が必要になります。
トリガーが設定可能なタイミングは以下の通りです。
サインアップ前:このトリガーは、ユーザーがサインアップのための情報を送信すると呼び出されます。
認証前:ユーザーが認証のための情報を送信すると呼び出され、サインインのリクエストを承諾または拒否するカスタム検証を実行できるようにします。
カスタムメッセージ:MFA メッセージの送信前に呼び出されます。名前のイメージと違う気がします(主観)
確認後:ユーザーの確認後に呼び出されます。
認証チャレンジの作成:カスタムチャレンジが指定されている場合に、[認証チャレンジの定義] の後で呼び出されます。
認証後:ユーザーの認証後に呼び出されます。
認証チャレンジの定義:カスタム認証フローを開始するために呼び出されます。
認証チャレンジレスポンスの確認:カスタム認証チャレンジに対するエンドユーザーからのレスポンスが有効かどうかを確認するために呼び出されます。
ユーザーの移行:サインインまたはパスワードリマインダー実施のオペレーション中に呼び出され、ユーザーを既存のディレクトリからこのユーザープールに移行します。
トークン生成前:トークンの生成前に呼び出され、ID トークンのクレームをカスタマイズできるようにします。

GET https://mydomain.auth.us-east-1.amazoncognito.com/logout? client_id=ad398u21ijw3s9w3939& logout_uri=com.myclientapp://myclient/logout

アカウントロックやパスワード漏洩時の要件などをアドバンスドセキュリティ機能で対応する

Cognitoにある「アドバンスドセキュリティ」を活用することでアカウントロックやパスワード漏洩時の要件などに対応ができます。
ただし、Cognitoの「アドバンスドセキュリティ機能」を有効にすると、Cognitoの料金に加え、月間アクティブユーザー(MAU)に対して追加料金が発生する点には注意が必要です。
「侵害された資格情報の保護」
流出したID・パスワードリストを利用したCredential Stuffing Attackなどに対抗するため、他のWebサイトなどで漏洩した資格情報(ユーザー名とパスワードのペア)を再利用できないようにする機能が「侵害された資格情報の保護」です。「許可」または「ブロック使用」が選択できますが、どちらの場合でもでも、侵害された認証情報を使おうとするすべてのログイン試行がCloudWatchに記録されます。
「サインアップ」「サインイン」「パスワード変更」のチェックを付けた対象が監視対象になります。コンプライアンスプログラム関連の要件の場合は、全チェックしましょう。

リスクベースの適応認証
アカウントが攻撃者に何らかの侵害を受けている疑いがある際にユーザをどのように保護するかをここで設定できます。みなさんは以下の文面のメールは見覚えないでしょうか。

件名:新しいサインイン試行
次の情報を使用した、お客様のアカウントでの認識できないサインインを検出しました。
時間: {login-time}
デバイス: {device-name}
場所: {city}、{country}
このサインインは他のユーザーにより行われたものである場合は、パスワードを変更し、次のリンク先をクリックしてお知らせください。 {one-click-link-invalid}
このサインインがご自分によるものである場合は、 {one-click-link-valid} を使用してお知らせください

「IPアドレス指定による許可・ブロック」
「常に許可」のIPと「常にブロック」のIPをプレフィックス表記で設定できます。
ユーザーイベント履歴の表示
Cognitoコンソールの「ユーザーとグループ」のユーザをクリックした際に、ユーザーのサインイン履歴の詳細などを確認出来るようになります。
アドバンスドセキュリティのメトリクスの表示
アドバンスドセキュリティ機能のメトリクスをCloudWatchに出せるようになります。特に漏洩した認証情報が検出されたリクエスト(CompromisedCredentialsRisk)とアカウントの乗っ取りリスクを検出されたリクエスト(AccountTakeOverRisk)がログから確認出来るようなる点が大きいです。

ユーザの移管の問題

既存のユーザーを Amazon Cognito ユーザープールに移行できます。 CSV インポートと Lambda を利用したマイグレーションの2種類の方法が提供されています。
ただしパスワードは移動できないため、CSVインポートの場合はパスワードリセットフローが必要になります。もちろんユーザ離れが危惧されるため可能な限り負担を減らすフローに配慮する必要があります。Lambda を利用した方法では、Cognitoの初回ログインまたはパスワード忘れのフローに入った場合をトリガーに、予め定義したLambda関数を起動して既存の認証システムからデータを取得する方法が公式にも紹介されています。

③実装手段を明確化する-AWS Amplifyを用いたCognitoの導入

AWS Amplifyは様々なAWSサービスをまとめたもの

主な繋がっているサービス郡(コマンドベース)は以下の通りたくさんあります。
AWS Cognito (認証)
AWS AppSync (APIの追加)
Amazon Pinpoint
Amazon API Gateway
Amazon Kinesis
Amazon Persinalize
Amazon S3
Amazon CloudFront

 

AWS Amplifyを用いたCognitoの導入(Cloud9編)

Cloud9環境のセットアップ

AWS Cloud9自体は無料で利用できるIDE(統合開発環境)です。課金対象は利用しているEC2 instanceに依存します。
AWSマネージメントコンソールにてサービスを検索するから「Cloud9」を検索します。
右側のNew AWS Cloud9 environmentの下にある「Create environment」ボタンを押下します。
Name environmentではnameとdescriptionを入力して「Next Step」ボタンを押下します。
「Instance Type」にてt2.small以上に変更します。そして「Next step」を押下します。
Cloud9setup
Review画面で内容を確認したら「Create Environment」を押下します。少し時間が経つと画面が触れるようになり設定完了です。

まずやるべきことはAWS 管理の一時認証情報 の無効化です。雲に「9」が書かれたアイコンにカーソルを持っていくと「Preferences」が出てくるので、左ペインのAWS Settingsを選択します。
AWS managed temporary credentials:をOFF(赤)にします。(下の画像はデフォルトのON(緑)の状態)
AWS Settings

Vueアプリケーションのセットアップ

設定は終わったのでターミナル部分「~/environment $」でVue アプリケーションを作成します。

~/environment $ node -v
v10.21.0
~/environment $ npm -v
6.14.4
~/environment $ npm install -g @vue/cli
~ ~
:~/environment $ vue create amplifytestproject

ここまでうまくいくと下のような質問が出てきますので、上下キーで移動させて「Manually select features」を選択しEnterを押下します。

デフォルトでは「上」のdefault (babel, eslint)が選択されています。

? Please pick a preset: (Use arrow keys)
❯default (babel, eslint)
 Manually select features

そこで、下キーを押して「>」を「Manually select features」に移動させてEnterを押下します。

? Please pick a preset: (Use arrow keys)
default (babel, eslint)
❯ Manually select features

続いて、「Router」の項目まで上下キーで移動して「Shift」を押しながら「スペースキー」でON(黒丸)にします。

? Check the features needed for your project: (Press <space> to select, <a> to toggle all, <i> to invert selection)
◉ Babel
◯ TypeScript
◯ Progressive Web App (PWA) Support
❯◉Router
◯ Vuex
◯ CSS Pre-processors
◉ Linter / Formatter
◯ Unit Testing
◯ E2E Testing

あとは変更なしなのでYとかEnterで進めてプロジェクトを作成します。

? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, Router, Linter
? Use history mode for router? (Requires proper server setup for index fallback in production) Yes
? Pick a linter / formatter config: Basic
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? (y/N) y

?Save preset as: amplifytestpresetとプリセット名を入れてEnterを押下するとプロジェクトが作成されます。少々時間がかかります。

完了すると「Get started with the following commands:」のように出てくるのですが、このまま実行できないので以下の順で実行してください。

$ cd amplifytestproject
$ echo "module.exports = {devServer: {disableHostCheck: true}}" > vue.config.js
$ npm run serve

早速、立ち上がっているアプリケーションをみたいと思いますので、上部グローバルメニューにある「PreView」(ちょっと離れた位置にある)を選択し「Preview Running Application」を選びます。
Preview Running Application
するとVueの初期画面が立ち上がっていることが確認できます。
Preview Running Application2
確認できましたら、一旦サーバプロセスをcontrol+Cで止めて以下のコマンドを実行しUIコンポーネントを導入します。

$ npm install vue-material element-ui --save

ここでamplifyの導入コマンドを実行します。

$ npm install -g @aws-amplify/cli

完了し、プロンプトが返ってきたらバージョン確認を行いましょう。

$ amplify --version
$ amplify configure
Follow these steps to set up access to your AWS account:

Sign in to your AWS administrator account:
https://console.aws.amazon.com/
Press Enter to continue

URLの部分にカーソルを持っていくと「Copy」が選択できるのでマネージメントコンソールにログインした後にURLを貼り付けアクセスします。

Specify the AWS Region
? region: ap-northeast-1
Specify the username of the new IAM user:
? user name: amplify-test-vue
Complete the user creation using the AWS console
https://console.aws.amazon.com/iam/home?region=undefined#/users$new?step=final&accessKey&userNames=amplify-test-vue&permissionType=policies&policies=arn:aws:iam::aws:policy%2FAdministratorAccess
Press Enter to continue

IAMの作成画面では何もいじることなく次へ次へ「ユーザの作成」まで行います。作成完了画面の情報は利用するので閉じないで下さい。

Enter the access key of the newly created user:
? accessKeyId: (追加したユーザのアクセスキー)
? secretAccessKey: (追加したユーザのシークレットキー)
This would update/create the AWS Profile in your local machine
? Profile Name: amplify-test-vue

次に

$ amplify init

Choose your default editor: Vim (via Terminal, Mac OS only)以外は特に選択肢を変えずにEnterしていきます。

? Enter a name for the project amplifytestproject
? Enter a name for the environment test
? Choose your default editor: Vim (via Terminal, Mac OS only)
? Choose the type of app that you're building javascript
Please tell us about your project
? What javascript framework are you using vue
? Source Directory Path: src
? Distribution Directory Path: dist
? Build Command: npm run-script build
? Start Command: npm run-script serve
Using default provider awscloudformation

? Do you want to use an AWS profile? (Y/n)YとしてEnterを押下すると候補が出てくるのでそれでよければEnterを押下します。(ここでしばし待ちます。)

完了後「amplify status」を実行し「空」だったら成功です。

Amazon Cognito User Poolの実装

ようやく「認証機能」の実装まできました。

$ npm i aws-amplify aws-amplify-vue

しばし待つと完了します。

$ amplify add auth

選択肢が表示されるので実装したいないように合わせてセットアップします。

Do you want to use the default authentication and security configuration? Default configuration
Warning: you will not be able to edit these selections.
How do you want users to be able to sign in? Email
Do you want to configure advanced settings? No, I am done.

$ amplify push
を押下すると以下のように質問されるので本当によければYでEnterを押下します。
Are you sure you want to continue? (Y/n)
少し時間がかかって反映されます。実は必要なユーザプールとフェデレーションアイデンティティの設定が全てこの間に実行されています。
(CREATE_COMPLETE UpdateRolesWithIDPFunctionRole、CREATE_COMPLETE SNSRoleなど手作業だと大変ですが・・)
src配下のmain.jsを開き以下のコードを追記しましょう。

// -------↓ここから↓-------
import ElementUI from 'element-ui';
import 'element-ui/lib/theme-chalk/index.css';
import awsconfig from './aws-exports';
import Amplify, * as AmplifyModules from 'aws-amplify';
import { AmplifyPlugin } from 'aws-amplify-vue';

Amplify.configure(awsconfig);
Vue.use(AmplifyPlugin, AmplifyModules);
// ------↑ここまで↑-----
Vue.config.productionTip = false
// -------↓ここから↓-------
Vue.use(ElementUI, { locale });
// ------↑ここまで↑-----

同じくsrc配下のApp.vueを開き<div id=”app”>の下に以下のコードを追加します。(たった1行)

<template>

    <div id="app">

<!-- -------↓ここから↓------- -->

        <amplify-authenticator />

<!-- ------↑ここまで↑----- -->

amplify serveで起動し確認してみましょう。リロードした上の方の画面にログイン画面が表示されていると思います。

login_View

メールに確認コードが届く仕様も実装されていることが確認できます。

Email

ログアウトがないので、サインイン後だったらユーザ名ととも表示させる実装を行います。

<template>
<div id="app">
<div v-if="signedIn">
<div id="nav">
<div class="amplify-sign-out">
<amplify-sign-out/>
ご利用ありがとうございます、{{username}} 様
</div>
</div>
</div>

<div v-else>
<amplify-authenticator />
</div>
</div>
</template>

<script>
import { Auth } from 'aws-amplify'
import { AmplifyEventBus } from 'aws-amplify-vue'

window.LOG_LEVEL = 'VERBOSE';

export default {
name: 'app',
data(){
return {
signedIn: false,
username: ''
}
},
async beforeCreate() {

try {
let cognitoUser = await Auth.currentAuthenticatedUser()
this.signedIn = true
this.username = cognitoUser.username
} catch (err) {
this.signedIn = false
}

AmplifyEventBus.$on('authState', async info => {
if (info === 'signedIn') {
let cognitoUser = await Auth.currentAuthenticatedUser()
this.signedIn = true
this.username = cognitoUser.username
} else {
this.signedIn = false
}
});
}
};
</script>

<style src="./assets/style.css" />

ログインするとユーザ名が表示されたと思います。これで最低限の認証・認可が実装できました。Amazon S3 でホスティングの形式で

amplify add hosting

? Select the plugin module to execute Amazon CloudFront and S3
? Select the environment setup:
DEV (S3 only with HTTP)
❯ PROD (S3 with CloudFront using HTTPS)

hosting bucket nameはいい感じに適当に決めてくれますので、こだわりがなければそのままEnterを押下します。

$ amplify publish

? Are you sure you want to continue? (Y/n)Y

公開が終了したらコンソールにamplify statusのコマンドでアクセスURLを確認します。Domainの欄を確認します。

$ amplify status

~~

Amplify hosting urls:
┌──────────────┬───────────────────────────────────────────┐
│ FrontEnd Env │ Domain │
├──────────────┼───────────────────────────────────────────┤
│ test │ https://test.doa91vup2ayf0.amplifyapp.com │

Amazon Cognito Login

AWS Amplifyを用いたCognitoの導入(ローカル編)

Amplify CLIのインストールにはNode.js 10.x以上、npm 5.x以上が必要です。バージョンを確認しましょう。

> node -v
> npm -v

インストールした後にはバージョンを確認しましょう。

> npm install -g @aws-amplify/cli
> amplify --version

設定を行うため、コンソールのログインを行ってから以下のコマンドを実行します。

> amplify configure
?region: ap-northeast-1
?user name:amplify-test
Complete the user creation using the AWS console
https://console.aws.amazon.com/iam/home?region=undefined#/users$new?step=final&accessKey&userNames=amplify-test&permissionType=policies&policies=arn:aws:iam::aws:policy%2FAdministratorAccess
Press Enter to continue

IAMユーザーの追加ページが表示されるので、ユーザ名などは勝手に入っているのでそのまま次へ次へでユーザを作成します。作成が終わったらEnterを押下します。
追加したIAMユーザーの情報を入力し新しいプロファイルを作成します。(プロファイル名はユーザー名と同じにしています。)

Enter the access key of the newly created user:
? accessKeyId: (追加したユーザのアクセスキー)
? secretAccessKey: (追加したユーザのシークレットキー)
This would update/create the AWS Profile in your local machine
? Profile Name: amplify-test

ここでEnterを押下します。

Successfully set up the new user.

本当に作成できているか確認しましょう(AWS CLIの導入はこちら)

>aws configure list --profile amplify-test

ここでユーザ名諸々が返ってくればユーザ設定までは完了しました。
ここまでWebアプリとスマートフォンアプリの共通手順です。

スマートフォンアプリの手順(Android:途中)

Androidプロジェクトのディレクトリに移動してから

> amplify init
name for the project AmplifyTest
name for the envirnment dev
Choose the type of app that you're building android
Where is your Res directory: app/src/main/res

少ししてAWSプロファイルを使用するかと出てくるのでYesとして先に作ったユーザを選択すると作成が進みます。
AWS Management Consoleからも確認できます。

Amazon CognitoでAuthを追加する(Manual configurationは独自ログインを作成している場合)
まずはUserpoolの作成

>amplify add auth
>Default configuration
How do you want user to be able to sign in? Email
Do you want to configure advanced settingss? No I am done
>amplify push

コマンドを実行すると./app/src/main/res/raw にawsconfiguration.jsonが追加されたことを確認しましょう。

続きは確認出来次第追記します。

以上です。参考になりましたら幸いです。