ZendeskのチケットデータをAmazon Elasticsearch Serviceへ自動的にアップロードする | Developers.IO

Amazon Elasticsearch ServiceはAmazon VPCプライベートサブネットに作成; Amazon API Gateway経由でAWS Lambdaを実行させる; Zendeskの自動化とwebhookでAmazon Elasticsearch Serviceへデータを入れるまでを自動化する; Amazon Elasticsearch Serviceへ入れるデータスキーマ … 続きを読む

センサデータを fluentd 経由で Amazon Elasticsearch Service に送信して可視化

1. はじめに

以前の記事 で、RaspberryPi で収集したセンサデータを、 さくらVPS上に構築した Elasticsearch に送信して、Kibana で可視化しました。
今回は勉強を兼ねて、データを Amazon Elasticsearch Service ( Amazon ES ) に送信するように構成を変更します。

2. 全体の構成

image.png

3. 設定

3-1. Server side ( Amazon ES )

Amazon ES を立ち上げます。

Amazon ES ダッシュボード

  • 画面右上で、東京リージョン( ap-northeast-1 )が選択されていることを確認します
  • 新しいドメインの作成ボタンを押します
image

ドメインの定義

  • ドメイン名と Elasticsearch のバージョンを設定します
image

クラスターの設定

  • 今回は最小構成にします
image

アクセスの設定

  • ダッシュボードは特定メンバーに公開したかったので、パブリックアクセスとして、IPアドレスでアクセス制限を設定しました
  • 本当は IAM Role で制限したかったのですが、Webブラウザからのアクセスが面倒になるので今回は見送りました ( ブラウザはIAM認証できない )
image

完了確認

  • 10分ほど待ちます
image
  • 設定の状態が「アクティブ」になれば完了です
image

3-2. Sensor side ( Raspberry PI )

前提条件

以前の記事 の状態が前提です。今回はこれに変更を加えます。

プラグインのインストール

  • fluentd から Elasticsearch に直接格納するためのプラグインをインストールします
  • なお、IAM 認証をする場合は fluent-plugin-aws-elasticsearch-service を使うようです
sudo fluent-gem install fluent-plugin-elasticsearch

fluentd の設定

  • fluentd の設定ファイルを編集して、データの送信先を変更して、fluentd を再起動します
/home/pi/fluent/fluent.conf
<source>
  @type tail
  format json
  path /home/pi/myroom.log
  pos_file /home/pi/myroom.log.pos
  tag log.myroom
</source>

<match log.myroom>
  @type copy
  <store>
    @type elasticsearch
    type_name myroom
    logstash_format true
    logstash_prefix myroom
    reload_connections false
    hosts https://search-myroom-********.ap-northeast-1.es.amazonaws.com
  </store>
</match>

4. 確認

データが送信されていることを確認しました。
image.png

続きを読む

RaspberryPi で収集したセンサデータを Amazon ES に格納

1. はじめに

前回の記事 では、RaspberryPi で収集したセンサデータを、 さくらVPS上に構築した Elasticsearch に格納しました。
今回は勉強を兼ねて、データを Amazon Elasticsearch Service ( Amazon ES ) に格納するように構成変更します。

2. 全体の構成

image.png

3. 設定

3-1. Server side ( Amazon ES )

Amazon ES を立ち上げます。今回はそれだけです。

Amazon ES ダッシュボード

  • 画面右上で、東京リージョン( ap-northeast-1 )が選択されていることを確認します
  • ドメインの作成ボタンを押します
image

ドメインの定義

  • ドメイン名と Elasticsearch のバージョンを設定します
image

クラスターの設定

  • 今回は最小構成にします
image

アクセスの設定

  • ダッシュボードは特定メンバーに公開したかったので、パブリックアクセスとして、IPアドレスでアクセス制限を設定しました
  • 本当は IAM Role で制限したかったのですが、Webブラウザからのアクセスが面倒になるので今回は見送りました ( ブラウザはIAM認証できない )
image

完了確認

  • 10分ほど待ちます
image
  • 設定の状態が「アクティブ」になれば完了です
image

3-2. Sensor side ( Raspberry PI )

前提条件

以前の記事 の状態が前提です。今回はこれに変更を加えます。

プラグインのインストール

  • fluentd から Elasticsearch に直接格納するためのプラグインをインストールします
  • なお、IAM 認証をする場合は fluent-plugin-aws-elasticsearch-service を使うようです
