GitLab CI/CD secrets from HashiCorp Vault: what the integration does
Many self-managed GitLab instances still hold deployment credentials as long-lived CI/CD variables, where any job that can reference the variable can read the value, and where rotation depends on someone remembering to change it. The native GitLab CI/CD integration with Vault replaces that pattern. A job asks Vault for the secret it needs at run time, using an ID token that GitLab issues for that specific job, and Vault returns a credential that expires. Your secrets manager, not the variable list, becomes the place where access is granted and revoked. The integration is part of the Premium tier, so confirm the tier you are licensing before you plan the design around it. The supported secrets manager is HashiCorp Vault, and GitLab's documentation for the version you run should be checked before you treat a compatible fork such as OpenBao as supported in the same way.
The control point is the Vault role and its bound claims. When a job presents its ID token, Vault checks claims such as the project path, the project ID, the ref and the ref type, then decides whether that job may authenticate and which policy applies to it. A role bound to one project and to a protected branch can return a production database credential, while a role for feature branches receives nothing sensitive. Because the token identifies a project and a ref, a branch name alone is a weak boundary, and a role that matches on the project path can break after a rename, so the bound claims deserve the same review as the policy attached to them. Ask your team to list which roles exist, which projects they cover and who can change them, before any job is migrated.
Before you migrate, confirm three things with your GitLab and Vault documentation for your exact versions: how the ID token audience is set in the CI/CD job configuration, which Vault auth method and mount path your roles use, and whether your Vault edition and storage backend fit the availability and audit requirements you already hold for other secrets. Plan the migration as an inventory exercise. Each existing CI/CD variable should map to a role, a policy and a named owner, and variables that cannot be mapped should be retired or kept only for a documented reason.
What you need before connecting GitLab to Vault
Connecting GitLab CI/CD to Vault touches four systems: the GitLab instance that issues ID tokens, the Vault cluster that validates them, the runners that fetch secrets, and the people who own the policies. Settle each of the cards below before writing any pipeline configuration, because a gap in one usually surfaces as a failed job.
Self-managed GitLab on a supported version
Confirm that your instance runs a release still receiving fixes, and check the current release list rather than assuming a version. Under the maintenance policy, bug fixes go only to the current stable release, while security fixes reach the previous two monthly releases too. Plan the upgrade path through required upgrade stops before you rely on newer ID token behavior. Confirm that the Premium tier is applied to the instance, because the Vault secrets integration requires it.
Reachable Vault endpoint with trusted TLS
Vault needs a stable HTTPS address that every GitLab runner can reach over your network path, including any proxies or egress rules. The certificate chain must be trusted by the runner host, which means an internal certificate authority must be installed where runners execute jobs. Test the chain from a runner, not from your laptop, since runner images and hosts often hold different trust stores.
JWT and OIDC auth method in Vault
GitLab issues a short-lived ID token to each job, and Vault must be configured to validate it. Enable the JWT auth method and point it at the GitLab instance URL so Vault can fetch signing keys. Decide early whether one JWT mount serves all projects or whether you split mounts by group, since that choice shapes how roles are named and audited.
Vault edition and license status
Choose between Vault Community Edition, Vault Enterprise and HCP Vault Dedicated, and record the license terms that apply. HashiCorp moved future releases to the Business Source License 1.1, so confirm with legal how that license affects your use, especially if you offer hosted services. Enterprise features such as performance replication, namespaces and FIPS compliance need a license applied to the cluster, so ask HashiCorp for current Enterprise pricing through its sales team.
Vault version checked against releases
Vault 2.2.0 is the current HashiCorp release at the time of writing, following 2.1.2. Check the GitHub releases page on the day you plan the build, and confirm the exact version your Vault team has approved. If you choose OpenBao instead, verify its migration notes, since its guide was tested against Vault 1.14.1 Community Edition only.
Named owner for Vault policies
Assign one accountable person or team to write, review and retire the Vault policies and roles that bind secrets to GitLab projects and branches. Without a named owner, roles drift as projects are renamed or branches are added, and secrets end up readable by pipelines that should not see them. Agree how changes are requested, reviewed and logged before the first production pipeline reads a secret.
Configuration sequence from Vault auth to a passing pipeline
This sequence connects a GitLab project to a Vault role that issues read-only access to one secret, scoped to a single project and protected branch. It ends with a passing pipeline and audit evidence that the restrictions work, using a non-production project for the test.
Confirm tier and instance network path
The platform owner confirms that the GitLab edition and tier on your instance include the CI/CD secrets integration, using the current pricing and feature pages. They then record the external URL that Vault will use to reach GitLab's OpenID configuration. Vault must reach that URL over HTTPS from its own network, so the security team checks firewall rules and certificate trust between the two systems first. This step is done when a request from the Vault host to the instance's OpenID discovery document returns a valid response that lists the expected issuer.
Enable and configure the JWT auth method
A Vault administrator enables the JWT auth method and sets the GitLab instance URL as the OIDC discovery URL, with the bound issuer set to the same value. The issuer string must match exactly what GitLab advertises, because a trailing slash or hostname mismatch is a common reason logins fail. Read the auth configuration back to confirm the issuer and discovery URL match your instance. Then attempt a login with no role attached, which should return a clear error instead of a token.
Create a test secret path
The secrets owner confirms a KV version 2 secrets engine is available, then writes a dummy value under a path reserved for one non-production GitLab project, such as a sandbox project with no deployment rights. Production secrets stay out of this exercise entirely. Read the secret back as an administrator to confirm the path and version. Share only the path with the pipeline team, never the value, and keep the value out of tickets, chat and job logs.
Write a read-only policy for that path
The Vault administrator writes a policy that grants only the read capability on the exact data path of the test secret, with no list, create, update or delete capabilities. Keep one policy per application or environment, so a compromised job cannot reach unrelated secrets. Confirm the policy by testing it with a token that carries it: a read on the test path should succeed, and a write to the same path should return permission denied.
Bind the role to project and branch
Create a JWT role that accepts only tokens issued for the test project, using claims that GitLab sets for each job. Set the user claim to a stable identifier, bind the audience to the value the job will request, and restrict the ref and protected-branch claims so only a protected branch can receive the policy. Attach the read-only policy and a short token lifetime. Confirm by reading the role back and checking each bound claim against a sample token from a protected branch and from an unprotected branch.
Request the ID token in the job
The pipeline author adds an id_tokens entry to the test job with the audience that Vault expects, then adds a secrets entry that names the Vault path and role and maps the value to a CI/CD variable. Keep the audience specific to this Vault instance. Restrict who can edit the job definition on protected branches, since the role and path are visible to anyone who can change the pipeline. Run the job on a protected branch and confirm in the job log that the secrets step completed without an error.
Confirm retrieval without printing the value
In the test job, print only a fixed success message and never the secret value or any part of it, then confirm the job passes. Next, open the Vault audit log and find the JWT login entry, which should name the role and show the project and branch claims without any secret content. Finally, run the same pipeline from an unprotected branch and confirm Vault denies the login. A denial there proves the branch restriction works.
Which GitLab claims map to which Vault role conditions
This table pairs each GitLab ID token claim with the Vault role condition that can match it, the stability of that claim, and the policy paths it should unlock. Read the stability column first, because a role condition built on an unstable claim can stop matching after a rename or quietly widen access. Confirm the exact claim names and their formats in the GitLab CI/CD ID token documentation for your installed version before writing any role.
| GitLab claim | Vault role condition | Stability and why | Policy path use |
|---|---|---|---|
| project_id | bound_claims on project_id | Stable. The numeric ID persists through project renames and path changes. | Anchor production secret access to this value. |
| project_path | bound_claims on project_path | Unstable. Changes on rename or move, so the role can stop matching without warning. | Use as a readable check alongside project_id, not alone. |
| namespace_id | bound_claims on namespace_id | Stable. Identifies the group or user namespace that owns the project. | Grant shared secret paths to a whole group where teams share ownership. |
| namespace_path | bound_claims on namespace_path | Unstable. Changes when a group is renamed or the subgroup structure changes. | Avoid as the only condition for group-wide read access. |
| ref | bound_claims on ref | Weak alone. Anyone with push rights can create a branch with a matching name. | Do not map deploy or production paths to ref alone. |
| ref_protected | bound_claims on ref_protected set to true | Stronger. GitLab sets it from branch or tag protection rules, which maintainers control. | Map production secret paths only to protected refs. |
| ref_type | bound_claims on ref_type | Distinguishes branch from tag pipelines. Stable for a given ref kind. | Restrict release secrets to tag pipelines where your process uses tags. |
| pipeline_source | bound_claims on pipeline_source | Reflects what triggered the job, such as a push, merge request or schedule. Confirm the value list. | Keep deploy secrets away from merge request and external-trigger pipelines. |
| sub | bound_subject | Built from project and ref details, so it changes when either changes. Confirm its format for your version. | Use only when the format is confirmed and tested against a sample job. |
Hardening the GitLab to Vault trust path
The trust path runs from a GitLab job's ID token to a Vault role and then to the secret the job reads. Each link can be tightened separately, and the cards below cover the controls that matter most. Roll them out gradually, starting with role conditions and logging, as the GitLab hardening guidance recommends.
Bind Vault roles to protected refs and project IDs
Condition each Vault role on the ID token claims that identify the exact project and ref allowed to authenticate, such as the project ID in the project_id claim and the protected branch in ref_protected and ref. Matching on project path alone is weaker because paths change when projects are renamed or moved. Check that unprotected branches and merge request pipelines cannot satisfy the role conditions, and test this with a deliberately mismatched job before go-live.
Use one Vault role per environment
Create separate roles for development, staging and production, each granting read access only to the secret paths that environment needs. A single broad role lets a compromised lower-environment job read production credentials. Ask your team to list which roles can read each production path and confirm that no shared role reaches it.
Keep token and lease lifetimes short
Set short time-to-live values on the Vault tokens issued to jobs so that a leaked token expires soon after the job finishes. Pair this with short-lived dynamic credentials where the target system supports them. Confirm the exact lifetime settings in the Vault and OpenBao documentation for your version, and align them with how long your longest job runs.
Prevent secrets from appearing in job logs
Mark CI/CD variables that hold secrets as masked and, where the value format allows it, as protected so they reach only protected branches. Avoid commands that print credentials, such as debug tracing with set -x around authentication steps. Review job logs after a test run to confirm that the secret values do not appear, because masking only hides values that match exactly.
Audit Vault access and alert on failures
Enable Vault audit devices so every authentication and secret read is recorded, and forward those entries to your log platform. Create alerts for repeated JWT login failures, logins from unexpected projects, and reads of production paths outside deployment windows. Decide in advance who receives each alert and what response is expected.
Manage Vault like production secrets
Place the Vault cluster, its configuration, its storage backend and its unseal or auto-unseal keys under the same change control, backup and access review as other production secrets. Changes to JWT auth configuration and role conditions should go through review and be logged. Confirm with your Vault or OpenBao provider how the chosen storage backend is backed up and restored.
Choosing between HashiCorp Vault and OpenBao for this integration
Vault Community Edition is distributed as binaries or source and gives you the Vault API that GitLab's ID token authentication can call. The license has changed over time. Releases from 1.15.0 onward fall under the Business Source License 1.1, and the Vault LICENSE file names IBM as licensor. That license bars competitive hosted or embedded offerings, so legal review should confirm whether your use is affected.
- License conversion: Each release converts to MPL-2.0 four years after publication, so a pinned older version will move to a more permissive license on a known schedule.
- Feature set: Community Edition omits the Enterprise features in HashiCorp's documentation, including namespaces, Enterprise MFA, control groups and performance replication.
- Role options: Confirm in the Community Edition documentation that the JWT auth role options you need, such as bound claims and token policies, exist in the build you will run.
- Support model: Without a HashiCorp support contract, your team or partner owns upgrades, patching and incident response.
- Current release: The GitHub releases page lists Vault 2.2.0 (October 15, 2026) as current, so decide which release line you will standardize on.
Before you build, confirm the JWT role options, the auth path and the exact Community Edition version against the GitLab steps in this guide.
Vault Enterprise is licensed software offered for self-managed clusters and as HCP Vault Dedicated, a managed service that runs the same binary as self-managed Enterprise. Several features require a license applied to the cluster. Namespaces separate teams' secrets within one cluster, Enterprise MFA adds a second factor to Vault logins, and control groups add approval steps before sensitive reads. HashiCorp publishes pay-as-you-go, flex and Enterprise self-managed models but directs self-managed Enterprise buyers to sales, so you will need a written quote.
- Licensed features: Namespaces, Enterprise MFA, control groups, Sentinel policy as code and FIPS compliance depend on a license, so confirm which ones your controls require.
- HCP Vault Dedicated: It runs the same binary as self-managed Enterprise while HashiCorp operates the cluster. Ask how GitLab runners reach it over private networking.
- Replication and HSM: Performance and disaster recovery replication and HSM or PKCS#11 support matter if secrets must stay available across sites or keys must sit in hardware.
- Quote scope: Ask the vendor to separate the license, support and any hosting cost in the quote.
- Upgrades: Automated upgrades are an Enterprise feature, so confirm how you will test each upgrade against your GitLab pipelines first.
Ask the vendor which Enterprise features appear in your quote, then confirm that the GitLab JWT steps work on that exact edition and deployment model.
OpenBao is a community fork of Vault licensed under MPL-2.0. It is a Sandbox project of the Open Source Security Foundation under Linux Foundation stewardship, and the community leads it under open-governance principles. It documents key/value storage, dynamic secrets, leasing with automatic revocation, JWT/OIDC and AppRole auth methods, and login MFA. Its migration guide was tested only against Vault 1.14.1 Community Edition, so any migration from an Enterprise deployment needs its own validation.
- License: The repository is MPL-2.0 licensed, so there is no license conversion schedule to track.
- Governance: Ask how the Sandbox status fits your vendor-risk policy and who will support the product in your organization.
- Release line: v2.7.0 (September 23, 2026) and v2.7.1 (October 1, 2026) are the latest releases listed, with v2.6.4 for the previous minor line. Confirm your patch cadence against these.
- Read scaling: Raft standbys serve read-only operations since 2.5.0, and v2.7.0 extended this to PostgreSQL.
- Migration evidence: Validate the migration guide on your exact source version and edition before you rely on its steps.
Confirm in the OpenBao documentation that the JWT auth path, bound claims and namespace layout you choose match the version you deploy.
Why the secret fetch fails and how to fix it
This table lists the failures teams most often hit when a CI/CD job pulls a secret from Vault, with the likely cause and a check you can run to confirm and fix it. Work down the rows in the order a job reaches each step: tier and feature, token, Vault authentication, network trust, token lifetime and finally the policy. The main takeaway is that most failures trace back to a mismatch between the job's ID token claims and the Vault role, so compare those values first.
| Failure | Likely cause | Fix to verify |
|---|---|---|
| Secret fetch is not available | Premium tier or the secrets feature is not enabled for the project or group | Confirm the tier on the instance and check that the secrets keyword is accepted in a test pipeline on the same project |
| Authentication rejected with audience error | The aud claim in the job's ID token does not match the audience set on the Vault JWT auth method | Print the decoded token claims in a debug job, then set the same audience value in both the CI/CD id_tokens block and the Vault role |
| Role lookup fails after a project rename | Bound claims in the Vault role still use the old project path, which no longer matches the sub or project_path claim | Replace path-based bound claims with the numeric project ID, then rerun the job on the renamed project |
| Merge request pipeline cannot read the secret | The Vault role is bound to a protected branch, and merge request pipelines do not run on that ref | Confirm the ref claim in a merge request pipeline, then scope the role to the merge request ref or a separate role with a narrower policy |
| Runner cannot verify Vault certificate | The runner does not trust the internal certificate authority that signed the Vault listener certificate | Add the CA bundle to the runner's trust store or to the job's CA settings, then run vault status from the runner host |
| Token expires during a long job | The Vault token lifetime is shorter than the job runtime and the token is not renewed | Check the token TTL and max TTL on the role, then fetch secrets early in the job or split long steps into separate jobs |
| Permission denied on a KV v2 secret | The policy grants read on the secret metadata path but not on the data path under the mount | Add read capability on the path with the data segment for the KV v2 mount, then test with vault kv get as the job role |
Questions buyers ask before connecting GitLab to Vault
What does it cost to connect GitLab CI/CD to HashiCorp Vault?
The cost has three parts: GitLab, Vault and the people doing the work. GitLab's pricing page lists Premium at 29 US dollars per user per month billed annually, and the external secrets feature is part of the Premium tier, so every user who needs it is counted under that subscription. Vault Enterprise pricing is not published, so request a quote from HashiCorp sales for the license, and confirm whether you are buying self-managed Enterprise, pay-as-you-go or HCP Vault Dedicated. Services fees depend on the written scope. Ask any partner to separate one-time build work from recurring support, upgrades and Vault or OpenBao operations.
How long does a Vault integration for GitLab CI/CD take?
Duration depends on how many projects and secret paths you need, how many Vault auth roles must be designed, whether Vault already exists, and how your network and TLS certificates are set up. A pilot with one project and one secret is much shorter than a rollout across groups with branch-specific access. No duration is quoted here. Ask for a written plan with phases, the environments included and the acceptance tests, and confirm which items depend on your security review or change windows.
Can our own team connect GitLab CI/CD to Vault without a partner?
Yes, if your team already runs Vault or OpenBao, administers GitLab at the Premium tier or higher, and has someone who understands JWT claims and Vault policies. The work is mostly configuration: enabling ID tokens in CI/CD, defining a Vault JWT or OIDC auth method, writing roles that match the project and branch claims, and testing that jobs receive only their secrets. Teams without that mix often benefit from a fixed-scope engagement, where scope and deliverables are agreed in writing before work starts.
What do our security and platform teams need to provide?
Plan for time from both teams. Security should define which secrets belong in Vault, who approves access, how long leases last and how audit logs are reviewed. Platform engineering should provide the Vault and GitLab endpoints, network paths from runners to Vault, TLS certificates, storage backend decisions and the change process for the Vault policies. Both teams should agree on a naming scheme for roles, paths and projects, because stable project identifiers and branch rules are hard to change after jobs depend on them.
Should we use HashiCorp Vault or OpenBao under our license policy?
Choose based on your license rules, support needs and the Vault features you depend on. Vault's LICENSE uses the Business Source License 1.1 for releases from 1.15.0 onward, bars competitive hosted or embedded offerings and converts each version to MPL-2.0 four years after publication. OpenBao is a community fork under MPL-2.0 managed under the Linux Foundation's OpenSSF. Its migration guide was tested only against Vault 1.14.1 community edition, so confirm compatibility with any Enterprise features you use before choosing it. Ask your legal team to review both licenses against your intended use.
How do we handle upgrades on the GitLab side and the Vault side?
Treat them as two tracks with a shared test plan. On GitLab, follow the required upgrade stops, since the upgrade paths documentation lists x.2, x.5, x.8 and x.11 as required stops from GitLab 17.5 onward, and confirm that the CI/CD secrets settings still behave as expected after each step. On Vault or OpenBao, confirm the release notes, storage backend compatibility and any Enterprise license implications before moving. Keep a staging Vault and a test GitLab project so role claims and policy changes are tested before production jobs depend on them.
What goes wrong most often when GitLab jobs read secrets from Vault?
The most common failures are role conditions that are too broad, claims that do not match after a project rename, runners that cannot reach Vault and secrets exposed in job logs. Restrict roles by the project path or stable project ID and by protected branches, use short token lifetimes, and test a job from an unprotected branch to confirm it is refused. Check your runner network path and TLS trust early, and confirm that masked variables and job output rules are set so secret values do not appear in logs.
How DeployOpen scopes and delivers this integration
DeployOpen plans and builds the link between self-managed GitLab and your HashiCorp Vault or OpenBao cluster inside your own infrastructure. We agree the projects, branches, roles and secret paths in writing before any configuration starts, then test and document the result so your team can run it.
How we scope
- Inventory of the projects and groups that need Vault secrets, and the environments each one deploys to
- Written mapping of each secret path to a Vault role bound to project and branch claims
- Confirmation of your GitLab tier, Vault edition and the Vault version your cluster runs before design starts
- Agreed list of out-of-scope items, such as dynamic database credentials or Vault cluster hardening
How we build
- Configure JWT authentication in Vault using the ID token claims GitLab issues for each job
- Create least-privilege Vault roles and policies that limit access by project path and protected branch
- Wire CI/CD jobs to fetch secrets at runtime, with masked variables and no long-lived copies in GitLab
- Test success and denied cases on protected and unprotected branches, and record the results
How we hand over
- Runbook covering role creation, claim conditions, secret rotation steps and how to add a new project
- Configuration as code for the Vault auth method, roles and policies, stored in your repositories
- Walkthrough with your platform and security teams, plus a record of tests and any open risks
- Documentation of the Premium tier requirement and the GitLab and Vault versions tested
How we support
- Ongoing support, upgrades and testing are available as a retainer after handover
- Review of role conditions when projects are renamed, moved or added to groups
- Verification after GitLab and Vault upgrades, checked against the version stops and releases you plan to use
- Quotes follow from the written scope, and changes to scope are agreed in writing before work starts

