パターン 3. WebUIからElasticsearchに検索、登録を行いたい

注意

パターン3は現在未対応です。対応につきましては、2022年以降を予定しております。

本パターンでは、WebアプリクライアントがWebUIにアクセスし、認証します。その後、Elasticsearchに検索、登録等を行うことができます。

クラウドアプリケーション内の構成は以下の通りです。

パターン03

No.

リソース名

概要

1

S3(html+js)

WebクライアントがダウンロードしてアクセスするためのUIを格納します。

2

Cognito

ログインの際の認証を行います。

3

API Gateway

Lambdaにリクエストを送信し、結果を返却します。

4

Elasticsearchアクセス

myiot-rel-es-access-lambda
My-IoTデータストアに検索、登録等を行います。

5

Elasticsearch

My-IoTデータストアです。エッジアプリから送信されたデータが蓄積されています。

CloudFormationテンプレート例

本パターンにおけるCloudFormationテンプレートを作成します。
各項目についての設定の詳細はAWSのドキュメントを参照してください。
※yml/yamlファイルの場合に、IoTストアでは!GetAttなど、短縮形の構文で組み込み関数は使用できないため、Fn::GetAttのように完全名関数の構文で記述する必要があります。

テンプレート作成する際の注意事項として以下のコメント種別で説明をします。

コメント種別

内容

+

利用目的に応じて開発者側で適切な値の設定が必要な箇所を示しています

!

My-IoTが提供する共通リソースに関する記載のため変更禁止の箇所を示しています

*

その他の補足説明を示しています

yaml形式の場合の例

AWSTemplateFormatVersion: '2010-09-09'
Description: An AWS function.
Parameters:
#************************************************************
# Parameters
# テンプレート内で使用するパラメータです
#
  BucketName:
    Description: bucket name.
    Type: String
  StageName:
    Description: stage name.
    Type: String
    Default: "dev"
  #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
  # 下記の項目は変更しないでください
  #
  # EsAccess: 
  #    Default:  Elasticsearchにアクセスする共通LambdaのArnを指定しています
  #
  EsAccess:
    Description: ESAccessLambda arn.
    Type: String
    Default: "arn:aws:lambda:ap-northeast-1:946501391975:function:myiot-rel-es-access-lambda"  
  #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#
# Parameters
#************************************************************

