SORACOM Beamでコマンドの実行結果を雑だけどセキュアに送信する #soracom

2015.10.06

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

[2015/10/06 16:00更新]
BeamのTCP→HTTP/Sに仕様変更があり、転送されるHTTPリクエストが変わったため実行結果を訂正しました。

ども、大瀧です。

皆さん、SORACOM触ってますか?Air SIMに目が行きがちですが、IoTプラットフォームとしての利用であればプロキシサービスのBeamも検討するべき要チェックサービスですよ!

さて、IoTデバイスからクラウドへのデータ送信を考えるとき、必ず検討するのがフォーマットとプロトコルでしょう。互換性の高さからHTTPにするか、IoT向けということでMQTTにするか要件によって目移りするところだと思います。ただ、プロトコルによっては専用のクライアントライブラリが必要だったり、フォーマットの整形にあまりコンピュータリソースが割けない場合もあるのではないでしょうか。

そこで今回は、ncユーティリティを用いてコマンドの実行結果(標準出力)をBeam経由で"雑だけどセキュア"に送信する構成をご紹介します。

構成の概要

図で示すと以下の通りです。Beamには、TCPで送信されるテキストデータをHTTPないしHTTPSに変換しバックエンドのWebサーバーに転送する機能があるのでこれを利用します。今回はデータ送信先のクラウドとしてAWS環境を用いて、Beam-AWS(ELB)間はTLS暗号化を施します。

beam-stdout01_1

AWSの構成

BeamからのHTTPリクエストは特別なものではないため、任意のHTTP/HTTPSサーバーで受信できます。今回はELB+EC2で試してみました。Beamは自己署名証明書など不正なTLS通信を遮断するため、ELBではSSLターミネーションとともに有効な証明書と対応するDNS構成を準備しておきます。

beam-stdout02

EC2インスタンスでは、ApacheやNginxなど一般的なWebサーバーやアプリケーションサーバーを用いるところですが、今回はBeamが送信するHTTPリクエストをダンプするためにこちらの記事を参考にnc -lを実行してみます。

[ec2-user@ec2 ~] $ while true; do ( echo "HTTP/1.0 200 Ok"; echo; echo "Hello World" ) | sudo nc -l 80; done

Beamの構成

続いてBeamの構成です。Beamの中継設定はSIMグループに設定するため、グループが未作成の場合は任意のグループ名で作成しておきます。

グループの設定画面を開き、[+] - [TCP → HTTP/HTTPSエントリポイント]を選択します。

beam-stdout03

任意の設定名を入力し、[プロトコル]を「HTTPS」、[ホスト名]にELB Endpointに設定したDNS名、[ポート番号]は空のまま、[パス]に「/」をそれぞれ入力します。Beam側のエントリポイントはこのあとnc実行時に指定するので控えておきましょう。

beam-stdout04

[パラメータ操作]の部分は、今回の例では特に利用しませんが動作確認のためにそれぞれ有効化してみました。

beam-stdout05

これでOKです。

beam-stdout06

動作確認

それでは、SORACOM Air SIMを搭載したデバイスからデータを送信してみます。任意のコマンドをncにパイプラインで繋ぎ、Beamのエントリポイントにデータを送信します。

デバイスのターミナル

vagrant@debian-wheezy:~$ cat /proc/cpuinfo | nc beam.soracom.io 23080
^C
vagrant@debian-wheezy:~$

nc -lを実行しているEC2のターミナル

POST / HTTP/1.1
host: XXXX.XXXX.XXXX
accept: application/json
content-type: application/json
User_Agent: SORACOM Beam
X_SORACOM_IMSI: XXXXXXXXXXXXXXX
X_SORACOM_SIGNATURE: 906ac66b2440284100d9cbfa325ca9c75f0a32065218656125399f9556c07b7c
X_SORACOM_SIGNATURE_VERSION: 20150901
X_SORACOM_TIMESTAMP: 1444114620657
X-Forwarded-For: XX.XX.XX.XX
X-Forwarded-Port: 443
X-Forwarded-Proto: https
Content-Length: 898
Connection: keep-alive

{"payload":"cHJvY2Vzc29yCTogMAp2ZW5kb3JfaWQJOiBHZW51aW5lSW50ZWwKY3B1IGZhbWlseQk6IDYKbW9kZWwJCTogNjEKbW9kZWwgbmFtZQk6IEludGVsKFIpIENvcmUoVE0pIE0tNVk3MSBDUFUgQCAxLjIwR0h6CnN0ZXBwaW5nCTogNAptaWNyb2NvZGUJOiAweDE5CmNwdSBNSHoJCTogMTI5OS45NTcKY2FjaGUgc2l6ZQk6IDQwOTYgS0IKZnB1CQk6IHllcwpmcHVfZXhjZXB0aW9uCTogeWVzCmNwdWlkIGxldmVsCTogMjAKd3AJCTogeWVzCmZsYWdzCQk6IGZwdSB2bWUgZGUgcHNlIHRzYyBtc3IgcGFlIG1jZSBjeDggYXBpYyBzZXAgbXRyciBwZ2UgbWNhIGNtb3YgcGF0IHBzZTM2IGNsZmx1c2ggbW14IGZ4c3Igc3NlIHNzZTIgc3lzY2FsbCBueCByZHRzY3AgbG0gY29uc3RhbnRfdHNjIHVwIHJlcF9nb29kIG5vcGwgeHRvcG9sb2d5IG5vbnN0b3BfdHNjIHBuaSBwY2xtdWxxZHEgbW9uaXRvciBzc3NlMyBjeDE2IHNzZTRfMSBzc2U0XzIgbW92YmUgcG9wY250IGFlcyB4c2F2ZSBhdnggcmRyYW5kIGxhaGZfbG0gYWJtIDNkbm93cHJlZmV0Y2gKYm9nb21pcHMJOiAyNTk5LjkxCmNsZmx1c2ggc2l6ZQk6IDY0CmNhY2hlX2FsaWdubWVudAk6IDY0CmFkZHJlc3Mgc2l6ZXMJOiAzOSBiaXRzIHBoeXNpY2FsLCA0OCBiaXRzIHZpcnR1YWwKcG93ZXIgbWFuYWdlbWVudDoKCg=="}

