Webhook as a ServiceでIoTのserverlessなバックエンド考える - Part 3: Webtask.ioでIDCFクラウド APIのセキュアな情報を扱う

　MicroServicesの関数内の処理では別のMicroServicesのAPIを実行することが多くなります、serverlessなバックエンドにWebtask.ioを例にして、API Keyなどセキュアな情報を安全に扱う方法を見ていきます。Webtask.ioではwebtask tokenに埋め込む方法と、webtaskの作成時に埋め込む方法の2つがあります。今回は[IDCFクラウド](http://www.idcf.jp/cloud/)のAPI KeyとSecret Keyのセキュアな情報を安全に管理しようと思います。

　マイクロサービスをDIできてワークフローを管理できる良いフレームワークを探しています。コンテナのステートレスとかステートフルとかサービスディスカバリとかEJBとSpringの夢の続きを見ているみたい。


## このシリーズ

* [Webhook as a ServiceでIoTのserverlessなバックエンド考える - Part 1: リソース](http://qiita.com/masato/items/ecc786a9703c314844e3)
* [Webhook as a ServiceでIoTのserverlessなバックエンド考える - Part 2: Webtask.ioのHello world](http://qiita.com/masato/items/5689238a4d90cfd8a307)


## Webtask tokenにセキュアな情報を埋め込む

　webtask tokenはwebtask cluster内の操作を認可するときに使います。技術的には[JWT](https://jwt.io/)のtokenです。BLOBなので指定した文字列から中身はわかりませんが詳細なパーミッションの情報を含んでいます。JWT tokenのクレームとして以下の制約を定義できます。

参考

* [Taxonomy of a Webtask Token](https://webtask.io/docs/token)

### pctx

　`pctx`のプロパティはwebtaskのコードから実行時にパラメーターから利用できます。署名で保護されていますが暗号化されていないので、webtask tokenから中身の文字列を知ることができます。

### etcx

　一方の`etcx`は`pctx`と違い暗号化されます。データベースの接続文字列やAPI Keyなどセキュアな情報をwebtask tokenに埋め込み、安全にwebtask codeに渡すことができます。


### 使い方

　以下の例は`etcx`プロパティに暗号化したセキュアな情報を埋め込んだwebtask tokenを作成します。このwebtask tokenは`url`プロパティから参照するwebtask codeのコードの実行に用途を限定されます。`etcx`プロパティはwebtask codeの実行時に復号化されて`context.data`に渡されます。

することに限定したwebtask tokenを作成します。

```
$ export PARAMETERIZED_TOKEN=$(curl -s https://webtask.it.auth0.com/api/tokens/issue -H "Authorization: Bearer eyJhbxxx" \
  -H "Content-Type: application/json" \
  --data-binary '{"url":"http://bit.ly/1wT1DOi","ectx":{"secret":"abc!123"}}')       
```

参考

* [Passing Secrets to Webtask Code](https://webtask.io/docs/issue_parameters)
* [Programming model](https://webtask.io/docs/model)


## Webtaskにセキュアな情報を埋め込む

　`wt create`コマンドに`--secret {key}={value}`フラグをつけるとAES256-CBCで暗号化された`secret`を作成します。`--secret MONGO_URL=xxx`のように指定すれば、webtask codeに渡される`context.data`から利用できます。

```js：mongodb.js
module.exports = function(context, cb) {
    var MONGO_URL = context.data.MONGO_URL;
```

### 使い方


　webtaskを作成するときはローカルのファイル以外に、パブリックにアクセスできるURLからNode.jsのコードを指定することもできます。この例ではGitHubのリポジトリから直接コードを読み込みます。`--secret`フラグに[MongoLab](https://mongolab.com/)が提供するMongoDBの接続文字列を指定しています。

```bash
$ wt create https://raw.githubusercontent.com/auth0/wt-cli/master/sample-webtasks/mongodb.js \
  --name mongo \
  --secret MONGO_URL=mongodb://webtask:supersecret@ds047592.mongolab.com:47592/webtask-examples
```

参考

* [Getting Started](https://webtask.io/docs/101)


## IDCFクラウド API

　IDCFクラウド APIはクエリ文字列から署名 (signature)を作成して認証に使います。`signature`は元になったクエリ文字列に追加てリクエストします。Pythonを使った署名の作成方法は[CloudStackのドキュメント](http://docs.cloudstack.apache.org/en/latest/dev.html#how-to-sign-an-api-call-with-python)にありますが、今回はNode.jsで書いてみました。

```js:startstop.js
'use strict';

var crypto = require('crypto'),
    request = require('request'),
    querystring = require('querystring');

function buildSignature(query, secretKey) {
    var message = querystring.stringify(query)
        .split('&')
        .map(function(q){ return q.toLowerCase() })
        .sort()
        .join('&');
    return crypto.createHmac('sha1', secretKey)
        .update(message)
        .digest('base64');
};
```


## 仮想マシンを開始と停止するサンプル

　webtaskの作成にはローカルのファイルからwebtaskを作成する方法と
GitHubのリポジトリなどの公開URLのコードを指定する方法がありますが、今回はローカルのファイルを使います。上記の関数を含むコードの続きです。`--secret`を使う場合もJWT tokenの`etcx`を使う場合も、webtask codeでは同じように`context.data`に渡されます。

　`module.exports`で公開する関数では`signature`を作成と、仮想マシンをstart/stopするAPIの実行を実装します。

```js:startstop.js
module.exports = function(context, cb) {
    var query = {
        apiKey: context.data.apikey,
        response: 'json',
        command: context.data.command+'VirtualMachine',
        id: context.data.id
    }

    query.signature = buildSignature(query, context.data.secretkey);

    request.get({
        url: context.data.endpoint,
        qs: query,
        json: true
    }, function (error, response, body) {
        cb(null, body);
    });
};
```

　`context.data`のプロパティは以下の方法で渡されます。

* apikey: IDCFクラウドのAPI Key
* secretkey: IDCFクラウドのSecret Key
* endpoint: IDCFクラウドのエンドポイント
* command: [start|stop]VirtualMachineコマンドになるprefixを指定
* id: 操作対象の仮想マシンのid、クラウドコンソールの仮想マシン基本設定から確認

### 使い方

　`command`と`id`プロパティ以外は、`wt create`コマンドでwebtaskを作成するときに`--secret`フラグをつけて暗号化して埋め込みます。[Webtask CLI](https://github.com/auth0/wt-cli)をインストールした環境で実行します。

```bash
$ wt create startstop.js \
  --name startstop \
  --secret apikey=xxx \
  --secret secretkey=xxx \
  --secret endpoint=xxx 
```

　以下のようなWebhookの戻り値が出力されます。

```bash
https://webtask.it.auth0.com/api/run/{コンテナ名}/startstop?webtask_no_cache=1

```

　webtaskを実行するWebhookのURLのクエリ文字列として、`command`と`id`プロパティは動的に追加します。IDCFクラウドのアカウント所有者がwebtaskを作成して自分の仮想マシンを動的にWebhookから開始と停止をできるユースケースを想定しています。

　仮想マシンを停止する場合は以下のダブルクォートで囲んだURLを実行します。デフォルトのkeyは`~/.webtask`の`token`フィールドを確認します。

```bash
$ curl "https://webtask.it.auth0.com/api/run/{コンテナ名}/startstop?webtask_no_cache=1&key={デフォルトのkey}&command=stop&id={仮想マシンのID}"
```

　webtaskの実行に成功するとCloudStackからjobidか返ります。

```bash
{"stopvirtualmachineresponse":{"jobid":"ad52d24e-xxx"}}
```

　クラウドコンソール画面で確認すると仮想マシンの停止が始まりました。

<img width="512" alt="vm-stop.png" src="https://qiita-image-store.s3.amazonaws.com/0/43745/2bbeefc7-ebc0-e68a-f4eb-711f9824ca4a.png">



　仮想マシンを開始する場合は`command`プロパティを`start`にします。


```bash
$ curl "https://webtask.it.auth0.com/api/run/{コンテナ名}/startstop?webtask_no_cache=1&key={デフォルトのkey}&command=start&id={仮想マシンのID}"
```