Resources:
#************************************************************
# S3
# No1.S3(html+js)のテンプレート例です
#
  Bucket:
    Type: "AWS::S3::Bucket"
    Properties:
      BucketName: 
        Ref: BucketName
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      # 下記の項目は作成するクラウドアプリケーションに応じて変更してください
      # 
      # AccessControl: 静的Webサイトへの適切なアクセスコントロールを設定してください
      # 
      AccessControl: PublicRead
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      WebsiteConfiguration:       
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
        # 下記の項目は作成するクラウドアプリケーションに応じて変更してください
        #  
        # IndexDocument:Webサイトで最初に表示されるファイルを記載します
        #       
        IndexDocument: top.html
        #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

  BucketPolicy:
    Type: AWS::S3::BucketPolicy
    Properties:
      PolicyDocument:
        Version: 2012-10-17
        Statement:
            #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
            # 下記の項目は作成するクラウドアプリケーションに応じて変更してください
            # 
            # サンプルではGetObjectを許可するポリシーを例として記載しています
            # 
          - Sid: PublicReadForGetBucketObjects
            Effect: Allow
            Principal: '*'
            Action: 's3:GetObject'
            Resource: 
              Fn::Join: 
                - ''
                - - 'arn:aws:s3:::'
                  - Ref: Bucket
                  - /*
            #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      Bucket: 
        Ref: Bucket
#
# S3
#************************************************************

#************************************************************
# ApiGateway
# No3.API Gatewayのテンプレート例です
#
  RestAPI:
    Type: AWS::ApiGateway::RestApi
    Properties:
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      # 下記の項目は作成するクラウドアプリケーションに応じて変更してください
      # 
      # Description: 説明文を記載してください
      # ※空文字はエラーとなります。不要の場合は「Description」を削除してください
      # Name: API名を記載してください
      #
      Description: 'sip-sample-pattern-03 RestApi'
      Name: 'sample-apigw'
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

  RestAPIDeployment:
    Type: AWS::ApiGateway::Deployment
    Properties:
      Description: ''
      RestApiId: 
        Ref: RestAPI
    DependsOn:
      - RestAPIMethod
      - RestAPIResource

  RestAPIStage:
    Type: AWS::ApiGateway::Stage
    Properties:
      RestApiId: 
        Ref: RestAPI
      DeploymentId: 
        Ref: RestAPIDeployment
      StageName: 
        Ref: StageName

  RestAPIResource:
    Type: AWS::ApiGateway::Resource
    Properties:
      PathPart: "{proxy+}"
      ParentId: 
        Fn::GetAtt: RestAPI.RootResourceId
      RestApiId: 
        Ref: RestAPI

  RestAPIMethod:
    Type: AWS::ApiGateway::Method
    Properties:
      #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      # 下記の項目は変更しないでください
      #
      # HttpMethod:        メソッド種別を指定しています
      # AuthorizationType: 認証種別を指定しています
      # Integration:       プロキシ統合に関する設定を指定しています
      # 
      HttpMethod: ANY
      AuthorizationType: AWS_IAM
      RequestParameters: 
        "method.request.path.proxy": true
      Integration:
        CacheKeyParameters: 
          - "method.request.path.proxy"
        CacheNamespace: 
          Ref: RestAPIResource
        IntegrationHttpMethod: POST
        Type: AWS_PROXY
        Uri: 
          Fn::Sub: "arn:aws:apigateway:${AWS::Region}:lambda:path/2015-03-31/functions/${EsAccess}/invocations"
      #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      ResourceId: 
        Ref: RestAPIResource
      RestApiId: 
        Ref: RestAPI
#
# ApiGateway
#************************************************************

#************************************************************
# Lambda Permission
# No3.APIGatewayからNo4.ElasticsearchアクセスLambdaへのPermissionです
#
  LambdaPermission:
  #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    Type: 'AWS::Lambda::Permission'
    Properties:
      Action: 'lambda:InvokeFunction'
      Principal: 'events.amazonaws.com'
      FunctionName: 
        Ref: EsAccess
      SourceArn: 
        Fn::Sub: "arn:aws:execute-api:${AWS::Region}:${AWS::AccountId}:${RestAPI}/${StageName}/ANY/{proxy+}"
#
# Lambda Permission
#************************************************************

#************************************************************
# Cognito
# No2.Cognitoのテンプレート例です
#
  UserPool:
    Type: AWS::Cognito::UserPool
    Properties:
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      # 下記の項目は作成するクラウドアプリケーションに応じて変更してください
      # 
      # UserPoolName:           ユーザープール名称を記載してください
      # AdminCreateUserConfig:  ユーザー作成の設定を記載してください
      #                         trueの場合管理者のみがユーザーを作成できます
      # UsernameConfiguration:  ユーザー名入力の際、大文字と小文字を区別するか否かを設定してください
      #                         trueの場合大文字と小文字が区別されます
      # AutoVerifiedAttributes: 所有権の確認に用いる手段を記載してください
      # Policies:               パスワードの強度を設定してください
      # AccountRecoverySetting: アカウントの回復方法を記載してください
      #
      UserPoolName: "sip_healthcare_user_pool_test"
      AdminCreateUserConfig:
        AllowAdminCreateUserOnly: true
      UsernameConfiguration:
        CaseSensitive: false
      AutoVerifiedAttributes: 
        - email
      Policies:
        PasswordPolicy:
          MinimumLength: 8
          RequireLowercase: true
          RequireNumbers: true
          RequireSymbols: false
          RequireUppercase: true
      AccountRecoverySetting:
        RecoveryMechanisms: 
          - Name: verified_email
            Priority: 1
          - Name: verified_phone_number
            Priority: 2
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

      LambdaConfig:
        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        # 下記の項目は変更しないでください
        #
        # PostAuthentication: 認証後に呼び出されるLambdaを設定しています
        # 
        PostAuthentication: 
          Ref: EsAccess
        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  UserPoolClient:
    Type: AWS::Cognito::UserPoolClient
    Properties:
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      # 下記の項目は作成するクラウドアプリケーションに応じて変更してください
      # 
      # ClientName:                      ユーザープールクライアント名称を記載してください
      # CallbackURLs:                    呼び出されるURLを記載してください
      # LogoutURLs:                      ログアウト後に表示されるURLを記載してください
      # GenerateSecret:                  シークレットキーを用いるか否かを設定してください
      # RefreshTokenValidity:            一時パスワードの有効期限を記載してください
      # UserPoolId:                      ユーザープールのIDを記載してください
      #                                  "Ref"の後ろにユーザープールのリソース名を記載してください
      # AllowedOAuthFlowsUserPoolClient: OAuthプロトコルを使用するか否かを設定してください
      #                                  trueの場合有効になります
      # AllowedOAuthFlows:               有効にするOAuthフローを記載してください
      # AllowedOAuthScopes:              有効にするOAuthスコープを記載してください
      # SupportedIdentityProviders:      有効にするIDプロバイダ名を記載してください
      #
      ClientName: sip-healthcare-appclient-test
      CallbackURLs: 
        - Fn::Sub: https://${BucketName}.s3.amazonaws.com/top.html
      LogoutURLs:
        - "https://www.google.com/?hl=ja"
      GenerateSecret: false
      RefreshTokenValidity: 7
      UserPoolId:
        Ref: UserPool
      AllowedOAuthFlowsUserPoolClient: true
      AllowedOAuthFlows:
        - code
        - implicit
      AllowedOAuthScopes:
        - openid
      SupportedIdentityProviders:
        - COGNITO
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

  UserPoolDomain:
    Type: AWS::Cognito::UserPoolDomain
    Properties:
      Domain: 
        Ref: BucketName
      UserPoolId:
        Ref: UserPool  

  IdentityPool:
    Type: AWS::Cognito::IdentityPool
    Properties:
      #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      # 下記の項目は変更しないでください
      #
      # AllowClassicFlow:               認証フローを指定しています
      #                                 trueの場合基本フローが許可されます
      # AllowUnauthenticatedIdentities: 認証されていないIDのアクセスの指定をしています
      #                                 trueの場合認証されていないIDに対するアクセスが有効になります
      # 
      AllowClassicFlow: False
      AllowUnauthenticatedIdentities: true
      #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      # 下記の項目は作成するクラウドアプリケーションに応じて変更してください
      # 
      # IdentityPoolName: IDプール名を記載してください
      #
      IdentityPoolName: "sip_sample_id_pool"
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      CognitoIdentityProviders:
      - ClientId: 
          Ref: UserPoolClient
        ProviderName: 
          Fn::Sub: "cognito-idp.${AWS::Region}.amazonaws.com/${UserPool}"
#
# Cognito
#************************************************************

#************************************************************
# IAM
# No2.Cognitoで使用されるIAMのテンプレート例です
#
  #************************************************************
  # 非認証ロール向けIAMポリシー
  #
  UnauthenticatedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        # 下記の項目は変更しないでください
        #
        # 非認証ロール向けの権限を指定しています
        # 
        - Effect: Allow
          Action:
          - mobileanalytics:PutEvents
          - cognito-sync:*
          Resource:
          - "*"
        - Effect: Allow
          Action: 'execute-api:Invoke'
          Resource: 
            Fn::Sub: "arn:aws:execute-api:${AWS::Region}:*:${RestAPI}/*"
        - Effect: Deny
          Action: 's3:ListBucket'
          Resource: 
            Fn::Sub: "arn:aws:s3:::${BucketName}"
        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  #************************************************************
  # 非認証ロール向けIAMロール
  #
  UnauthenticatedRole:
    Type: AWS::IAM::Role
    Properties:
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      # 作成するロールの名称を記載してください
      #
      RoleName: "sip_sample_cognito_unauth_role"
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: Allow
          Action: "sts:AssumeRoleWithWebIdentity"
          Principal:
            Federated: 
              Fn::Sub: cognito-identity.${BucketName}
      ManagedPolicyArns:
      - Ref: UnauthenticatedPolicy

  #************************************************************
  # 認証ロール向けIAMポリシー
  #
  AuthenticatedPolicy:
    Type: AWS::IAM::ManagedPolicy
    Properties:
      PolicyDocument:
        Version: "2012-10-17"
        Statement:
        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
        # 下記の項目は変更しないでください
        #
        # 認証ロール向けの権限を指定しています
        # 
        - Effect: Allow
          Action:
          - mobileanalytics:PutEvents
          - cognito-sync:*
          - cognito-identity:*
          Resource:
          - "*"
        - Effect: Allow
          Action: 's3:ListBucket'
          Resource: 
            Fn::Sub: "arn:aws:s3:::${BucketName}" 
        - Effect: Allow
          Action: 's3:GetObject'
          Resource: 
            Fn::Sub: "arn:aws:s3:::${BucketName}" 
        - Effect: Allow
          Action: 'execute-api:Invoke'
          Resource: 
            Fn::Sub: "arn:aws:execute-api:${AWS::Region}:*:${RestAPI}/*"
        #!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

  #************************************************************
  # 認証ロール向けIAMロール
  #
  AuthenticatedRole:
    Type: AWS::IAM::Role
    Properties:
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      # 作成するロールの名称を記載してください
      #
      RoleName: "sip_sample_cognito_auth_role"
      #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
        - Effect: Allow
          Action: "sts:AssumeRoleWithWebIdentity"
          Principal:
            Federated: 
              Fn::Sub: cognito-identity.${BucketName}
      ManagedPolicyArns:
      - Ref: AuthenticatedPolicy

  RoleAttachment:
    Type: AWS::Cognito::IdentityPoolRoleAttachment
    Properties:
      IdentityPoolId:
        Ref: IdentityPool
      Roles:
        unauthenticated:
          Fn::GetAtt:
          - UnauthenticatedRole
          - Arn
        authenticated:
          Fn::GetAtt:
          - AuthenticatedRole
          - Arn
#
# IAM
#************************************************************

WebUI作成例

本パターンにおけるWebUIを作成します。
サンプルでは以下のファイル、フォルダ構成となります。

top.html
js(フォルダ)
└─ index.js

WebUI画面例(top.html)

パターン03_WebUi

<!DOCTYPE html>
<html lang="ja">
 <head>
  <meta charset="utf-8">
   <title>TOP画面</title>
   <meta name="viewport" content="width=device-width, initial-scale=1">  
   <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.4.0/jquery.min.js"></script>
  </head>
<body>
    <header>
      <h2 class="bg-secondary text-white text-center">検索/登録画面</h2>
    </header>
    <div class="Search area">
      <table>
        <tr>
          <td><b> インデックス名:</b></td>
          <td><input type="text" id="index" size="30"></td>
        </tr>
        <tr>
          <td><b> クエリ/アイテム文:</b></td>
          <td><textarea id="query_item" rows="4" cols="40"></textarea></td>
        </tr>
        <tr>
          <td><button type="button" id="searchBtn" style="width: 140px">検索</button></td>
          <td><button type="button" id="addBtn" style="width: 140px">登録</button></td>
        </tr>
      </table>
    </div>
    <div class="Response area">
      <table>
        <tr>
          <td><b> 実行結果:</b></td>
          <td><textarea id="result" style="width: 810px" rows="10"></textarea></td>
      </table>
    </div>
    <script type="text/javascript" src="js/index.js"></script>
</body>
</html>

WebUIソースコード例(index.js)

/**
 * Cognitoの情報を設定します。
 *
 */
