CIからクラウドプロバイダーにアクセスする際にAPI KeyなどのSecretsをCI側に置くと、CI側でセキュリティインシデントが発生した際にデータを守れません。
自分のデータは自分で守りましょう。
ということで、SecretsはSelf HostedなHashiCorp Vaultに置くとします。ではCIからHashiCorp Vaultへのアクセスはどうすれば良いでしょうか?VaultのトークンをCI側に置いてしまうと、意味がないですね。
GitHub ActionsではOpen ID Connectを使用して、GitHub側でJWTを発行し、Vault側でこのトークンを信頼し、Vaultのトークンをジョブごとに一時的に払い出すことができます。これを使うと、CI側にVaultのトークンを保存するよりも遥かに安全にVaultへアクセスすることができます。
このアクセス方法を試したのでメモします。以下のドキュメントを参考にしました。
- https://docs.github.com/en/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-hashicorp-vault
- (日本語版) https://docs.github.com/ja/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-hashicorp-vault
- https://github.com/hashicorp/vault-action
前提としてGitHub Actionsからアクセス可能なVaultがあるとします。
動作確認したVaultのバージョンは以下です。
$ vault version
Vault v1.12.2 (415e1fe3118eebd5df6cb60d13defdc01aa17b03), built 2022-11-23T12:53:46Z
$ vault status
Key Value
--- -----
Seal Type shamir
Initialized true
Sealed false
Total Shares 5
Threshold 3
Version 1.12.2
Build Date 2022-11-23T12:53:46Z
Storage Type s3
Cluster Name vault-cluster-d5eb8945
Cluster ID 76979525-c584-407c-6b91-2671b591bf04
HA Enabled false
JWT Auth Methodの設定
JWT Auth Methodを有効にし、トークンの検証方式としてOIDC Discoveryを設定します。 Discovery URLは https://token.actions.githubusercontent.com です。
vault auth enable jwt
vault write auth/jwt/config \
bound_issuer="https://token.actions.githubusercontent.com" \
oidc_discovery_url="https://token.actions.githubusercontent.com"
Policyの作成
kv
というパスの下のcicd
以下のみGitHub Actionsからのreadを許可します。
vault policy write cicd - <<EOF
path "kv/data/cicd/*" {
capabilities = [ "read" ]
}
EOF
Roleの作成
JWT Auth Methodに対するRoleを作成します。このRoleは後にGitHub ActionsのWorkflowで指定します。
vault write auth/jwt/role/cicd -<<EOF
{
"role_type": "jwt",
"user_claim": "actor",
"bound_claims_type": "glob",
"bound_claims": {
"sub": [
"repo:making/*",
"repo:categolj/*"
]
},
"policies": [
"cicd"
],
"ttl": "10m"
}
EOF
policies
に先ほど作成したPolicyを設定します。
bound_claims
にトークンを許可する条件を書きます。sub
Claimに対してワイルドカードを指定することで、特定のGitHubのレポジトリからのみのアクセスを許可します。
Secretの作成
テスト用のSecretを作成します。
vault secrets enable -path=kv/ kv-v2
vault kv put kv/cicd/message text='Hello World!' user='\@making'
GitHub Actions Workflowの作成
以下のようなWorklowを定義します。ここではVaultのURLであるVAULT_ADDR
だけ、GitHubのSecretに保存しました。機密情報というより、ハードコードしたくなかっただけです。
exportToken
をtrue
にすると、Vaultから払い出されたトークンが環境変数VAULT_TOKEN
に入ります(デフォルト: false
)。後にトークンをRevokeする際に使用します。exportEnv
をtrue
にするとVaultから取得したSecretが環境変数に入ります(デフォルト: true
)。
name: retrieve-secret
on:
- push
- workflow_dispatch
jobs:
retrieve-secret:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
steps:
- name: Import Secrets
id: secrets
uses: hashicorp/vault-action@v2.4.3
with:
exportToken: true
exportEnv: true
method: jwt
url: ${{ secrets.VAULT_ADDR }}
role: cicd
secrets: |
kv/data/cicd/message text | MESSAGE_TEXT ;
kv/data/cicd/message user | MESSAGE_USER
- name: Use Secrets
run: |
echo "MESSAGE_TEXT: ${MESSAGE_TEXT}"
echo "MESSAGE_USER: ${MESSAGE_USER}"
- name: Revoke token
if: always()
run: |
curl -X POST -s -H "X-Vault-Token: ${VAULT_TOKEN}" ${{ secrets.VAULT_ADDR }}/v1/auth/token/revoke-self
実際に試したGitHub Repoは https://github.com/making/test-oidc です。

これでGitHub ActionsでVaultからSecretが安全に取得できました。