sudo fluent-gem install fluent-plugin-elasticsearch

fluentd の設定

  • fluentd の設定ファイルを編集して、データの送信先を変更して、fluentd を再起動します
/home/pi/fluent/fluent.conf
<source>
  @type tail
  format json
  path /home/pi/myroom.log
  pos_file /home/pi/myroom.log.pos
  tag log.myroom
</source>

<match log.myroom>
  @type copy
  <store>
    @type elasticsearch
    type_name myroom
    logstash_format true
    logstash_prefix myroom
    reload_connections false
    hosts https://search-myroom-q6f5bk4cwppojeescffv24dmkm.ap-northeast-1.es.amazonaws.com
  </store>
</match>

4. 確認

データが送信されていることを確認しました。
image.png

続きを読む

Amazon Linux 2 に elasticsearchのbenchmarkツールrallyをインストールして、Amazon Elasticsearch Serviceの性能評価を行う.

Amazon Linux 2 に elasticsearchのbenchmarkツールrallyをインストールして、Amazon Elasticsearch Serviceの性能評価を行う.

Amazon Elasticssearch Serviceのパフォーマンスを調査する為に、Elasticsearchが提供するベンチマークツールのrallyを導入したEC2インスタンスを立ち上げ、性能評価を行います。

AMIは、最近発表された
Amazon Linux 2 LTS Candidate AMI 2017.12.0 (HVM), SSD Volume Type - ami-7707a10f
を利用してみます.

rallyは、python3上で動作する為、python3をインストールが必要になります.
AMIとして利用するAmazon Linux2に標準でインストールされているpythonは、version2系(Python 2.7.5)の為、python3系をインストールします。

$ sudo amazon-linux-extras install python3
$ python3 --version
Python 3.6.2

rally用のpython3環境とする為、python3の仮想環境を作ります.

$ python3 -m vent .py-esrally-venv
$ source .py-esrally-venv/bin/activate

rallyのインストール,実行時に不足するライブラリをインストールします.

$ sudo yum install gcc python3-devel git

rallyをインストールします.

(.py-esrally-venv) $ pip3 install esrally
(.py-esrally-venv) $ esrally configure
 # Press Enter to skip. 

elasticsearch serviceへのアクセスは、 Signature Version 4でアクセスする必要がある為、rallyから直接接続するすることができません. そこで Elasticsearch serviceにアクセスする為のproxyを立ち上げます.
今回は、 nodeベースのproxy aws-es-proxyを利用します.

nodeをインストールする為にnvmのインストールを行い、その後、nodeをインストールし、 aws-es-proxyを導入します.

(.py-esrally-venv) $ curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.8/install.sh | bash
(.py-esrally-venv) $ source .bashrc
(.py-esrally-venv) $ nvm install  v8.9.3
(.py-esrally-venv) $ npm init
(.py-esrally-venv) $ npm install --save aws-es-proxy

proxyを起動します.
なお、aws credentials情報(access_key_id, aws_secret_access_key)は、aws cliで設定しておいてください.

(.py-esrally-venv) $ node_modules/aws-es-proxy/bin/aws-es-proxy --port 9200 --profile default --region [region]  [endpoint]

proxy経由でElasticsearch Serviceにアクセスできることを確認します.

(.py-esrally-venv) $ curl http://localhost:9200/

rallyを実行します. target-hostsとして、proxyのアドレスを指定します。

