--- 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 --- **目次** 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///`から取得する。 ``` 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//hello/my-secret value=FOO ``` > 実際は、Teamごとにトークンを発行して、`concourse//*`以下のみ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でデプロイする方法を試す。