CI/CDパイプラインとVaultの連携
Vaultのユースケースの一つに、CI/CDパイプラインからVaultで管理しているシークレットを利用することがあります。この記事では、CI/CDツールであるCircleCIを使ってマネージド型のHCP Vaultからシークレットを利用する方法をご紹介します。
はじめに
CI/CDパイプラインは、アプリケーション開発の自動化プロセスの一部であり、コードの変更がリポジトリにプッシュされるたびに自動的にビルド、テスト、デプロイが行われます。このプロセス中にVaultからシークレットを取り出して環境変数に適用するであったり、メモリー上で扱うことでシークレットをアプリケーションのコードに直接書くことなく、セキュリティを維持しながら効率的なデプロイが可能になります。
Vaultの認証・認可とシークレットの利用
CircleCIはVaultへの認証にOpenID Connect(以下OIDC)を利用でき、パスワードレスな認証が可能です。CircleCIがVaultで管理しているシークレットを利用する流れは次のようになります。
- CircleCIはOIDCでVaultに認証します
- 認証に成功するとCircleCIが署名したOIDC準拠のJWTトークンが生成されます。VaultはこのJWTトークンに対しVaultの操作権限を付与したVaultのトークンを生成して、CircleCIにレスポンスします
- CircleCIはVaultの認証・認可を通過すると、②でVaultが生成したトークンを用いてVaultにアクセスします
- CircleCIはVaultに利用を許可されたシークレットにアクセスします
Vaultの設定
Vaultには次の4つの設定を行います。Namespaceはadminを使います。
- JWT認証メソッドを有効化
- Vaultにポリシーを設定
- CircleCI認証用のVaultロールを作成
- Vaultにシークレットを登録
1.JWT認証メソッドを有効化
最初にJWT認証メソッドを有効にします。
$ vault auth enable jwt
Success! Enabled jwt auth method at: jwt/
有効にした JWT認証メソッドでCircleCI のオーガニゼーションからJWTトークンを受け取るように構成します。具体的には、bound_issuerとoidc_discovery_url パラメータにCircleCIのOIDCプロバイダURLを設定します。<CircleCIのオーガニゼーションID>はご自身のオーガニゼーションIDに置き換えてください。
$ vault write auth/jwt/config \
bound_issuer="https://oidc.circleci.com/org/<CircleCIのオーガニゼーションID>" \
oidc_discovery_url="https://oidc.circleci.com/org/<CircleCIのオーガニゼーションID>"
Success! Data written to: auth/jwt/config
2.Vaultにポリシーを設定
特定のパスのシークレットのみにアクセスを制御するポリシーを設定します。ここでは、キーバリューストアのパス secret/circleci/demo に保存したシークレットのみ参照できるようにします。
3.CircleCI認証用のVaultロールを作成
今回Vaultロールはcircleci-demoという名前で作成します。
$ vault write auth/jwt/role/circleci-demo -<<EOF
{
"role_type": "jwt",
"user_claim": "sub",
"bound_claims": {
"aud": "< CircleCIのオーガニゼーションID>"
},
"policies": ["circleci-dev"],
"ttl": "1h"
}
EOF
この例ではオーガニゼーションID からの要求を全て受け付けるようにしていますが、特定のプロジェクトIDからのみ要求を限定することもできます。ただ、利用者(CircleCIを実行する人)のオーガニゼーションとCircleCIのプロジェクトID及びVaultのNamespaceが関連付いている構成であれば、利用者の要求範囲は利用者が属するNamespace内のリソースに限定されるので、要求をプロジェクトごと細かく設定せずとも、楽に運用できると思います。
<注意点>
この記事を執筆している時点では、Vaultロールの設定はGUIから行えず、CLIもしくはAPIから行う必要があります。また、CLIで設定する場合bound_claimsにおいてはJSON形式で記述しなければならない制約があります。
4.Vaultにシークレットを登録
Vaultにシークレットを登録します。キーバリューストアのパス secret/circleci/demo に次のユーザー名/パスワードを書込みます。Vaultはデータを自動で暗号化してストレージに保存しますので、セキュリティが担保されます。
Key | Value |
password | passwd |
username | user01 |
CircleCIの設定
今回はVCSにGitHubを使用します。GitHubにvault-circleci-demoレポジトリを作成しCircleCIの設定ファイル(config.yml)を配置します。ここでは、CircleCI Developerにある下記のカスタムOrbを設定ファイルに使用しました。
https://circleci.com/developer/orbs/orb/smaeda-ks/orb-hashicorp-vault-cli
今回は試験用にプロジェクトを1つのみ使用しているため、Contextsは設定していません。
## Vault and CircleCI Interaction Demo
version: 2.1
orbs:
orb-hashicorp-vault-cli: smaeda-ks/orb-hashicorp-vault-cli@0.1.6
jobs:
my-job:
machine: true
steps:
- checkout
# Install Vault
- orb-hashicorp-vault-cli/install
# Authenticate using OIDC and obtain token
# This will automatically set VAULT_TOKEN env variable
- orb-hashicorp-vault-cli/auth-oidc:
vault-address: "https://mnakabayashi-hcp-vault-cluster-public-vault-xxxxxxxx.xxxxxxxx.z1.hashicorp.cloud:8200"
vault-namespace: "admin"
vault-role: "circleci-dev"
- run:
name: Get secret
command: |
# export secret using $BASH_ENV
# so it can be referenced by subsequent steps within the job
UNAME=$(vault kv get -field=username secret/circleci/demo)
echo ${UNAME}
PASSWD=$(vault kv get -field=password secret/circleci/demo)
echo ${PASSWD}
workflows:
use-my-orb:
jobs:
- my-job
パイプラインの実行
circleci-vault-demoというプロジェクトを作成して、パイプラインのジョブを実行します。
ジョブが正常に終了し、Vaultのキーバリューストアに格納されたシークレットを取得できました。アプリケーションのデプロイは、このシークレットを使って行います。
まとめ
このようにCI/CDのパイプラインにVaultを組み込むことで、開発チームはセキュリティリスクを最小限に抑えつつ、迅速かつスムーズにソフトウェアをリリースできます。
今回の記事がみなさまのご参考になれば幸いです。