Vault provider by Terraform v0.8

terraform 0.8がリリースされました。

幾つかの新機能が追加さました!!!その中でVaultとの連携を試してみます。

が、うまく動きませんでした。orz できた。✨ → Read access key from Vault with Terraform

やったところまで書く。

Vault providerが提供する2つの機能

vault providerが提供する機能は2つあります。

  • terraformからvaultそのものを変更する機能(新しいkey/valueの追加とか)
  • vaultから機密情報をreadし、terraformで使う機能(シークレットキーを取得したりとか)

注意事項

vaultと連携することによって、より便利にterraformが使えるようになりましたが、それぞれ以下のようなセキュリティ上のトレードオフがあるのでよく考慮した上で導入すること。とのこと。

  • vaultに変更を加える(機密情報の追加とか)場合は、terraformの設定ファイル内にその値を書くことになる
  • vaultから値(機密情報)を読んで使う場合、場合によってはapplyしたときterraformの標準出力にその値が見えてしまうかもしれない
  • tfstateは暗号化されていないので、機密情報が平文で保持されてしまうかもしれない

tfstateは特にあんまり意識しなかったりするので気をつけねば。

ドキュメントは以下。

Vaultから機密情報を取得してterraformで使う方法

データソースとしてvaultが使えるようになる、ということみたいです。

今回はdigitaloceanのproviderの設定で、トークンを指定する部分をvaultに置き換えてみようと思います。

基本的なdigitaloceanのproviderの設定は以下のような形式です。

  • do_tokenという変数に環境変数やterraform.tfvarsで定義したトークンが入る設計
provider "digitalocean" {
    token = "${var.do_token}"
}

これが以下のようにvaultから読み込む設計に出来る、というイメージです。

provider "digitalocean" {
    token = "${data.vault_generic_secret.digitalocean.data["token"]}"
}

やってみる

やってみます。まずvaultにアクセスできるように、以下の環境変数を設定しておきます。

export VAULT_ADDR="https://YYYYYYYY"
export VAULT_TOKEN="ZZZZZZZZ"

次にvaultにdigitaloceanのトークンを追加します。

vault write secret/digitalocean token="XXXXXXXX"

適当なmain.tfを作成します。

data "vault_generic_secret" "test" {
  path = "secret/digitalocean"
}

provider "digitalocean" {
  token = "${data.vault_generic_secret.test.data["token"]}"
}

resource "digitalocean_ssh_key" "test" {
  name       = "Test Key"
  public_key = "hogehoge"
}

早速実行してみると...。

おっと!ここでなぜかoptionalなはずのvault providerの変数を要求されてしまいました。

$ terraform plan
provider.digitalocean.token
  The token key for API operations.

  Enter a value:
provider.vault.ca_cert_file
  Path to a CA certificate file to validate the server's certificate.

  Enter a value:

issueが上がっていて、-input=falseを指定することで回避できるとのこと。

気を取り直して実行。

$ terraform plan -input=false
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but
will not be persisted to local or remote state storage.

data.vault_generic_secret.test: Refreshing state...

The Terraform execution plan has been generated and is shown below.
Resources are shown in alphabetical order for quick scanning. Green resources
will be created (or destroyed and then created if an existing resource
exists), yellow resources are being changed in-place, and red resources
will be destroyed. Cyan entries are data sources to be read.

Note: You didn't specify an "-out" parameter to save this plan, so when
"apply" is called, Terraform can't guarantee this is what will execute.

<= data.vault_generic_secret.test
    data.%:           "<computed>"
    data_json:        "<computed>"
    lease_duration:   "<computed>"
    lease_id:         "<computed>"
    lease_renewable:  "<computed>"
    lease_start_time: "<computed>"
    path:             "secret/digitalocean"

+ digitalocean_ssh_key.test
    fingerprint: "<computed>"
    name:        "Test Key"
    public_key:  "hogehoge"


Plan: 1 to add, 0 to change, 0 to destroy.

よさそう☆

apply。

$ terraform apply -input=false
data.vault_generic_secret.test: Refreshing state...
data.vault_generic_secret.test: Refreshing state...
Error applying plan:

1 error(s) occurred:

* Resource 'data.vault_generic_secret.test' does not have attribute 'data' for variable 'data.vault_generic_secret.test.data'

Terraform does not automatically rollback in the face of errors.
Instead, your Terraform state file has been partially updated with
any resources that successfully completed. Please address the error
above and apply again to incrementally change your infrastructure.

!!!???

dataアトリビュート指定してるし、公式ドキュメントでも上で書いたコードみたいな感じで使っているんだけどな...。ここで詰まり、結局わからなかったので一旦ここまで...。うまく出来た人が居たら教えてください。

$ terraform version
Terraform v0.8.0

感想

今回は失敗してしまいましたが、もしうまくvaultとterraformを連携させられたら、以下のような利点を享受できるのではないかと思っています。

これまで私は環境変数に機密情報を書いていました。terraformで扱う機密情報が多くなるにつれ、環境変数の管理が大変になってきました(アッ!このマシンのアクセスキー、前捨てたやつのままだ!とか)。

vaultで機密情報を管理することによって、vaultのトークン以外は環境変数に機密情報を書かなくて良くなりそうです。

また、vaultのAuthentication機能を使って、「terraformコマンドを使用するタイミングで1時間だけ有効なIAM(とアクセスキー)をGithub認証越しに動的に作成しapplyする」というようなことも可能になるかもしれません。

そうなればもはやIAMユーザの管理もいらなくなりそうです。例えば異動や退職イベントが発生したとしても、GitHubのチームから当該アカウントを外せばvaultにアクセスできなくなるし、以前使ったIAM(とアクセスキー)もその時使ったタイミングの1時間後に消滅しているからです。

うまく動かせたらまたメモしておこうと思います。

参考リンク