Amazon Dash ButtonをHackするのはJust do itでしょ、と思って手を出したら落とし穴にどハマった件

Exective Summary

そもそもやりたかったこと:

Amazon Dash Buttonを押して、AWS上の全EC2を停止する。
(利用料が個人レベルでない上に、お小遣いが少ないもので…)

前提・制約:

(甲) 我が家にはWindows10マシンしかない(Linuxマシンはない、という意味)。
(乙) 一方、AWS Dash ButoonをHackするツールとしては、Linux/OS X向けNode.js系ツールが主流らしい([1],[3],[5],[9])。
⇒Amazon Dash Buttonは、ボタンを押すとARPリクエストを送出(ブロードキャスト)する。それを同じLANで待ち受けて検知できるのがDasher。その検知をトリガーにして任意の処理(WebAPIを呼び出す、等)を起動できる。
(丙) 我が家にはAWS Dash Buttonが2つある。それは、購入商品の指定/設定を、
  (A) 意図的に途中でやめてあるモノ
  (B) 無邪気に最期まで完了した(知らずに済ませてしまった)モノ
  の2種類だ。
(丁) 呼び出されたら「全EC2を停止する」というAPIは、AWS IoT/API Gateway/Lambdaのサーバレスアーキで作成済み。
⇒世間の情報も豊富だし、小1時間程度でできるっしょーとたかをくくる。

俺的に考え得た・試した選択肢

①Windows10+Dasher・・・×
②Windows10+Bash on Windows+Dasher・・・×
③Windows10+Cygwin+Dasher・・・×
④Windows10+win-node-dash-button・・・×
⑤Windows10+Vagrant+VirtualBox+Ubuntu+Dasher・・・○
⑥Windows10+Docker-Machine+VirtualBox+Boot2Docker+Dasher・・・×
⑦Windows10+Docker-Machine+VirtualBox+Boot2Docker+Docker+Ubuntu+Dasher・・・未

紆余曲折の結果が…コレだ…ワン・ツー・スリー…

⑤Windows10+Vagrant+VirtualBox+Ubuntu+Dasher

学べる(学べた)コト

・Git
・node.js/npm/node-gyp/node_pcap
・python/pip
・Bash on Windows/Cygwin/Ubuntu
・Docker-Machine/Vagrant/VirtualBox
・Wireshark/tcpdump
・NW/ARP/DNS

嵐の後の所感

やってみた結果として、Amazon Dash Buttonは幅広く技術を体験するのに良いテーマだったという実感。
(「フェルマーの最終定理」と同じ構図?定理の意味の理解はトリビアルだが、その証明を理解するには色々な数学的知識が必要!)
次は『Dash Button(丙)-(B)』のHackを試みる…(方向性としては『DNSサーバをポジティブに偽装する』)
…まあ、AWS IoT Buttonが日本でも発売されたら、それを使うけどね…

俺が落ちた落とし穴の各論

以下、詳細:(細々と続く)

参考情報

[1] Amazon Dash ButtonをただのIoTボタンとして使う
[2] node-dash-button@GitHub
[3] Amazon Dashボタンのハックにおける期待と落胆(Wi-Fi編)
[4] dasher@GitHub
[5] Amazon Dash Buttonを(正しくない方向で)使ってみた
[6] Dash Button for Node@GitHub
[7] node_pcap
[8] node_pcapのWindows7対応Folk
[9] win-node-dash-button
[10] Windowsでnpm installしてnode-gypでつまずいた時対処方法
[11] これはすごい!分解とパケット解析で分かったAmazon Dash Buttonの「本気度」
[12] これはすごい!Amazon Dash Buttonをプレゼンに使う
[13] これはすごい!Amazon Dash Buttonでツイートできた

続きを読む

初心者がどハマりしたAWS IoTのRuleの概要と使い方まとめ

AWS IoT使ってますか!

Webコンソールが分かりづらかったり新UIになったりで、
まだまだ黎明期感を感じるAWS IoTですが、最近ようやく僕もはじめました。
ただ毎回何かやる度にハマって学んでを繰り返してる感じで、
毎日ぐぬぬってなってます(でもこういう感覚っていいですよね!)。

で、今回もRuleっていう概念をお勉強してハマったんですが、
せっかくなのでハマったことも含めて概要とか使い方まとめてみました。
僕みたいな誰かの役に立てれば幸いです:sweat_smile:

まずAWS IoTのRuleとは!

AWS IoT内の指定したTopicに更新があった場合に、
LambdaやSNSなど外部のサービスをキックすることができるAWS IoTの重要なサービス!

例えば予め指定したデバイスShadowのTopic更新を受けて、
それを元にLambdaでクラウド側にデータを保存したり、
Shadowを再更新してあげたりなどいろいろできます。

正直このRuleを上手く使えないとAWS IoTで出来ることが全然広がりません :joy:

作ってみよう

と思ってCreateボタンを押してみてもぱっと見何がなんだかわかりません。
この初心者殺しめっ!!:knife:

ので、メモも兼ねて解説していきます。

Description

まぁただの説明なので省略

Using SQL version

一番新しいものを使えばいいと思います。

