クラウドインテグレーションサービス「雲斗」のブログ

芝公園にある創研情報株式会社がAWS を 中心にクラウドの基本から便利な使いかたまでをお伝えしていきます。

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組だけなので「ソートキーの追加」はチェックせず、「デフォルト設定の使用」をチェックする。

1-1-dynamodb_console_create-table

テーブルが無事作成できると、概要等を確認できる。のちほどテーブルへのアクセス権設定情報として使用するため「概要」タブの一番下に表示されているAmazonリソースネーム(ARN)をメモしておく。

1-2-dynamodb_console_overview
1-3-dynamodb_console_item

前回作成したLambda FunctionへwatsonTokensテーブルへのトークン格納コードを追記する。

AWS SDK for Javaライブラリ追加

LambdaからDynamoDBへはAmazonDynamoDBClientによりアクセスする。まずはLambdaプロジェクトへライブラリを追加する。

AWS SDK for Java右上の「AWS SDK for Java >>」からファイルをダウンロードする。

2-1-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ライブラリおよび依存ライブラリを参照設定する。

2-2-eclipse_aws-java-sdk-jar

全て追加後の参照設定は以下のとおりとなる。(多い...。)

2-3-eclipse_dependencies

IAMユーザへの権限設定

DynamoDBへの書込み権限を持つユーザを作成する。作成ユーザのクレデンシャル情報をLambda Functionから利用できるよう今回はJavaコードで設定する。

ユーザ:dynamoput
アタッチするポリシー名:DynamoDB-putItemOnly
許可するアクション:dynamodb:PutItem

3-1-iam_console_users_new_step1

「次のステップ:アクセス権限」により次画面へ遷移すると、以下の1-3、いずれの方法でアクセス権限を設定するか選択できる。

  1. ユーザーをグループに追加
  2. アクセス権限を既存のユーザーからコピー
  3. 既存のポリシーを直接アタッチ

通常はグループとユーザを紐付けて管理するのだろうが、今回はシンプルに3.のユーザに対して直接ポリシーをアタッチすることとした。

画面から「既存のポリシーを直接アタッチ」を選択 > 「ポリシーの作成」ボタンクリック > Policy Generatorを選択する。

3-2-iam_console_policies_new-01

ARNに先ほどメモっておいたDynamoDBテーブルのARNを指定し、PutItemのアクションのみ許可する。

3-3-iam_console_policies_new-02

一応「ポリシーの検証」で設定に問題が無いことを確認し「ポリシーの作成」をクリックする。

3-4-iam_console_policies_new-03

アクセス権限の設定画面に戻り、作成したDynamoDB-putItemOnlyポリシーを指定する。

3-5-iam_console_users_new_step2
3-6-iam_console_users_new_step3

確認画面の「ユーザを作成」ボタンでユーザが追加される。完了画面では忘れずに「.csvのダウンロード」をクリックしてcredentials.csvをダウンロードする。

3-7-iam_console_users_new_step4
3-8-iam_console_users_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ログにより正常に実行される事を確認する。

4-1-cloudwatch_console_logeventviewer

DynamoDBのコンソールより格納データを確認する。処理が正常であればSTT/TTS用トークンで2レコードが追加される。

4-2-dynamodb_console_item

クライアントサイドJavascript

ここからクライアントサイドJavaScriptによりDynamoDBの値を取り出せる事を確認する。

IAMユーザ追加、権限設定

DynamoDBのテーブル読取り権限を持つユーザを作成する。作成したユーザのクレデンシャル情報をJavaScriptから利用できるようコードに設定する。

ユーザ:dynamoget
アタッチするポリシー名:DynamoDB-getItemOnly
許可するアクション:dynamodb:GetItem

5-1-iam_console_users_new_step1

ユーザ・ポリシー作成は書込み権限の設定と同じ流れなので以下ポイントだけあげる。ポリシー作成時のARNはputItem時と同じものを指定する。

5-2-iam_console_policies_new-02

アクセス権の設定画面より作成したポリシーを指定し、ユーザを作成する。「.csvのダウンロード」をクリックしてcredentials.csvをダウンロードする。

5-3-iam_console_users_new_step3

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)

6-chrome_developer_tools_console

もうお気付きの方もいらっしゃるかと思うが、このコードを一般の公開サーバへ配置した場合、世界中のどなたからもWatsonトークンを取りだせてしまう。

次回はこのDynamoDBへのアクセスコードをCognito認証により制限する方法を紹介する。

◆クラウドインテグレーションサービス「雲斗」以下のページからアクセス出来ます。

-Amazon DynamoDB, AWS IAM, AWS Lambda, 人工知能・機械学習

Bitnami