セキュリティ

CI/CDパイプラインとVaultの連携

Vaultのユースケースの一つに、CI/CDパイプラインからVaultで管理しているシークレットを利用することがあります。この記事では、CI/CDツールであるCircleCIを使ってマネージド型のHCP Vaultからシークレットを利用する方法をご紹介します。

はじめに

CI/CDパイプラインは、アプリケーション開発の自動化プロセスの一部であり、コードの変更がリポジトリにプッシュされるたびに自動的にビルド、テスト、デプロイが行われます。このプロセス中にVaultからシークレットを取り出して環境変数に適用するであったり、メモリー上で扱うことでシークレットをアプリケーションのコードに直接書くことなく、セキュリティを維持しながら効率的なデプロイが可能になります。

Vaultの認証・認可とシークレットの利用

CircleCIはVaultへの認証にOpenID Connect(以下OIDC)を利用でき、パスワードレスな認証が可能です。CircleCIがVaultで管理しているシークレットを利用する流れは次のようになります。

  1. CircleCIはOIDCでVaultに認証します
  2. 認証に成功するとCircleCIが署名したOIDC準拠のJWTトークンが生成されます。VaultはこのJWTトークンに対しVaultの操作権限を付与したVaultのトークンを生成して、CircleCIにレスポンスします
  3. CircleCIはVaultの認証・認可を通過すると、②でVaultが生成したトークンを用いてVaultにアクセスします
  4. CircleCIはVaultに利用を許可されたシークレットにアクセスします

Vaultの設定

Vaultには次の4つの設定を行います。Namespaceはadminを使います。

  1. JWT認証メソッドを有効化
  2. Vaultにポリシーを設定
  3. CircleCI認証用のVaultロールを作成
  4. 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を組み込むことで、開発チームはセキュリティリスクを最小限に抑えつつ、迅速かつスムーズにソフトウェアをリリースできます。
今回の記事がみなさまのご参考になれば幸いです。

 

 

 

 

 

 

 

 

この記事に関連する製品・サービス

この記事に関連する記事