Amazon DynamoDB AWS IAM AWS Lambda 人工知能・機械学習
Amazon DynamoDBにクライアントサイドJSでアクセスしてみる
2017/04/21
前回の記事の続きである。
前回はAWS Lambdaで定期的にWatson STT/TTSのトークンを取得するところまで紹介した。
今回は取得したWatsonトークンをAmazon DynamoDB経由でブラウザのクライアントサイドJavaScriptから利用する方法を紹介する。
利用したサービス・API
IBM Bluemix Watson承認API
AWS Lambda、DynamoDB、CloudWatch、IAM、(S3)
事前準備
DynamoDBのConsoleよりテーブルを新規作成する。
テーブル名:watsonTokens
プライマリキー(パーティションキー):tokenType、文字列
格納するデータはキー/値が2組だけなので「ソートキーの追加」はチェックせず、「デフォルト設定の使用」をチェックする。
テーブルが無事作成できると、概要等を確認できる。のちほどテーブルへのアクセス権設定情報として使用するため「概要」タブの一番下に表示されているAmazonリソースネーム(ARN)をメモしておく。
前回作成したLambda FunctionへwatsonTokensテーブルへのトークン格納コードを追記する。
AWS SDK for Javaライブラリ追加
LambdaからDynamoDBへはAmazonDynamoDBClientによりアクセスする。まずはLambdaプロジェクトへライブラリを追加する。
AWS SDK for Java右上の「AWS SDK for Java >>」からファイルをダウンロードする。
ダウンロードしたzipファイルを一旦展開する。解凍されるのをしばし待つ...。
SDKライブラリ本体とその依存ライブラリは以下の構成となる。(バージョン1.11.65、展開フォルダからの相対パス)
lib/aws-java-sdk-1.11.65.jar
third-party/lib/aspectjrt-1.8.2.jar
third-party/lib/aspectjweaver.jar
third-party/lib/commons-codec-1.9.jar
third-party/lib/commons-logging-1.1.3.jar
third-party/lib/freemarker-2.3.9.jar
third-party/lib/httpclient-4.5.2.jar
third-party/lib/httpcore-4.4.4.jar
third-party/lib/ion-java-1.0.1.jar
third-party/lib/jackson-annotations-2.6.0.jar
third-party/lib/jackson-core-2.6.6.jar
third-party/lib/jackson-databind-2.6.6.jar
third-party/lib/jackson-dataformat-cbor-2.6.6.jar
third-party/lib/javax.mail-api-1.4.6.jar
third-party/lib/jmespath-java-1.11.65.jar
third-party/lib/joda-time-2.8.1.jar
third-party/lib/spring-beans-3.0.7.RELEASE.jar
third-party/lib/spring-context-3.0.7.RELEASE.jar
third-party/lib/spring-core-3.0.7.RELEASE.jar
third-party/lib/spring-test-3.0.7.RELEASE.jar
Eclipseで前回作成したプロジェクトを開き、上記のSDKライブラリおよび依存ライブラリを参照設定する。
全て追加後の参照設定は以下のとおりとなる。(多い...。)
IAMユーザへの権限設定
DynamoDBへの書込み権限を持つユーザを作成する。作成ユーザのクレデンシャル情報をLambda Functionから利用できるよう今回はJavaコードで設定する。
ユーザ:dynamoput
アタッチするポリシー名:DynamoDB-putItemOnly
許可するアクション:dynamodb:PutItem
「次のステップ:アクセス権限」により次画面へ遷移すると、以下の1-3、いずれの方法でアクセス権限を設定するか選択できる。
- ユーザーをグループに追加
- アクセス権限を既存のユーザーからコピー
- 既存のポリシーを直接アタッチ
通常はグループとユーザを紐付けて管理するのだろうが、今回はシンプルに3.のユーザに対して直接ポリシーをアタッチすることとした。
画面から「既存のポリシーを直接アタッチ」を選択 > 「ポリシーの作成」ボタンクリック > Policy Generatorを選択する。
ARNに先ほどメモっておいたDynamoDBテーブルのARNを指定し、PutItemのアクションのみ許可する。
一応「ポリシーの検証」で設定に問題が無いことを確認し「ポリシーの作成」をクリックする。
アクセス権限の設定画面に戻り、作成したDynamoDB-putItemOnlyポリシーを指定する。
確認画面の「ユーザを作成」ボタンでユーザが追加される。完了画面では忘れずに「.csvのダウンロード」をクリックしてcredentials.csvをダウンロードする。
csvファイルに記載されているアクセスキーID、シークレットアクセスキーをコード中の[Access key ID]、[Secret access key]部分に埋め込む。またテーブルを作成した[Region]を設定する。
LambdaLogger logger = null; // static final AWSCredentials CREDENTIALS = new BasicAWSCredentials("[Access key ID]","[Secret access key]"); static final Region TARGET_REGION = Region.getRegion(Regions.[Region]); static final String TABLE_NAME = "watsonTokens"; // AmazonDynamoDBClient dynamoDB = null; protected void _log(String input) { this.logger.log(input+"\n"); } public void putItem(String key, String value) { _log("putItem key ["+key+"] value["+value+"]"); Map<String, AttributeValue> item = new HashMap<String, AttributeValue>(); item.put("tokenType", new AttributeValue().withS(key)); item.put("data", new AttributeValue().withS(value)); PutItemRequest putItemRequest = new PutItemRequest(TABLE_NAME, item); PutItemResult putItemResult = this.dynamoDB.putItem(putItemRequest); _log("putItem Result["+putItemResult+"]"); } @Override public Object handleRequest(Object input, Context context) { this.logger = context.getLogger(); try{ Map<String, OkHttpClient> connMap = new HashMap<String, OkHttpClient>(); Map<String, UrlInfo> accMap = new HashMap<String, UrlInfo>(); accMap.put("TTStoken", new UrlInfo("https://stream.watsonplatform.net/authorization/api/v1/token?url=https%3A%2F%2Fstream.watsonplatform.net%2Ftext-to-speech%2Fapi","************************************", "************")); accMap.put("STTtoken", new UrlInfo("https://stream.watsonplatform.net/authorization/api/v1/token?url=https%3A%2F%2Fstream.watsonplatform.net%2Fspeech-to-text%2Fapi","************************************", "************")); // this.dynamoDB = new AmazonDynamoDBClient(CREDENTIALS); this.dynamoDB.setRegion(TARGET_REGION); // for(Map.Entry<String, UrlInfo> elem : accMap.entrySet()) { String key = elem.getKey(); UrlInfo urlInfo = elem.getValue(); connMap.put( key, new OkHttpClient() ); Request request = new Request.Builder() .url(urlInfo.getUrl()) .header("Authorization", Credentials.basic(urlInfo.getAccessKey(),urlInfo.getAccessSecret())) .build(); Response response = connMap.get(key).newCall(request).execute(); if (response.isSuccessful()) { String token = response.body().string(); _log("token["+token+"]"); // putItem(key, token); } else { _log("response error["+response.message()+"]"); } } } catch (Exception e){ _log(e.toString()); } return null; }
アップロード
前回と同様、Eclipse/AWSツールキットから更新コードをアップロードする。
SDK本体のjarファイルだけで約45MBもありアップロードに時間がかかる。ひたすら待つ...。
Lambda Functionの実行
こちらも前回と同様にAWSツールキットからLambda Functionを実行する。
CloudWatchログにより正常に実行される事を確認する。
DynamoDBのコンソールより格納データを確認する。処理が正常であればSTT/TTS用トークンで2レコードが追加される。
クライアントサイドJavascript
ここからクライアントサイドJavaScriptによりDynamoDBの値を取り出せる事を確認する。
IAMユーザ追加、権限設定
DynamoDBのテーブル読取り権限を持つユーザを作成する。作成したユーザのクレデンシャル情報をJavaScriptから利用できるようコードに設定する。
ユーザ:dynamoget
アタッチするポリシー名:DynamoDB-getItemOnly
許可するアクション:dynamodb:GetItem
ユーザ・ポリシー作成は書込み権限の設定と同じ流れなので以下ポイントだけあげる。ポリシー作成時のARNはputItem時と同じものを指定する。
アクセス権の設定画面より作成したポリシーを指定し、ユーザを作成する。「.csvのダウンロード」をクリックしてcredentials.csvをダウンロードする。
JavaScriptコード作成
AWS SDK for JavaScriptのとおり、ブラウザhtmlからDynamoDBへアクセスするのに必要なのは以下の1行だけである。シンプル!
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.7.13.min.js"></script>
dynamogetユーザのアクセスキーID、シークレットアクセスキーおよびDynamoDBのリージョンをコード中の[Access key ID]、[Secret access key]、[Region]に設定する。
<script src="https://sdk.amazonaws.com/js/aws-sdk-2.7.13.min.js"></script> <script type="text/javascript"> <!-- var ACCESSKEYID = "[Access key ID]"; var SECRETACCESSKEY = "[Secret access key]"; var REGION = "[Region]"; var TABLENAME = "watsonTokens"; AWS.config.update({accessKeyId: ACCESSKEYID, secretAccessKey: SECRETACCESSKEY}); var table = new AWS.DynamoDB({params: {TableName: TABLENAME}, region: REGION }); table.getItem({ Key:{ tokenType:{S:'STTtoken'}} },function(err,data){ if( err === null ){ console.log( "STTtoken [" + data.Item.data.S + "]" ); // Tokenを使用してWatson STT処理 } }); table.getItem({ Key:{ tokenType:{S:'TTStoken'}} },function(err,data){ if( err === null ){ console.log( "TTStoken [" + data.Item.data.S + "]" ); // Tokenを使用してWatson TTS処理 } }); //--> </script>
ブラウザで上記コードを実行しコンソールログを確認する。
LambdaでDynamoDBへ格納した値を出力している事がわかる。(例はChrome Developer Tools)
もうお気付きの方もいらっしゃるかと思うが、このコードを一般の公開サーバへ配置した場合、世界中のどなたからもWatsonトークンを取りだせてしまう。
次回はこのDynamoDBへのアクセスコードをCognito認証により制限する方法を紹介する。
◆クラウドインテグレーションサービス「雲斗」以下のページからアクセス出来ます。