Amazon Echo (Alexa) で自宅のネットワークを覗いてみる

この記事はシスコの同志による [Cisco Systems Japan Advent Calendar 2017](https://qiita.com/advent-calendar/2017/cisco) の 17 日目です。

# TL;DR
- Cisco Meraki はクラウドでネットワーク全体を一元管理します
    - **ネットワークの状況**を Web インターフェイス / API で提供します
- 今流行りの **Amazon Echo (Alexa)** を使って Meraki な自宅の状況を聴けるようにしてみました
- ネットワークエンジニアなら**朝のニュースで自宅のネットワークを確認**しよう!!!

# デモ

こればっかりは見るより聞いたほうがはやいです。

<a href="https://vimeo.com/247607334"><img width="687" alt="Video" src="https://qiita-image-store.s3.amazonaws.com/0/214716/74094c14-a817-b756-bce6-1a82d2f80b42.png"></a>

# 構成

![構成図](https://gist.githubusercontent.com/mochipon/68a852415b188c856783c3411adb5086/raw/43c29d5d939581a6588063cb19d7b8f3e52e9163/alexa.gif)

# 方針
- [Cisco Meraki](https://meraki.cisco.com/) が提供する [Dashboard API](https://dashboard.meraki.com/api_docs) を使って、ネットワークの情報を取得します
    - Cisco Meraki のダッシュボードはネットワーク機器の状態だけではなく、**高い通信の可視性**を提供します
<details><summary>ここをクリックしてダッシュボードのサンプルを表示</summary><div>
![ダッシュボードのサンプル](https://gist.githubusercontent.com/mochipon/68a852415b188c856783c3411adb5086/raw/6dcb07499b1ecebac5b7a908753a626f1af6e520/dashboard.png)
</div></details>
- Amazon Echo (Alexa) を使って、ユーザインターフェイスを全て音声にします
    - Alexa Skills Kit の開発環境を使うことで、自分の Alexa だけで使えるオリジナルの[フラッシュニュース](https://developer.amazon.com/ja/docs/flashbriefing/understand-the-flash-briefing-skill-api.html)を作ります
        - 会話例：「Alexa, 今日のニュースは？」「今日のニュースは....」
- 1 時間おきに [AWS Lambda](https://aws.amazon.com/jp/lambda/) で実行する Python スクリプトがニュース記事を作成して [Amazon S3](https://aws.amazon.com/jp/s3/) に保存し、Alexa は 1 時間以内に作成されたニュース記事を読み上げます
    - フラッシュブリーフィングスキル API では Alexa からニュース記事を要求されたとき [**応答のレイテンシーが 1 秒未満** であることが要求されます](https://developer.amazon.com/ja/docs/flashbriefing/flash-briefing-skill-api-feed-reference.html#performance-requirements)
    - 要求に応じてリアルタイムにニュース記事を生成することは困難のため、リアルタイム性は犠牲にします

# 具体的な構築手順

この記事ではスクリーンショット多めに、この環境の構築手順を細かく説明しています。時間がなければ[まとめ](#まとめ)に進んでください！

## ニュース記事を作る
### 前提
AWS にアカウントがあり、[AWS コンソール](https://console.aws.amazon.com/console/home)にログインできる必要があります。
### 1. KMS 暗号化キーの作成
今回の記事では Lambda 関数で実行する Python スクリプトが Cisco Meraki Dashboard API から情報を取得します。そのため、Python スクリプトは Meraki API の認証情報を必要とします。Amazon は[機密情報を暗号化して保存することを強く推奨](https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/env_variables.html#env-storing-sensitive-data)しているため、今回の記事では Meraki API の認証情報を暗号化して取り扱います。この節では認証情報の暗号化・復号化で使われる暗号化キーを簡単に作成および管理できるマネージド型サービス **KMS** の初期設定を行います。

#### 1.1. KMS 暗号化キーの作成

AWS コンソールから [IAM → 暗号化キー](https://console.aws.amazon.com/iam/home#/encryptionKeys/us-west-2) を開き、`キーの作成` をクリックします。

適当な名前をつけて進めます。
![IAM - 暗号化キーの作成](https://qiita-image-store.s3.amazonaws.com/0/214716/f0f02a5d-6669-f5d3-d758-408d34b54257.png)

`キー管理アクセス許可の定義` 及び `キーの使用アクセス許可の定義` では自分のアカウントを選択し、ウィザードに従って暗号化キーを作成します。

![IAM - キー管理アクセス許可の定義](https://qiita-image-store.s3.amazonaws.com/0/214716/50ccc81b-5137-c7ea-8cb2-dc428802dbbd.png)

#### 1.2. 作成した暗号化キーの ARN を確認

この後の作業で必要になるので暗号化キーの **ARN** をメモします。

![IAM - 作成した暗号化キーの概要の表示](https://qiita-image-store.s3.amazonaws.com/0/214716/f42814bd-3e3e-87cb-26df-55ab63fca5ee.png)

### 2. S3 バケットの作成
今回の記事では Lambda 関数で実行する Python スクリプトが定期的にニュース記事を作成します。この節では作成されたニュース記事を保存する受け皿（ストレージ ≒ **バケット**）を **Amazon S3** に作り、このニュース記事を外部に HTTPS で公開するための設定を行います。

#### 2.1. S3 バケットの作成

AWS コンソールから [S3](https://s3.console.aws.amazon.com/s3/home?region=us-west-2) を開き、`バケットを作成する` をクリックします。適当なバケット名をつけて `作成` をクリックします。

<img width="1178" alt="S3 - バケットの作成" src="https://qiita-image-store.s3.amazonaws.com/0/214716/fd34e030-88ba-3d55-a68d-b2e6e07da2ac.png">

#### 2.2. 外部公開のためのポリシー設定

作成したバケットの `アクセス権 → パケットポリシー` に外部公開のためのポリシーを設定します。
<details><summary>ここをクリックするとコピペ用の文字列が表示されます</summary><div>

`<s3-bucketname>` の部分は実際のバケット名に置き換えてください。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "PublicReadGetObject",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::<s3-bucketname>/*"
        }
    ]
}
```
</div></details>
![S3 - 外部公開のためのポリシー設定](https://qiita-image-store.s3.amazonaws.com/0/214716/876d223c-f86c-5fd3-ebac-503ce0d8360c.png)


### 3. IAM ロールの作成
今回の記事では Lambda 関数で実行する Python スクリプトが [KMS 暗号化キー](#1-kms-の作成)を使ったり、[S3 バケット](#2-s3-バケットの作成)にファイルを保存したりします。この節ではまず、Lambda 関数が必要とする権限の定義（**ポリシー**）を作成します。最後に、ポリシーを使ってアクセス権の委任（**IAM ロール**）を行います。

#### 3.1. IAM ポリシーの作成
AWS コンソールから [IAM → ポリシー → ポリシーの作成](https://console.aws.amazon.com/iam/home?region=us-west-2#/policies$new?step=edit) を開きます。[S3 でポリシーを設定](#22-外部公開のためのポリシー設定)したときと同様に、ここでも ポリシーを json 形式で表現します。

<details><summary>ここをクリックするとコピペ用の文字列が表示されます</summary><div>

`<s3-bucketname>` `<ARN-KMS>` の部分は実際のバケット名及び KMS の ARN に置き換えてください。

```json
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "logs:CreateLogGroup",
                "logs:CreateLogStream",
                "logs:PutLogEvents"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": "s3:*",
            "Resource": "arn:aws:s3:::<s3-bucketname>/*"
        },
        {
            "Effect": "Allow",
            "Action": ["kms:Decrypt"],
            "Resource": [
                "<ARN-KMS>"
            ]
        }
    ]
}
```
</div></details>

<img width="852" alt="IAM - ポリシーの作成" src="https://qiita-image-store.s3.amazonaws.com/0/214716/40581751-7cbd-cfca-831e-a32fc48221b8.png">

#### 3.2. IAM ロールの作成

AWS コンソールから [IAM → ロール → ロールの作成 → Lambda](https://console.aws.amazon.com/iam/home?region=us-west-2#/roles$new?step=permissions&selectedService=Lambda&selectedUseCase=Lambda) と進みます。ポリシーの一覧が表示されるので、[先ほど作成したポリシー](#31-iam-ポリシーの作成)を選択します。
<img width="996" alt="IAM - ポリシーの関連付け" src="https://qiita-image-store.s3.amazonaws.com/0/214716/b61ba3e1-da10-65a3-c882-657d75d84652.png">

適当な名前をつけて IAM ロールの作成は完了です。

### 4. Lambda 関数の作成
AWS Lambda はサーバーを構築することなしにプログラムを実行することができるプラットフォームです。実行したいプログラムやその条件を設定するだけで、必要に応じてプログラムをサーバ（コンテナ）に展開してくれます。この節では Lamnda 関数を作成し、1 時間おきに自動実行されるように設定します。

#### 4.1. 設計図を使って Lambda 関数を作成

AWS コンソールから [Lambda](https://us-west-2.console.aws.amazon.com/lambda/home?region=us-west-2#/functions) を開き、`関数の作成` を行います。

ここでは手順を簡単にするために、Lamba であらかじめ用意された設計図（テンプレート）`lambda-canary-python3` を使います。これは定期的に Web サイトを確認して、エラーを検出するための Lambda 関数の設計図です。定期的に Meraki API を使ってニュースを作成する、という今回の記事に似ていますね :)

![Lambda - 設計図を選択](https://qiita-image-store.s3.amazonaws.com/0/214716/617f9e51-12dc-5f94-90ca-3241707eb67e.png)

設計図に沿って設定を行います。基本的にデフォルトのままで問題はありませんが、IAM ロールとトリガーは設定が必要です。ここでいうトリガーとは Lambda 関数を実行する「きっかけ」「条件」のようなものです。今回は **1 時間おきのタイマー**をトリガーとして設定します。入力例は以下の通りです。

<img width="711" alt="Lambda - 設計図をもとに設定" src="https://qiita-image-store.s3.amazonaws.com/0/214716/68cf142c-c2a0-7711-5685-5f4a464dd6a6.png">

<img width="689" alt="Lambda - トリガーを設定" src="https://qiita-image-store.s3.amazonaws.com/0/214716/0ca0edd3-fde4-17da-478a-b5b8288a1d9e.png">

Lambda 関数が作成されます。1 時間おきに自動的に実行するためのトリガー（**CloudWatch Events**）と、IAM ロールに基づいて **KMS 暗号化キー**と **S3 バケット**への関連付けが行われていることがわかります。

![Lambda - 作成直後](https://qiita-image-store.s3.amazonaws.com/0/214716/5267029d-caf6-c56c-cea8-6149f58e0e58.png)

#### 4.2. 関数コードのアップロード

次に Lambda 関数として実行する Python スクリプトを設定します。`関数コード` の欄から `.zip ファイルをアップロード` を選んで、Python スクリプト一式をアップロードします。今回の記事で使ったプログラムは [upload.zip](https://gist.githubusercontent.com/mochipon/68a852415b188c856783c3411adb5086/raw/upload.zip) として公開しています。エラー処理などは不十分ですが、プログラミングすることなく、誰でも使い回せるように設計されています。

<img width="1040" alt="Lambda - 関数コードのアップロード" src="https://qiita-image-store.s3.amazonaws.com/0/214716/14366919-7f29-1062-810c-aef6a39a8120.png">

#### 4.3. 環境変数の設定

ユーザごとに異なる変数は環境変数として Python スクリプトに入力します。このスクリプトでは以下の環境変数を使います。

- `enc_apikey`: 暗号化済みの Cisco Meraki API キー (取得方法は[こちら](https://documentation.meraki.com/zGeneral_Administration/Other_Topics/The_Cisco_Meraki_Dashboard_API#Overview))
- `organization_name`: Cisco Meraki 上の組織名
- `network_name`: Cisco Meraki 上のネットワーク名
- `bucket_name`: ニュース記事を保存するために[先ほど作成した S3 バケット](#21-s3-バケットの作成) の名前

Meraki API の認証情報は暗号化するので、API キーを入力した後に **暗号化** ボタンを押してください。自動的に暗号化されます。

<img width="1032" alt="Lambda - 環境変数の設定" src="https://qiita-image-store.s3.amazonaws.com/0/214716/35ae4447-e48d-06f1-d445-e34400485049.png">

#### 4.4. トリガーの有効化

画面上部の `CloudWatch Events` をクリックしてトリガーを有効にします。

![Lambda - トリガーの有効化](https://qiita-image-store.s3.amazonaws.com/0/214716/e2f64da8-b0e4-0c13-e949-3ccfea222b6d.png)

#### 4.5. 動作確認

画面右上の `テスト` をクリックして適当なイベント名を入力し、保存します。
<img width="583" alt="Screen Shot 2017-12-15 at 23.14.31.png" src="https://qiita-image-store.s3.amazonaws.com/0/214716/b7722d9e-83ff-1070-6956-835433cd7e07.png">

`テスト` をクリックすればタイマーを待つことなく Lambda 関数を実行することができます。
<img width="307" alt="Screen Shot 2017-12-15 at 23.14.40.png" src="https://qiita-image-store.s3.amazonaws.com/0/214716/71ef548e-1b8f-1c5e-8c26-c87f03aa25fc.png">

以下のように表示されれば成功です。
<img width="846" alt="Screen Shot 2017-12-15 at 23.14.54.png" src="https://qiita-image-store.s3.amazonaws.com/0/214716/3d61b007-51c9-838e-08e3-23e3e9e5eeb9.png">

AWS コンソールから [S3](https://s3.console.aws.amazon.com/s3/home?region=us-west-2) を開き、先程作成したバケットを開いてください。Lambda 関数によって作成されたニュース記事 **news.json** が見えます。このファイルへのリンク (https://.....) をメモしておきます。

<img width="1031" alt="Screen Shot 2017-12-15 at 23.15.20.png" src="https://qiita-image-store.s3.amazonaws.com/0/214716/7c6157b3-561f-c3f5-3c9f-e8a2c2c00d70.png">

### ここまでのまとめ

ここまでで以下のことが出来るようになりました。

- 1 時間に 1 回自動的に Lambda 関数が実行される
- 環境変数で定義した情報を使って Lambda 関数は Cisco Meraki から情報を取得する
- Cisco Meraki から取得した情報をもとにニュース記事を作成して Amazon S3 に保存する
 
以上の流れによって、[インターネットからアクセスできる `news.json`](#45-動作確認) にネットワークの状況がニュース記事として保存され、1 時間に 1 回更新されることになります。

## Alexa でニュース記事を読み上げる
### 前提
Alexa を使うために Amazon Echo があると便利ですが、[Echosim](https://echosim.io) や [Alexa Voice Service](https://developer.amazon.com/ja/alexa-voice-service) を利用することもできます。それぞれの使い方についてはこの記事では触れません。

Amazon Echo のログインに使っている Amazon アカウントを使って [アマゾン アプリ 開発者ポータル](https://developer.amazon.com/edw/home.html) にログインできる必要があります。

### 1. Alexa スキルの作成

アマゾン アプリ 開発者ポータルから [Alexa → Alexa Skills Kit → 新しいスキルを追加する](https://developer.amazon.com/edw/home.html#/skill/create/) を開いてウィザードに従ってスキルを作成します。

<img width="667" alt="Alexa スキル - スキル情報の入力" src="https://qiita-image-store.s3.amazonaws.com/0/214716/cac61ee8-a5c9-016c-87e3-ad14981aa996.png">

フィード（ニュース記事の情報源）を追加する画面では [Lambda 関数の動作確認](#45-動作確認)でメモしておいた `news.json` の URL を入力します。

<img width="1011" alt="Alexa スキル - フィードの設定" src="https://qiita-image-store.s3.amazonaws.com/0/214716/a192327a-2032-2598-1a7c-d93b7aef4333.png">

### 2. Alexa スキルの有効化

スマートフォンで Alexa アプリを開くか、[Web ページ](https://alexa.amazon.co.jp/spa/index.html#skills/your-skills/?ref-suffix=ysa_gw) を開いて、自分の Alexa で有効になっているスキルを確認します。

![Alexa スキル - 有効なスキルの一覧](https://qiita-image-store.s3.amazonaws.com/0/214716/4770c535-1c12-6663-03a3-cd2ffed9c9f2.jpeg)

先ほど作成したスキルが勝手に登録されているので、スキルを開いて有効にします。

![Alexa スキル - スキルの有効化](https://qiita-image-store.s3.amazonaws.com/0/214716/2197fdc1-025e-9266-8319-9c8c8e69860b.jpeg)

以上ですべての準備は終了です！

# まとめ
- ネットワークは問題が起こってから何かをアクションを取ることが多いですが、**朝のニュース感覚**でネットワークの状況を知ることができます
    - Meraki はネットワークの状況を表示する [Public Status Page](https://documentation.meraki.com/MR/Monitoring_and_Reporting/Using_the_Dashboard_XML_API_or_Public_Status_Page) 機能がありますが、手軽さが段違いです
- 今回は Alexa が一方的に喋るだけですが、会話によってネットワークを操作できると便利かもしれないですね
    - 声を使ってネットワークを操作する例は [Cisco Systems Japan Advent Calendar 2017 の 11 日目](https://qiita.com/kikuta1978/items/12f9ef8c5f7a64652b12#%E3%81%BE%E3%81%A8%E3%82%81) にあります 
    - 「Alexa, 〜会議室のネットワークをゲスト用に設定して」「Alexa, 今から〜の端末で重要なビデオ会議を始めるよ」

# 参考
- [Cisco DevNet](https://developer.cisco.com/): API や SDK をはじめとした技術情報や、イベント情報が公開されています
- [Alexa Skills Kit フラッシュブリーフィングスキル API について](https://developer.amazon.com/ja/docs/flashbriefing/understand-the-flash-briefing-skill-api.html)

# 免責事項
本サイトおよび対応するコメントにおいて表明される意見は、投稿者本人の個人的意見であり、シスコの意見ではありません。本サイトの内容は、情報の提供のみを目的として掲載されており、シスコや他の関係者による推奨や表明を目的としたものではありません。各利用者は、本Webサイトへの掲載により、投稿、リンクその他の方法でアップロードした全ての情報の内容に対して全責任を負い、本Web サイトの利用に関するあらゆる責任からシスコを免責することに同意したものとします。