@making's memo

All Categories All Tags Premium (Beta)


Concourse CIのVault連携メモ

Edit History

目次

Concourse 3.3で追加されたCredential Management(Vault対応)を試す。

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

今回は外部Vaultサーバーとして、Cloud FoundryにデプロイしたVaultを利用する。Pivotal Web Servicesでは月100円以下(無料期間あり)で管理できるのでおすすめ。

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

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

Vaultの設定

Vaultとの連携方式は

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

AppRoleもTokenもPeriodic Tokenにしないと、トークンの有効期限が切れるたびに設定し直しになるので注意。

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修正

  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を使うと差分だけ管理できる。今回はこちらを使用する。次のようなconcourse-vault.ymlを作成する。

- 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>から取得する。

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


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

このエントリーをはてなブックマークに追加