// 地域(リージョン)情報 <REGION>を環境に合わせて設定してください。
const AWS_REGION = "<REGION>";
// CognitoのIDプール情報 <IDENTITY_POOL_ID>を環境に合わせて設定してください。
const AWS_COGNITO_ID_POOL_ID = "<IDENTITY_POOL_ID>";
// Cognitoのユーザプール情報 <USER_POOL_ID>を環境に合わせて設定してください。
const AWS_COGNITO_USER_POOL_ID = "<USER_POOL_ID>";
// Cognitoのサインイン画面へのURL情報 <サインイン画面のURL>を環境に合わせて設定してください。
const SIGN_IN_URL = "<サインイン画面のURL>";


/**
 * サインインを行ったかチェックを行います。
 * サインインをしていない場合は、サインイン画面に遷移します。
 */
// IDトークンの取得を行います。
const idToken = (() => {
  const params = new URLSearchParams(location.hash.slice(1));
  return params.get("id_token");
})();

// Amazon Cognito 認証情報プロバイダーを初期化します。
AWS.config.region = AWS_REGION; 
AWS.config.credentials = new AWS.CognitoIdentityCredentials({
  IdentityPoolId: AWS_COGNITO_ID_POOL_ID,
  Logins: {
      ["cognito-idp."+ AWS_REGION +".amazonaws.com/"+AWS_COGNITO_USER_POOL_ID]: idToken,
  }
});

