---
title: Concourse CIのVault連携メモ
tags: ["Concourse CI", "BOSH", "Vault"]
categories: ["Dev", "CI", "ConcourseCI"]
date: 2017-08-06T18:33:51Z
updated: 2017-08-10T14:05:35Z
---

**目次**
<!-- toc -->

Concourse 3.3で追加された[Credential Management](http://concourse.ci/creds.html)(Vault対応)を試す。

今まで、平文で管理されていた機密情報はようやくVaultサーバーで管理することができる。

今回は外部Vaultサーバーとして、[Cloud FoundryにデプロイしたVault](https://blog.ik.am/entries/423)を利用する。[Pivotal Web Services](https://run.pivotal.io)では月100円以下(無料期間あり)で管理できるのでおすすめ。

以下はこのVaultにログインした状態で始める。

> "Concourse"という呼び方が正しいが、タイトルではググラビリティ向上のために"Concourse CI"と書いている。

### Vaultの設定

Vaultとの連携方式は

* [AppRole](https://www.vaultproject.io/docs/auth/approle.html)
* [TLS](https://www.vaultproject.io/docs/auth/cert.html)
* [Token](https://www.vaultproject.io/docs/auth/token.html)

が用意されているが、今回はAppRoleを使用する。Tokenの方が設定が楽だけれど、AppRoleの方が推奨っぽい。

AppRoleもTokenも[Periodic Token](https://www.vaultproject.io/docs/concepts/tokens.html#periodic-tokens)にしないと、トークンの有効期限が切れるたびに設定し直しになるので注意。

#### AppRole認証の有効化

```
vault auth-enable approle
```

#### Concourse用のバックエンドをマウント

```
vault mount -path=/concourse -description="Secrets for concourse pipelines" generic
```

`vault mounts`でマウント一覧を確認

```
$ vault mounts
Path        Type       Default TTL  Max TTL  Force No Cache  Replication Behavior  Description
concourse/  generic    system       system   false           replicated            Secrets for concourse pipelines
cubbyhole/  cubbyhole  n/a          n/a      false           local                 per-token private secret storage
secret/     generic    system       system   false           replicated            generic secret storage
sys/        system     n/a          n/a      false           replicated            system endpoints used for control, policy and debugging
totp/       totp       system       system   false           replicated            
transit/    transit    system       system   false           replicated 
```

#### ポリシー適用

writeした値をConcourseがreadできるように次のポリシーファイル(`policy.hcl`)を作成

```
path "concourse/*" {
  policy = "read"
  capabilities =  ["read", "list"]
}
```

そして設定

```
vault policy-write concourse policy.hcl
```

#### AppRoleの作成

`concourse`ポリシーを適用する。

```
vault write auth/approle/role/concourse secret_id_ttl=10m token_num_uses=10 token_ttl=20m token_max_ttl=30m period=768h secret_id_num_uses=20 policies=concourse
```


#### Role IDの取得

```
vault read auth/approle/role/concourse/role-id
```

変数に代入したい場合は、

```
export ROLE_ID=`vault read auth/approle/role/concourse/role-id | grep role_id | awk '{print $2}'`
```

で。

#### Secret IDの発行

```
vault write -f auth/approle/role/concourse/secret-id
```

変数に代入したい場合は、

```
export SECRET_ID=`vault write -f auth/approle/role/concourse/secret-id | grep secret_id | head -1 | awk '{print $2}'`
```

で。

本記事では次の値を使用する。

```
$ echo ${ROLE_ID}
96bfd1e4-8d9b-447f-81b3-8158233bae07
$ echo ${SECRET_ID}
1c9b7f4c-f7dc-445d-9a4b-ce13874fd339
```

#### ログイン

```
vault write auth/approle/login role_id=${ROLE_ID} secret_id=${SECRET_ID}
```

### ConcourseのManifest修正


``` yaml
  instance_groups:
  - name: web
    jobs:
    - name: atc
      properties:
        # (省略)

        # ここから追加
        vault:
          auth:
            backend: approle
            params:
              role_id: ((vault_role_id))
              secret_id: ((vault_secret_id))
          url: ((vault_url))
```

を設定すれば良い。直接manifestファイルを管理してもいいが、BOSH CLI v2の[Operation Files](http://bosh.io/docs/cli-ops-files.html)を使うと差分だけ管理できる。今回はこちらを使用する。次のような`concourse-vault.yml`を作成する。

``` yaml
- type: replace
  path: /instance_groups/name=web/jobs/name=atc/properties/vault?
  value:
    url: ((vault_url))
    auth:
      backend: approle
      params:
        role_id: ((vault_role_id))
        secret_id: ((vault_secret_id))
```

`bosh deploy`時に`-o`でOperation Fileを指定する。

```
bosh deploy -d concourse \
  concourse.yml \
  -o ops-files/concourse-vault.yml \
  -v internal_ip=10.244.0.200 \
  -v external_ip=concourse.example.com \
  -v vault_url=https://vault.example.com \
  -v vault_role_id=96bfd1e4-8d9b-447f-81b3-8158233bae07 \
  -v vault_secret_id=1c9b7f4c-f7dc-445d-9a4b-ce13874fd339
```

これでデプロイ可能。

> vaultで自己証明書を使用している場合は`vault.tls.ca_cert`も必要。

CredHubを使用する場合は

```
credhub set -n "/Bosh Lite Director/concourse/vault_role_id" --type=value -v 96bfd1e4-8d9b-447f-81b3-8158233bae07
credhub set -n "/Bosh Lite Director/concourse/vault_secret_id" --type=value -v 1c9b7f4c-f7dc-445d-9a4b-ce13874fd339
```
を設定し、

```
bosh deploy -d concourse \
  concourse.yml \
  -o ops-files/concourse-vault.yml \
  -v internal_ip=10.244.0.200 \
  -v external_ip=concourse.example.com \
  -v vault_url=https://vault.example.com
```

でOK。

### パイプラインのデプロイ

簡単なパイプライン(`hello.yml`)を作成。

これまで外部パラメータは`{{param}}`で設定していたがこれは穴埋めしただけで、値が丸見えだった。
Vault連携の場合は`((param))`で設定する。この場合、`param`はタスクの実行時にVaultの`concourse/<team-name>/<pipeline-name>/<param>`から取得する。

``` yaml
jobs:
- name: hello-world
  plan:
  - task: say-hello
    params:
      MY_SECRET: ((my-secret))
    config:
      platform: linux
      image_resource:
        type: docker-image
        source:
          repository: ubuntu
      run:
        path: bash
        args:
        - -c
        - |
          echo "MY_SECRET is ${MY_SECRET}"
```

でデプロイ。

```
fly -t dev sp -p hello -c hello.yml 
fly -t dev up -p hello
```

パラメータをVaultに設定する。

```
vault write concourse/<team-name>/hello/my-secret value=FOO
```
> 実際は、Teamごとにトークンを発行して、`concourse/<team-name>/*`以下のみread-writeできる権限を持つポリシーを設定すべき。

ジョブを実行。

```
$ fly -t dev tj -j hello/hello-world --watch

started hello/hello-world #12

initializing
running bash -c echo "MY_SECRET is ${MY_SECRET}"

MY_SECRET is FOO
succeeded
```

Vaultから値が取れていることがわかる。

> 403エラー(permission denied)が出る場合は、ポリシーが設定されていないか、ATCに設定したSECRET IDの有効期限が切れている可能性がある。Vaultのログを要チェック。

### 参考URL

* https://github.com/pivotalservices/concourse-pipeline-samples/tree/master/concourse-pipeline-patterns/vault-integration
* https://github.com/rahul-kj/concourse-vault
* https://www.vaultproject.io/docs/auth/approle.html
* http://concourse.ci/creds.html

---

次はVaultもConcourseと同時にBOSHでデプロイする方法を試す。
