DigdagのSecret機能を使う

Digdagシリーズその２。

前回は[「Digdag Serverのインストール手順」](http://qiita.com/bwtakacy/items/ec3151644512ca65f6b6)

DigdagにはDBの接続パスワードやWebサービスのAPI Keyなどの情報をセキュアに扱う機能としてsecretというものがある。これを使うと、パスワードなどの情報が平文でワークフロー定義ファイルに書く必要がなくなるし、ログに平文で出力されることもなくなる。

## Digdag Secret機能を有効化する。

デフォルトでは無効になっている。
有効にするには、設定ファイルに

* digdag.secret-access-policy-file : operatorごとのsecretへのアクセスポリシーを定義したファイル
* digdag.secret-encryption-key: secretをDigdag ServerがDBに保存する時に暗号化するキー。128bitのAES鍵をBASE64エンコードした文字列を指定する。

を記載してDigdag Server起動時に読み込ませる必要がある。

```yaml
digdag.secret-access-policy-file = secret-access-policy.yaml
digdag.secret-encryption-key = MDEyMzQ1Njc4OTAxMjM0NQ==
```

secret-access-policy-fileは以下のような記述形式を採る。

```yaml
# secret-access-policy.yaml
operators:
  mail:
    secrets:
      - mail.*
  pg:
    secrets:
      - pg.*
  s3_wait:
    secrets:
      - aws.*
  td:
    secrets:
      - td.*
  td_load:
    secrets:
      - td.*
  td_for_each:
    secrets:
      - td.*
  td_run:
    secrets:
      - td.*
  td_ddl:
    secrets:
      - td.*
  td_partial_delete:
    secrets:
      - td.*
  td_table_export:
    secrets:
      - td.*
      - aws.*
  td_wait:
    secrets:
      - td.*
  td_wait_table:
    secrets:
      - td.*
```

例えば1つ目のセクションは、mailオペレータは`mail.`で始まるsecretにアクセスできる、という意味。

secret-encryption-keyには自分で決めた文字列をBASE64エンコードした値を記入すること。
上の値は公式ドキュメントに載っていて、`0123456789012345`というものを使ったケース。

注意するのは、**128bit=16byte**にする必要があるということ。

## secretを登録する

Secret機能を有効化したDigdag Serverに対して、クライアントからsecretを登録する。
登録には`digdag secrets`コマンドを使う。

```
$ digdag secrets --project examples --set sh.key1
2016-12-13 22:38:52 +0900: Digdag v0.8.22-SNAPSHOT
sh.key1:    ## ここでsecretの値を入力する
Secret 'sh.key1' set
```

`--project`オプションは必須である。つまり、secretの値はプロジェクトごとに定義することになる。

## ワークフローからSecretを使う

オペレータごとに自動で使ってくれるsecretがある。
詳細は、[公式ドキュメント](http://docs.digdag.io/operators.html)を参照のこと。

例えば、Treasure Dataにクエリを投げる`td>:`オペレータは`td.apikey`というsecretを登録しておけばTDアクセスのAPI KEYとして使ってくれる。
PostgreSQLにクエリを投げる`pg>:`オペレータは`pg.password`というsecretを登録しておけばPostgreSQLサーバに接続する際のパスワードとして使ってくれる。

しかし、Embulk経由でDBに接続したい場合は上記の方法は使えない。
なぜなら、Embulkを実行する`embulk>:`オペレータは自動で利用するsecretを持たないからである。

## Embulkにsecretを渡す

そこで、シェルスクリプトを実行する`sh>:`のドキュメントには書かれていない機能を使う。
`sh:>`オペレータには、`_env`オプションで記述したsecretをシェルの環境変数にセットしてくれる機能がある。

具体的には、ワークフロー定義にて

```
# echo_secret.dig
+echo:
  _env:
    FOO:
      secret: sh.key1
  sh>: echo $FOO
```

とすると、`sh.key1`というsecretに登録された値を`FOO`環境変数にセットした上で、`sh>:`オペレータに記述したコマンドが実行される。


なお、上記を行うにはsecret-access-policy-fileにて`sh>:`オペレータに`sh.key1`へのアクセスを許可しておく。

```yaml
operators:
  sh:
    secrets:
      - sh.*
```

この機能を使うと、ワークフロー定義で

```
+ task
  _env:
    PASSWORD:
      secret: sh.mysqlpass
    APIKEY:
      secret: sh.tdapikey
   sh>: password=$PASSWORD apikey=$APIKEY embulk run ...
```

としておき、Embulkの設定ファイルで

```
password: "{{env.password}}"
```

として環境変数の値を利用するようにしておけばよい。

### Digdag 0.9.0以降

ワークフロー定義ファイルでのsecretの参照方法が少し変化している。

```
+echo:
  _env:
    FOO: ${secret:key1}
  sh>: echo $FOO
```

というようにすればよい。

### Digdag 0.9.3以降

コメントで教えていただいたように0.9.3からは環境変数としてsecretsをワークフロー内でいちいち定義しなくても `sh>:` オペレータでsecretを参照できるようになったようです。
しかも、`sh>:` だけはsecret-access-policy-fileに事前にsecretsを明示的に設定しなくても自動でアクセスできるようになる様子。

動作確認は`0.9.17-SNAPSHOT` (5d235dc9d281d2d50f6a2193ad2a312ec51d18ca)にて実施。

```yaml
+echo:
  sh>: echo foo=${secret:foo} bar=${secret:nested.bar}
```

詳細は以下のコミット。
https://github.com/treasure-data/digdag/commit/79665b1758ff670cc54306654b1d369e66f25710#diff-edc7ac16f0cc1279406406c430f3d25d

以上。



## 参考

* [digdag serverをシークレットモードで動かす。](http://qiita.com/oqrusk/items/ab91543d6bde79d9f143)