- Prerequisites
- Create a second JWT authentication path in Vault
- Recreate roles to use the new authentication path
- Update your CI/CD Jobs
Tutorial: Update HashiCorp Vault configuration to use ID Tokens
This tutorial demonstrates how to convert your existing CI/CI secrets configuration to use ID Tokens.
The CI_JOB_JWT
variables are deprecated, but updating to ID tokens requires some important configuration changes to work with Vault. If you have more than a handful of jobs, converting everything at once is a daunting task.
From GitLab 15.9 to 15.11, enable the automatic ID token authentication
setting to enable ID Tokens and disable CI_JOB_JWT
tokens.
In GitLab 16.0 and later you can use ID tokens without any settings changes.
Jobs that use secrets:vault
automatically do not have CI_JOB_JWT
tokens available,
Jobs that don’t use secrets:vault
can still use CI_JOB_JWT
tokens.
This tutorial will focus on v16 onwards, if you are running a slightly older version you will need to toggle the Limit JSON Web Token (JWT) access
setting as appropriate.
To update your vault configuration to use ID tokens:
- Create a second JWT authentication path in Vault
- Recreate roles to use the new authentication path
- Update your CI/CD Jobs
Prerequisites
This tutorial assumes you are familiar with GitLab CI/CD and Vault.
To follow along, you must have:
- An instance running GitLab 15.9 or later, or be on GitLab.com.
- A Vault server that you are already using.
- CI/CD jobs retrieving secrets from Vault with
CI_JOB_JWT
.
In the examples below, replace vault.example.com
with the URL of your Vault server,
and gitlab.example.com
with the URL of your GitLab instance.
Create a second JWT authentication path in Vault
As part of the transition from CI_JOB_JWT
to ID tokens, you must update the bound_issuer
in Vault to include https://
:
$ vault write auth/jwt/config \
jwks_url="https://gitlab.example.com/-/jwks" \
bound_issuer="https://gitlab.example.com"
After you make this change, jobs that use CI_JOB_JWT
start to fail.
You can create multiple authentication paths in Vault, which enable you to transition to IT Tokens on a project by job basis without disruption.
-
Configure a new authentication path with the name
jwt_v2
, run:vault auth enable -path jwt_v2 jwt
You can choose a different name, but the rest of these examples assume you used
jwt_v2
, so update the examples as needed. -
Configure the new authentication path for your instance:
$ vault write auth/jwt_v2/config \ jwks_url="https://gitlab.example.com/-/jwks" \ bound_issuer="https://gitlab.example.com"
Recreate roles to use the new authentication path
Roles are bound to a specific authentication path so you need to add new roles for each job.
-
Recreate the role for staging named
myproject-staging
:$ vault write auth/jwt_v2/role/myproject-staging - <<EOF { "role_type": "jwt", "policies": ["myproject-staging"], "token_explicit_max_ttl": 60, "user_claim": "user_email", "bound_claims": { "project_id": "22", "ref": "master", "ref_type": "branch" } } EOF
-
Recreate the role for production named
myproject-production
:$ vault write auth/jwt_v2/role/myproject-production - <<EOF { "role_type": "jwt", "policies": ["myproject-production"], "token_explicit_max_ttl": 60, "user_claim": "user_email", "bound_claims_type": "glob", "bound_claims": { "project_id": "22", "ref_protected": "true", "ref_type": "branch", "ref": "auto-deploy-*" } } EOF
You only need to update jwt
to jwt_v2
in the vault
command, do not change the role_type
inside the role.
Update your CI/CD Jobs
Vault has two different KV Secrets Engines and the version you are using impacts how you define secrets in CI/CD.
Check the Which Version is my Vault KV Mount? article on HashiCorp’s support portal to check your Vault server.
Also, if needed you can review the CI/CD documentation for:
The following examples show how to obtain the staging database password written to the password
field in secret/myproject/staging/db
KV Secrets Engine v1
The secrets:vault
keyword defaults to v2 of the KV Mount, so you need to explicitly configure the job to use the v1 engine:
job:
variables:
VAULT_SERVER_URL: https://vault.example.com
VAULT_AUTH_PATH: jwt_v2
VAULT_AUTH_ROLE: myproject-staging
id_tokens:
VAULT_ID_TOKEN:
aud: https://gitlab.example.com
secrets:
PASSWORD:
vault:
engine:
name: kv-v1
path: secret
field: password
path: myproject/staging/db
file: false
Both VAULT_SERVER_URL
and VAULT_AUTH_PATH
can be defined as project or group CI/CD variables,
if preferred.
We use secrets:file:false
because ID tokens place secrets in a file by default, but we need it to work as a regular variable to match the old behavior.
KV Secrets Engine v2
There are two formats you can use for the v2 engine.
Long format:
job:
variables:
VAULT_SERVER_URL: https://vault.example.com
VAULT_AUTH_PATH: jwt_v2
VAULT_AUTH_ROLE: myproject-staging
id_tokens:
VAULT_ID_TOKEN:
aud: https://gitlab.example.com
secrets:
PASSWORD:
vault:
engine:
name: kv-v2
path: secret
field: password
path: myproject/staging/db
file: false
This is the same as the example for the v1 engine but secrets:vault:engine:name:
is set to kv-v2
to match the engine.
You can also use a short format:
job:
variables:
VAULT_SERVER_URL: https://vault.example.com
VAULT_AUTH_PATH: jwt_v2
VAULT_AUTH_ROLE: myproject-staging
id_tokens:
VAULT_ID_TOKEN:
aud: https://gitlab.example.com
secrets:
PASSWORD:
vault: myproject/staging/db/password@secret
file: false
After you commit the updated CI/CD configuration, your jobs will be fetching secrets with ID Tokens, congratulations!