(.py-esrally-venv) $ esrally --pipeline=benchmark-only --target-hosts=localhost:9200
    ____        ____
   / __ ____ _/ / /_  __
  / /_/ / __ `/ / / / / /
 / _, _/ /_/ / / / /_/ /
/_/ |_|__,_/_/_/__, /
                /____/

[INFO] Writing logs to /home/xxxxx/.rally/logs/rally_out_20171225T052238Z.log

************************************************************************
************** WARNING: A dark dungeon lies ahead of you  **************
************************************************************************

Rally does not have control over the configuration of the benchmarked
Elasticsearch cluster.

Be aware that results may be misleading due to problems with the setup.
Rally is also not able to gather lots of metrics at all (like CPU usage
of the benchmarked cluster) or may even produce misleading metrics (like
the index size).

************************************************************************
****** Use this pipeline only if you are aware of the tradeoffs.  ******
*************************** Watch your step! ***************************
************************************************************************
    :
  • 参考
    利用させていただいたproxy.
    https://github.com/joona/aws-es-proxy
    esrallyのドキュメント
    https://esrally.readthedocs.io/en/latest/index.html

  • 残件
    Amazon Elasticsearch Serviceの構成変更での性能評価を目的としている為、異なるproxyを利用する必要はないと想定しているが、go言語で実装された aws-es-proxyを使った場合の比較などもやっておくべきかもしれない. proxyで、パフォーマンスに差が出ると、性能指標の基準が低くなってしまうはず..
    trackを指定することで、異なるデータパターンでの評価を行うことができるので、サービスでの利用方法に近いtrackでの評価を実施すべき..デフォルト(オプション指定無)は、geonames.

  • 備考
    インスタンスタイプがt2.microだと、途中で異常終了してしまうようです. 評価中、CPU Creditを、使い切って途中で異常終了しました.
    また、Amazon Elasticsearch Service側の構成として、簡単に1台で立ち上げられますが、1台構成の場合、StatusがYellowの為、デフォルトでは、測定できません。 以下のようなERRORを出力して、測定が中断します.
    [ERROR] Cannot race. ('Could not execute benchmark', Cluster did not reach status [green]. Last reached status: [yellow])
    どうしても1台構成で実行する場合は、rally実行時に、 --cluster-health=yellow optionを付与する必要があります。

続きを読む

Amazon Elasticsearch ServiceのKibanaへ、SSH port forwardingでトンネルを掘り、踏み台サーバ経由でアクセスする

TL;DR

たまにSSH port forwardingのやり方を聞かれるのでメモがてら。

3+1行で説明するとこんな感じ。
SSH port forwardingでトンネルを掘る

ssh -i ~/Path_to_SSH_key/id_xxxx {account_name}@{踏み台サーバIP or DNS name} -L 8888:{Kibana private IP}:80 -N

ブラウザで(トンネルを通ってKibanaへアクセスする

http://localhost:8888/_plugin/kibana

Kibanaへのアクセス

今のところKibanaへアクセスするニーズがあるのは開発者のみ。
開発者は踏み台サーバにアカウントを持っている。

というわけで ssh port forwardingでアクセスできれば良しとしているケースです。

手順

1. KibanaのPrivate IPを確認

※東京リージョンの場合
https://ap-northeast-1.console.aws.amazon.com/es/home
My domains > “Kibanaにアクセスしたいドメイン” > Overview

Screen Shot 2017-12-20 at 17.50.05.png

赤枠部分のドメインをメモし、IPを確認する

$ host {赤枠部分のドメイン}.es.amazonaws.com
{赤枠部分のドメイン}.es.amazonaws.com has address 172.xx.xx.xx
{赤枠部分のドメイン}.es.amazonaws.com has address 172.xx.xx.xx

2. SSH port forwardingでトンネルを掘る

ssh -i ~/Path_to_SSH_key/id_xxxx {account_name}@{踏み台サーバIP or DNS name} -L 8888:{Kibana private IP:Port}:80 -N


e.g)
ssh -i ~/.ssh/id_rsa nntsugu@ec2-xx-xxx-xxx-xxx.ap-northeast-1.compute.amazonaws.com -L 8888:xxx.xxx.xxx.xxx:80 -N

3. ブラウザで(トンネルを通ってKibanaへアクセスする

http://localhost:8888/_plugin/kibana

お手軽に検索

Kibana > Dev Tools > Console
からだとJSONでクエリを投げられるのでとっつきやすい。かもしれない。

GET _search
{
  "query": {
    "match": {
      "severity": "ERROR"
    }
  }
}

続きを読む

AWS AppSync (Preview)を試してみた

AppSyncのプレビュー申請が通ったので早速試してみました

0.PNG

AWS AppSyncとは

AWS AppSync では、ウェブアプリケーションやモバイルアプリケーション内のデータがリアルタイムで自動的に更新されます。また、オフラインユーザーが再接続するとすぐにデータが更新されます。AppSync により、応答性に優れた協働的なユーザーエクスペリエンスを実現できる、共同のモバイルアプリケーションやウェブアプリケーションを簡単に構築できます。

AWS AppSync を使用すると、iOS、Android、JavaScript、React Native でネイティブなモバイルアプリケーションやウェブアプリケーションを構築できます。AWS AppSync コンソールにアクセスし、シンプルなコードステートメントでアプリケーションのデータを指定して、使用を開始してください。アプリケーションのデータの保存、処理、取得に必要なものすべては、AppSync で管理されます。

AWS AppSync

APIの作成

1. APIの作成

勢いよく「Create API」ボタンを押します。
1.PNG

2. APIの命名

ここではmyAppSyncとしておきます。
2.PNG

3. スキーマの選択

カスタムスキーマとサンプルスキーマを選択できます。
今回はあらかじめ用意されているサンプルスキーマを使いました。
DynamoDBのテーブルとアクセスに必要なIAM roleを自動生成してくれました。

3.PNG

4. スキーマの確認

スキーマが表示されますので、一番下の「Create」ボタンを押します。

5.PNG

これでAPIが作成されました!早い!

APIの確認

APIが作成されると、サンプルをGithubからクローンできます。
また、スキーマのダウンロードが可能です。

6.PNG

1. URL・API KEYの確認

作成したAPI「myAppSync」のトップページでURLやAPIキーを確認できます
7.PNG

2. DynamoDBの確認

DynamoDBのテーブルが自動生成されているのを確認する事が出来ました!
8.PNG

Read Capacity、Write Capacity共に「5」になっているので、テスト用途であれば小さめにしておきましょう。
9.PNG

今回は「1」にしておきました。
10.PNG

3. クエリーのテスト

AppSyncではクエリーのテストが出来るようになっています。
早速サンプルのイベントテーブルへデータを追加します。
11.PNG

無事にデータが入りました!
12.PNG

所感

  • GraphQLサーバーを数分で利用できるようになるのはとても便利で、apollo-serverをコンテナで立てるよりも楽だなという印象を受けました。
  • AWSの対応しているデータソースに繋ぐのであればとても便利なサービスです。
  • データソースはDynamoDB、Elasticsearch service、Lambdaの3つと制限はありますが、IAM roleを自動生成してくれるのはありがたいです。
  • スキーマは自分で準備する必要があるのでGraphQLの知識は必須です。
  • 今後はもう少し時間を作ってモバイルデバイスからのオフライン、オンライン時の動きを確かめたいと思います。

参考
Amazon Web Services ブログ

続きを読む

Meraki WiFi 位置情報の活用シーン

はじめに

以下2つの記事は Meraki Scanning API に関して、設定手順を中心にまとめています:

本記事はこれらの補足として、もう少しイメージが付くよう活用シーン付きで基本的な事柄も交えながら説明を試みます。

活用シーン

Meraki WiFi の活用シーンを小売店と想定します。Meraki WiFi はもともと次のような用途に向いています。

  • 店舗で WiFi を使えるようにしたい
  • 用途は業務用・お客様用の両方に使いたい
  • ビデオ視聴も可能な高速アクセスが必要
  • 店舗数は一店~数万店
  • 専任管理者がいないのでできるだけ簡単に運用したい
  • WiFi 位置情報を活用したい

Meraki WiFi の説明

そもそも Meraki WiFi とは?

Meraki WiFi はクラウド管理型 WiFi サービスです。

一般に、クラウドとは皆さんご存知の通り、データの保存や処理を手元の端末で行うのではなくインターネットを通じて「向こう側」に保存・処理する手法を指します。ところが、中には「向こう側」では不都合が出るサービスもあります。例えばリアルタイム処理が必要で遅延が問題となる場合には「こちら側」で処理できるよう機器を置くといいかもしれません。

WiFi も「向こう側」で全てを行うことはできません。WiFi 電波は仕様上 30メートルほどしか飛びませんので例えば東京タワーから送信しても「こちら側」の端末まで届きません。そこで Meraki アクセスポイント(AP) を「こちら側=店舗」に置くことになります。

AP がこちらにある以外は通常のクラウドサービスと同じ使い勝手で設定や監視ができるため、従来の WiFi AP を買ってきて個々に設定・設置する方法に比べると、特に多店舗では工数が圧倒的に少なくなるメリットがあります。

写真1:Meraki AP

image.png

クラウドへは Web ブラウザ経由でアクセスします。仮に複雑な機能を使ってもクラウド上に設定が残りますので、故障などで AP を交換した場合に一から再設定する必要はありません。また、数万 AP に対して一斉に設定変更を行うこともできます。

イメージ1:Meraki ダッシュボード(日本語対応済)
image.png

WiFi 端末の位置情報について(Meraki ダッシュボード)

スマホ等の WiFi 端末は使っていなくても(WiFi がオンになっていれば)プローブリクエストを定期的に送信します。送信間隔は機器の種類や状態によって異なります。

スマホの状態(iOS、アンドロイド等) プローブリクエストの間隔
スリープ(スクリーンオフ) 1分に1回程度
スリープ(スクリーンオン) 10-15回/分
APにアソシエート アプリケーションに大きく依存

WiFi 端末の送信するプローブリクエストを Meraki AP が受信すると、その時刻を SeenTime として記録します。また、プローブリクエストから端末の位置を算出する機能を持ちます。

WiFi 端末の識別には MACアドレスが使われますが、プライバシーの問題もあるため Meraki クラウドは一切の MAC アドレス情報を保存せず、そのハッシュ値のみを保存しています。

これらデータを利用して生成された端末位置情報ヒートマップを Meraki ダッシュボード(標準の管理インターフェイス)で見ることができます。

イメージ2:端末位置情報ヒートマップ(青はアソシエートした端末、灰色はアソシエートしていない端末、風船アイコンはAP)
image.png

また、データ解析レポートも Meraki ダッシュボードで見ることができます。

イメージ3:データ解析レポート
image.png

グラフは上から順に以下の意味を持っています:

  • 一つ目:近くを通っただけの人(Passersby)、訪問した人(Visitors)、接続して使った人(Connected)の割合
  • 二つ目:滞在時間毎の割合
  • 三つ目:訪問頻度の割合

データ解析レポートでは次のような比較が可能です。マーケティング的な分析に使えそうです。

  • 一店舗内のデータを異なる期間で比較(今週と先週)
  • 複数店舗間のデータを同一期間で比較(A店とB店、A店と全店の平均、A店とA~D店の平均、A~D店の平均と全店の平均)

以上は標準の Meraki ダッシュボードで利用可能です。

Scanning API の活用方法

端末位置情報を保持するには?

Meraki クラウドは上述のレポート提供を目的として WiFi 端末の位置情報を利用していますが、「個々の端末の時系列の位置情報」を保存している訳ではありません。保存したいと思った場合には Meraki クラウドから Scanning API を経由して取得可能です。ただし、保存用サーバを準備する必要があります。

サーバの準備が面倒であれば、例えば AWS の API Gateway/Lambda/DynamoDB を組み合わせて使うことでサーバレスにて比較的簡単に実現できます。手順はこちらの記事をご参照下さい(データ量は多くなり得るのでご注意下さい)。

DynamoDB は NoSQL データベースで可視化はあまり得意ではありません。可視化には同じく AWS の Elasticsearch service/kibana が利用できます。手順はこちらの記事をご参照ください。

端末位置情報から来店の有無を確認する

多くの小売店ではポイントカードを導入しており、お客様毎の購買履歴をデータとして蓄積しているかもしれません。ポイントカードは基本的に購入時のみ使うので、お客様が何も購入せずに店舗を去った場合には履歴が残りません。

それに対し、WiFi 位置情報はお客様が来店すれば(WiFi がオンになっている端末を持っている前提)データが残るため、これまでに扱えなかったデータの分析ができるようになる可能性があります。例えば、来店に対する購入頻度や、商品入替え・欠品による機会損失のより正確な額が求められるかもしれません。

イメージ4:既存お客様購買履歴とWiFi位置情報をマッピングした例。Meraki が提供する機能ではなくあくまでアイデアです。
image.png

※ イメージ4を実現するには、MACアドレスと個人情報の紐づけを何らかの方法で行う必要もあります

もっとも、お客様にとって来店記録が残ること自体気持ち良いものではなく、個人情報保護法を遵守しながらプライバシーを慎重に扱う必要があります(オプトイン・オプトアウト、保存データのハッシュ化等)。お客様にとって不利益が無く、新しい顧客体験を提供できることが何より重要かもしれません。技術の領域を越えますのでこの議論はここまでにしておきたいと思います。

最後に、MAC アドレス毎の SeenTime (AP が端末のプローブリクエストを受信した時刻)を可視化したグラフを作ってみました。Meraki の位置情報にご興味持たれた方は、データ活用に使えそうか眺めて頂けると幸いです。

DynamoDB 上のデータを CSV でファイルへ出力し、matplotlib で読み込んで描画しました。

イメージ5:MACアドレス毎の SeenTime (MACアドレスは左側をちょん切ってます)
image.png

イメージ5のコード
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
import pylab
from datetime import datetime as dt

# グラフ表示する MACアドレスの数を指定
cmac_num4graph = 50

# DynamoDB から取得した CSV ファイルの読込み
df = pd.read_csv("cmxdata.csv", parse_dates = ['seenString (S)'])

# MACアドレスの一覧作成
cmac_index = set(df['clientMac (S)'])

# MACアドレスの一覧作成(グラフ表示用)
cmac_index = list(cmac_index)[:cmac_num4graph]

# CSV ファイルから 'clientMac (S)' と 'seenString (S)' のみ抜き出したデータフレーム StringMac を作成
StringMac = pd.concat([df['clientMac (S)'], df['seenString (S)']], axis = 1)

# グラフ描画用のデータフレーム result_df を作成
result_df = pd.DataFrame()
for mac in cmac_index:
    seenString = StringMac[StringMac['clientMac (S)'] == mac]['seenString (S)']
    seenString = pd.Series(seenString, name = mac)
    df_seenString = seenString.to_frame()
    result_df = pd.concat([result_df, seenString], axis = 1)

# グラフを描画
pylab.figure(figsize=(15, 8))
xmin = dt(2017,12,17,7,22,0)
xmax = dt(2017,12,17,7,33,0)
for (y, mac) in enumerate(cmac_index):
    m = result_df[mac].dropna()
    y = np.linspace(y, y, len(m))
    result_df[mac].dropna()
    plt.scatter(m.tolist(), y)

plt.grid(True)
plt.xlim(xmin,xmax)
plt.yticks(range(0, cmac_num4graph, 1), cmac_index, fontsize = 8)
plt.show()

続きを読む

初めてのパブリッククラウド

入社前は、オンプレミスやプライベートクラウドでサービスを運用しているプロジェクトのみに従事してきましたが、ピクスタで初めてパブリッククラウドでのサービス運用に携わりました。 今回は、私がピクスタに入社して初めて使用したパブリッククラウド上のサービスのうち、Amazon Elasticsearch Service(以下、AWS ES)での … 続きを読む

Terraformにおけるクロスアカウント構成なモジュール

これはDMM.com #2 Advent Calendar 2017 8日目の記事です。

カレンダーのURLはこちら
DMM.com #1 Advent Calendar 2017
DMM.com #2 Advent Calendar 2017

こんにちは@mafuyukです。
最近はAWSでクロスアカウントなログ収集基盤の設計、実装、構成の自動化をしていました。

本記事では実際に作成した、ログ収集基盤の構成を参考にTerraformにおけるクロスアカウント構成なモジュールについて紹介したいと思います。

ログ収集基盤の構成紹介

Untitled Diagram (3).png

構成図の説明

別々のAWSアカウントのログを一元管理したいという要件を満たすために用意したログ収集基盤の構成図です。

図の上部にあるAWSアカウントでは、ログの一元管理を行っていて、同じAWSアカウント内のログや複数の別AWSアカウントのログを1つのアカウントに集約しています。
AWSアカウント同士の連携はAssumeRoleで実現しています。

ログ収集の流れ

  1. CWLのログをサブスクリプションフィルターをトリガーとしたLambdaで取得
  2. LambdaはAssume Roleでアクセス権限を取得後、Kinesis FirehoseのAPIをcallしログをストリームに流し入れる
  3. ストリームはログ保管用S3とログ可視化用Elasticsearch Serviceに出力する

構成図の赤丸で囲った部分(上記の1と2の部分)をモジュール化します。

Terraform新機能

実践に入る前におめでたい話

祝Terraform v0.11 リリース

2017年11月16日にTerraform v0.11がリリースされましたー:tada::tada::tada::tada:

今回作成するモジュールのテンプレートではv0.11で新たに追加されたprovidersというオプションを利用するのでTerraformのversionを確認してください:bow:

対象version 0.11.1

v0.11で追加されたmoduleの新オプションprovidersとは??

v0.10まで

v0.10までmoduleを利用する際にはプロバイダの継承が暗黙的に行われていました

provider "aws" {
  version                 = "~> 1.0"
  region                  = "us-west-2"
  shared_credentials_file = "${var.shared_credentials_file}"
}

module "create_module" {
  source = "git::https://github.com/mafuyuk/tf-aws-template?ref=master"
  // moduleを利用しているTerraform環境のデフォルトのプロパイダに対しての操作になる 
}

v0.11から

v0.11からはmoduleに対してプロバイダ情報をprovidersを使って明示的に渡す事ができるようになりました。

provider "aws" {
  version                 = "~> 1.0"
  region                  = "us-west-2"
  shared_credentials_file = "${var.shared_credentials_file}"
}

provider "aws" {
  version                 = "~> 1.0"
  alias                   = "foo"
  region                  = "us-west-2"
  shared_credentials_file = "${var.shared_credentials_file}"
}

module "create_module" {
  source = "git::https://github.com/mafuyuk/tf-aws-template?ref=master"
  providers = {
    "aws" = "aws.foo" // module内のaws(デフォルト)の値がaws.fooプロパイダになる
    "aws.bar" = "aws" // module内のaw.barの値がデフォルトプロパイダになる
  }
}

:warning: module内で1つのプロバイダのみに対して操作する場合は、従来の暗黙的なプロバイダ継承を推奨すると公式に記載されていましたのでうまく使い分けましょう。

実践

module側プロパイダ設定

クロスアカウント構成を実現するためにmodule側でプロパイダ設定を2つ受け取れるようにします。

aws.tf
// ログがあるAWSアカウントのプロバイダ
provider "aws" {
  alias  = "src"
}

// ログを集約するAWSアカウントのプロバイダ
provider "aws" {
  alias  = "dst"
}

moduleを利用する

このモジュールを利用する場合は以下のようにprovidersを渡します。

provider "aws" {
  version                 = "~> 1.0"
  alias                   = "myprov"
  profile                 = "myprov"
  region                  = "${var.myprov_region}"
  shared_credentials_file = "${var.shared_credentials_file}"
}

provider "aws" {
  version                 = "~> 1.0"
  alias                   = "logprov"
  profile                 = "logprov"
  region                  = "${var.logprov_region}"
  shared_credentials_file = "${var.shared_credentials_file}"
}

module "create_resource" {
  source = "git::https://github.com/mafuyuk/tf-aws-template?ref=master"
  providers = {
    "aws.src" = "aws.myprov"
    "aws.dst" = "aws.logprov"
  }
}

受け取った2つのプロバイダ情報を利用する

参考にしたログの収集基盤では、AssumeRole周りで2つのプロパイダ構成を利用する必要がありました。
実際に今回の構成のどの部分に使ったのかみてみましょう。

iam.tf
resource "aws_iam_role" "lambda" {
  provider = "aws.src"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Principal": {
        "Service": "lambda.amazonaws.com"
      },
      "Effect": "Allow"
    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "writes_to_cwl_policy" {
  // ただのCWLへの書き込み権限なので省略
}

// src側のRoleにdst側のRoleに対してAssumeRoleを行えるポリシー付与
resource "aws_iam_role_policy" "fh_sts_policy" {
  provider = "aws.src"
  role     = "${aws_iam_role.lambda.id}"

  policy = <<EOF
{
    "Version": "2012-10-17",
    "Statement": {
        "Effect": "Allow",
        "Action": "sts:AssumeRole",
        "Resource": "${aws_iam_role.lambda_assume.arn}"
    }
}
EOF
}

// dst側ではsrc側のロールがAssumeRoleを行った際に
// KinesisFirehoseの実行権限を持った一時クレデンシャルを発行することが可能なRoleを作成
resource "aws_iam_role" "lambda_assume" {
  provider = "aws.dst"
  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "${aws_iam_role.lambda.arn}"
      },
      "Action": "sts:AssumeRole"
    }
  ]
}
EOF
}

resource "aws_iam_role_policy" "writes_to_fh_policy" {
  provider = "aws.dst"
  role     = "${aws_iam_role.lambda_assume.id}"

  policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "firehose:PutRecordBatch",
      "Resource": [
        "${var.fh_stream_arn}" // 出力先のFirehoseのARN
      ]
    }
  ]
}
EOF
}

Terraformにおけるクロスアカウント構成なモジュールに必要な実装の紹介は以上です。
これで複数のAWSアカウントを股にかけたモジュールの作成ができるようになったと思います:100:

続きを読む