// トークンが無ければサインイン画面に遷移します。
if (idToken === null) {
  location.href = SIGN_IN_URL;
}


// スリープ処理
function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

window.onload = function() {

  // サインインに成功しているかチェックします。失敗の場合サインイン画面に遷移します。
  (async () => {
    for (i = 0; i < 5; i++) {
        let ok = false;
        AWS.config.credentials.get(function() {
            const secretAccessKey = AWS.config.credentials.secretAccessKey;
            if (secretAccessKey !== undefined) {
                // サインイン成功
                ok = true;
            }
      });
      await sleep(500);
      if(ok) return;
    }
    // サインイン失敗 サインイン画面に遷移します。
    location.href = SIGN_IN_URL;
  })();

};


// 入力の内容
var inputData = {
  method: "",
  index: "",
  query: "",
  item:""
};
  
// APIGatewayのURLを設定します。 <RESTAPI-ID>、<PATH>を環境に合わせて設定してください。
const apiGatewayUrl = "https://<RESTAPI-ID>.execute-api." + AWS_REGION + ".amazonaws.com/sample-stage/<PATH>"
// 検索ボタンを設定します。
const searchBtn = document.getElementById("searchBtn");
// 登録ボタンを設定します。
const addBtn = document.getElementById("addBtn");
// インデックス名テキストボックスを設定します。
const indexTxtBox = document.getElementById("index");
// クエリ文テキストエリアを設定します。
const query_itemTxtBox = document.getElementById("query_item");