^Z
[1]+  停止                  ( echo "HTTP/1.0 200 Ok"; echo; echo "Hello World" ) | sudo nc -l 80
[ec2-user@ec2 ~] $

来ました!Beamからのリクエストが以下になっていることがわかりますね。

  • HTTPメソッド : POST
  • Content-Type : application/json
  • IMSI : X_SORACOM_IMSIヘッダ
  • 署名 : X_SORACOM_SIGNATUREヘッダ
  • タイムスタンプ : X_SORACOM_TIMESTAMPヘッダ
  • 送信データ : JSONのpayloadキーの値としてBASE64エンコードされた文字列

サーバーサイドのロジックで、問題無くパースできそうな感じですね。あとは煮るなり焼くなり活用できると思います。IMSIはSIM固有のIDですので、以前のエントリーでご紹介したデバイス認証に利用しても良いでしょう。念のため、payloadの文字列をbase64コマンドでデコードしてみます。

$ echo 'cHJvY2Vzc29yCTogMAp2ZW5kb3JfaWQJOiBHZW51aW5lSW50ZWwKY3B1IGZhbWlseQk6IDYKbW9kZWwJCTogNjEKbW9kZWwgbmFtZQk6IEludGVsKFIpIENvcmUoVE0pIE0tNVk3MSBDUFUgQCAxLjIwR0h6CnN0ZXBwaW5nCTogNAptaWNyb2NvZGUJOiAweDE5CmNwdSBNSHoJCTogMTI5OS45NTcKY2FjaGUgc2l6ZQk6IDQwOTYgS0IKZnB1CQk6IHllcwpmcHVfZXhjZXB0aW9uCTogeWVzCmNwdWlkIGxldmVsCTogMjAKd3AJCTogeWVzCmZsYWdzCQk6IGZwdSB2bWUgZGUgcHNlIHRzYyBtc3IgcGFlIG1jZSBjeDggYXBpYyBzZXAgbXRyciBwZ2UgbWNhIGNtb3YgcGF0IHBzZTM2IGNsZmx1c2ggbW14IGZ4c3Igc3NlIHNzZTIgc3lzY2FsbCBueCByZHRzY3AgbG0gY29uc3RhbnRfdHNjIHVwIHJlcF9nb29kIG5vcGwgeHRvcG9sb2d5IG5vbnN0b3BfdHNjIHBuaSBwY2xtdWxxZHEgbW9uaXRvciBzc3NlMyBjeDE2IHNzZTRfMSBzc2U0XzIgbW92YmUgcG9wY250IGFlcyB4c2F2ZSBhdnggcmRyYW5kIGxhaGZfbG0gYWJtIDNkbm93cHJlZmV0Y2gKYm9nb21pcHMJOiAyNTk5LjkxCmNsZmx1c2ggc2l6ZQk6IDY0CmNhY2hlX2FsaWdubWVudAk6IDY0CmFkZHJlc3Mgc2l6ZXMJOiAzOSBiaXRzIHBoeXNpY2FsLCA0OCBiaXRzIHZpcnR1YWwKcG93ZXIgbWFuYWdlbWVudDoKCg==' \
  | base64 -D
processor	: 0
vendor_id	: GenuineIntel
cpu family	: 6
model		: 61
model name	: Intel(R) Core(TM) M-5Y71 CPU @ 1.20GHz
stepping	: 4
microcode	: 0x19
cpu MHz		: 1299.957
cache size	: 4096 KB
fpu		: yes
fpu_exception	: yes
cpuid level	: 20
wp		: yes
flags		: fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 syscall nx rdtscp lm constant_tsc up rep_good nopl xtopology nonstop_tsc pni pclmulqdq monitor ssse3 cx16 sse4_1 sse4_2 movbe popcnt aes xsave avx rdrand lahf_lm abm 3dnowprefetch
bogomips	: 2599.91
clflush size	: 64
cache_alignment	: 64
address sizes	: 39 bits physical, 48 bits virtual
power management:
$

いい感じですね。

また、以下のように標準出力が複数回出力される場合Beamはその出力ごとにHTTPリクエストを分けてバックエンドに転送してくれるので、tail -f / tailfのようなコマンドの連続実行にもうまく対応してくれるようです。

vagrant@debian-wheezy:~$ while true;do echo a;sleep 5; done | nc beam.soracom.io 23080
^C
vagrant@debian-wheezy:~$

あと恐らくマルチバイトの扱いは不得意だと思うので、デバイス側のロケール設定などに注意しましょう。

まとめ

ncユーティリティとBeamのTCP→HTTPS変換を利用したコマンド実行結果のデータ送信手法をご紹介しました。クラウドに手軽にデータを送る方法としていろいろ応用してみてください!