Rule query statement

ここに、これより下の欄で設定した結果が表示されます。
最終的には以下のようになりました。 ※可読性の為改行しています。

RuleQueryStatementの例
SELECT { "payload": *, "topicName": topic() } 
  FROM '$aws/things/+/shadow/update/accepted' 
  WHERE 
    indexof(topic(), '_foo_bar_baz_') > 0

細かい説明は下記で。

の前にまずは心構え

* はペイロード!

SQLでいうところのSELECT句の値となる場所にある * ですが、
AWS IoTのRuleだとこれは特別な意味を持っています。

非常に分かり辛いですが、 * だけだとTopicのペイロードがそのまま入ってくる感じで、
例えばSELECT句にこの * だけが指定されたRuleからLambdaがキックされた場合、
Lambda側で受け取れる event オブジェクトの中身はそのままTopicのペイロードと同一になります。

そして後述しますが、このSELECT句にはJSON形式でも記述できたりするので、
ペイロードそのものも、JSON内の1要素として扱うことができます。

関数を駆使する

正直 * でペイロードだけ取得するのでは若干情報が足りず扱いづらいです。
例えばそのRuleが実行されるにあたって、条件にマッチした複数のTopicから
どのTopicが呼んだものなのかを判別したりをペイロードの内容からだけでは実現できません。

そこでAWSが予め用意している便利な関数群があるので、これを使います。
先の例では topic() などがそうですね。これを利用すると、実際に実行されたトピック名を取得できるので、
ここから後でthing名なども抜き出すことができます。

ちなみにこの関数ですが下記にまとまっています。
但し、 日本語ページにはない情報が結構あります ので、必ず英語ページから探しましょう(めちゃくちゃハマりました…)。

Attribute

SELECT句の値となる場所です。
上記心構えでも説明しましたが、 * だとTopicのペイロードがそのままきます。
JSON形式での記述もでき、下記のような感じで書くことができます。

Attributesの例
{ "payload": *, "topicName": topic() }

先ほど利用した関数 topic() が使われていますね。
上記で実際にキックされたLambdaで event オブジェクトに入ってくる値が下記のようになります。

eventオブジェクトの中身
{
  payload: {
    state: {
      reported: { ... },
      desired: { ... },
      delta: { ... },
    }
  },
  topicName: '$aws/things/dev_foo_bar_baz_topic/shadow/update/accepted'
}

ペイロードが payload , トピック名が topicName というキーでラップされてちゃんとすべて渡されてきましたね! :thumbsup::sparkles:

Topic filter

ここで、どのトピックを対象にするのかの基本的な条件をMQTTのEndpointで指定します。
このEndpointは例えばデバイスシャドウなら各Thingの Interact -> MQTT 内で見つけられます。

TopicFilterの例
$aws/things/+/shadow/update/accepted

上記でも利用していますが、MQTTのTopic名には、MQTT専用のワイルドカードが利用できます。
# で前方一致、 + で部分一致という意味で、組み合わせも可能ですが、
文字列の途中で突然 + と使うことはできず / の区切りでのみ有効なことに注意しましょう( hoge+fuga みたいなのはダメ)。

Condition

上記TopicFilterだと、すべてのデバイスシャドウの update/accepted に対して反応してしまいます。
複数のプロダクトとかを1つのAWSアカウントで作成している時や、
その更新に対して関係ないデバイスに対しても一々反応して欲しくないですよね。
そこでConditionを書くと、ちょうど最初の Rule query statement の項に書かれている
SQLの WHERE 句として挿入されます。

Conditionの例
indexof(topic(), '_foo_bar_baz_') > 0

そしてここでもここでも関数が活躍しています。

indexof() は、第一引数で指定した文字列(カラム名ならその値)から、第二引数で指定した文字を検索し、
そのマッチしたIndexを返すというよくあるindexOf関数ですが、これを先ほどの topic() と組み合わせることで、
このRuleのトリガーとなったトピック名に _foo_bar_baz_ の名前が含まれている場合のみ、
Ruleを実行するというようなことが書けるようになります。便利ですね! :sparkles:

まとめ

正直これらの機能をフル活用しないとまともなRuleが書けない割に、
意外とまだWebに情報が転がってないので、
辛く厳しいAWSドキュメントの海を彷徨わないとなかなか正解に辿りつけずげんなりします。

というわけで僕は少なくとも最初にハマったのでメモとして残しておきます!

僕らのAWS IoTとの戦いはまだ始まったばかりだ…!! :boom::muscle:

続きを読む

クラウドサーバー Amazon EC2 を起動するだけのリアルボタンを作ってみた ~仮想と現実の新たな接点

AWSはクラウドサービスですが「AWS IoT Button」という物理的なボタンのサービスもあります。この AWS IoT Button は、AWSクラウド上の AWS IoT に対して … 続きを読む

BLEゲートウェイとSORACOMとAWSを使ってデータ収集基盤を作ってみた

IoTにおけるデータ収集基盤の構成は「AWS IoTで受けて、Kinesis Firehoseを経由してRedshiftやElasticsearch Serviceに溜める」といった構成がよく採られてい … 続きを読む