// 検索イベント(クリック)登録します。
searchBtn.addEventListener("click", onSearchBtn);
// 登録イベント(クリック)登録します。
addBtn.addEventListener("click", onAddBtn);
  
  
/**
 * 検索リクエストを実行します。
 *
 */
function onSearchBtn() {
  // 操作内容を設定します。
  inputData.method = "Get";

  // インデックス名を取得します。
  inputData.index = indexTxtBox.value;

  // クエリ文を取得します。
  inputData.query = query_itemTxtBox.value;

  sendRequest();
}


/**
 * 登録リクエストを実行します。
 *
 */
 function onAddBtn() {
  // 操作内容を設定します。
  inputData.method = "Post";

  // インデックス名を取得します。
  inputData.index = indexTxtBox.value;

  // アイテム文を取得します。
  inputData.item = query_itemTxtBox.value;

  sendRequest();
}
  
  
/**
 * APIGatewayへリクエスト送信します。
 *
 */
function sendRequest() {
  // レスポンス内容をクリアします。
  $("#result").val("");

  // URL(APIatewayエンドポイント)+パラメータを結合します。
  let url = apiGatewayUrl;
  let sep = "?";

  // 操作内容情報を結合します。
  if (inputData.method.length) {
    url += sep + "method=" + inputData.method;
    sep = "&";
  }  

  // 入力されたインデックス情報を結合します。
  if (inputData.index.length) {
    url += sep + "index=" + inputData.index;
    sep = "&";
  }
  // 入力されたクエリ文を結合します。
  if (inputData.query.length) {
    url += sep + "query=" + encodeURIComponent("{" + inputData.query + "}");
  }

  // 入力されたアイテム文を結合します。
  if (inputData.item.length) {
    url += sep + "item=" + encodeURIComponent("{" + inputData.item + "}");
  }

  $.get(
    url
  ).done(function(response){
    // 文字列型に変換します。
    var text = JSON.stringify(response);
    // レスポンス内容を表示します。
    $("#result").val(text);
  }).fail(function(error){
    // レスポンス内容を表示します。
    $("#result").val(error.responseText);
  });

  //入力内容を初期化します。
  inputData.method = "";
  inputData.index = "";
  inputData.query = "";
  inputData.item = "";
}