目次
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
- 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でデプロイする方法を試す。