Well-Architected Framework
Secure CircleCI secrets with HashiCorp Vault
CircleCI can issue a signed OIDC token for jobs that use OIDC-based identity patterns. The token contains claims that identify what is running — including the organization, project, context membership, and VCS branch. This makes JWT/OIDC auth the natural integration point for most CircleCI deployments: no credential pre-provisioning, no long-lived secrets stored in CircleCI, and a Vault token scoped to the duration of the job.
CircleCI's OIDC issuer URL is unique to each organization rather than shared across the platform. Vault must be configured with your specific organization's discovery URL, and in multi-organization environments each organization requires its own JWT auth configuration in Vault.
Architecture
The job-to-Vault authentication flow follows the same high-level pattern as the other CI/CD integrations in this section, but the verification step here is based on CircleCI-issued OIDC tokens:
- CircleCI platform issues an org-scoped OIDC token to the job, available as
$CIRCLE_OIDC_TOKEN_V2 - The job presents the token to Vault's JWT auth endpoint
- Vault fetches signing keys from the org-specific CircleCI OIDC discovery URL and validates the token signature
- Vault evaluates
bound_claimsagainst CircleCI-specific claims such as project ID, context membership, and VCS ref to match a Vault role - Vault issues a short-lived token scoped to the policies attached to the matching role
The job can now retrieve secrets based on the policy for that role.

Runner hosting and auth method selection
The right auth method depends on where CircleCI executors run. JWT/OIDC auth works for all executor types because CircleCI issues an OIDC token regardless of the underlying infrastructure. However, when jobs run on infrastructure you control, additional auth methods become available that can provide stronger identity guarantees or remove the dependency on CircleCI's token issuer entirely.
- CircleCI cloud executors — JWT/OIDC is the practical option. You do not control the underlying infrastructure, so there is no instance or pod identity to leverage.
- Self-hosted runners on Kubernetes — Kubernetes auth is available in addition to JWT. The runner pod's service account token is verified directly by the cluster API, independent of CircleCI.
- Self-hosted runners on AWS, Azure, or GCP — Cloud provider auth methods (AWS IAM, Azure Managed Identity, GCP IAM) are available. The runner instance or container already has a platform identity that Vault can validate against the cloud provider's API — no credential to provision or rotate.
- Self-hosted runners on bare metal or air-gapped environments — AppRole with response wrapping, or TLS certificate auth for persistent runner fleets. In air-gapped CircleCI Server environments where OIDC token issuance is not available, AppRole becomes the required fallback.
Authentication options
Use JWT/OIDC auth for CircleCI cloud executors and for self-hosted runners where CircleCI-issued workload identity is the most practical identity source. For self-hosted runners, choose the auth method that best matches the underlying infrastructure.
The following table summarizes when each auth method fits best.
| Auth method | Security posture | Credential lifecycle | Best suited for |
|---|---|---|---|
| JWT / OIDC | High; per-job identity bound to CircleCI project and context metadata | Token issued per job by CircleCI, no rotation needed | CircleCI cloud executors; self-hosted runners with access to CircleCI's OIDC endpoint |
| Cloud provider auth methods | Highest for cloud-hosted runners; identity is the platform infrastructure itself | Managed by cloud provider; no rotation required | Self-hosted runners on EC2, Azure VMs/ACI, or GCE instances with an assigned instance identity |
| Kubernetes | Highest for in-cluster; service account token verified directly by the cluster API | Short-lived projected service account token, auto-rotated by Kubernetes | Self-hosted runners deployed as pods in a Kubernetes cluster |
| TLS Certificate | High; mutual authentication | Certificate with defined expiry; requires rotation process | Long-lived, persistent runner fleets where mTLS is part of the existing security posture |
| AppRole | Moderate; requires secure secret ID delivery | Secret ID is single-use with response wrapping; RoleID is long-lived | Air-gapped CircleCI Server installations; environments where no platform identity is available |
JWT auth is the right choice for most CircleCI jobs, whether using CircleCI cloud executors or self-hosted runners that can reach CircleCI's OIDC endpoint.
There are two important structural differences from other platforms. First,
many CircleCI Vault integration patterns use a context so the job can access
shared configuration and claim-based controls tied to that context. Second,
CircleCI provides two token versions:
$CIRCLE_OIDC_TOKEN (v1) and $CIRCLE_OIDC_TOKEN_V2. Prefer v2 — it uses a
more precise sub claim format and is the version CircleCI recommends for new
integrations.
CircleCI's OIDC token contains the following claims that Vault can use as binding conditions:
| Claim | Example value | Use for |
|---|---|---|
sub | org/org_id/project/project_id/user/user_id | Primary identity combining org, project, and user |
oidc.circleci.com/project-id | abc123-... | Restrict to a specific project |
oidc.circleci.com/context-ids | ["uvw456-..."] | Restrict to jobs that have access to specific contexts |
oidc.circleci.com/vcs-origin | https://github.com/org/repo | Restrict to a specific VCS repository |
oidc.circleci.com/vcs-ref | refs/heads/main | Restrict to a specific branch or tag |
The oidc.circleci.com/context-ids claim is one of the most useful
CircleCI-specific security controls. Binding a Vault role to a specific context
UUID means a job must have been explicitly granted access to that context by a
CircleCI organization admin before it can authenticate. This creates a two-
factor access model: project identity plus operator-controlled context
membership.
Role configuration
CircleCI's namespaced claims use dot-notation keys that require the
claim names to be matched exactly as written. CircleCI's sub claim is a normal
top-level string claim, not a JSON pointer path. An unconstrained role
that accepts any JWT from your CircleCI organization gives every project access
to those secrets — always bind to at minimum project-id and where possible
also to context-ids.
# Vault JWT auth config — issuer URL is org-specific, not a global CircleCI URL
# Each CircleCI organization requires its own JWT auth configuration in Vault
vault write auth/jwt/config \
oidc_discovery_url="https://oidc.circleci.com/org/your-org-id" \
bound_issuer="https://oidc.circleci.com/org/your-org-id"
# Vault role scoped to a specific project and context
vault write auth/jwt/role/circleci-production-deploy \
role_type=jwt \
user_claim=sub \
bound_audiences="your-org-id" \
bound_claims='{
"oidc.circleci.com/project-id": "your-project-id",
"oidc.circleci.com/context-ids": ["your-context-id"],
"oidc.circleci.com/vcs-ref": "refs/heads/main"
}' \
token_policies=circleci-production-deploy-policy \
ttl=15m
The JWT auth configuration trusts only your CircleCI organization's OIDC issuer. The role then narrows access to a specific project, context, and branch before Vault issues a token.
Workflow configuration
The following example uses a context to provide shared configuration such as the Vault address and role name. If you use context-based claim restrictions in Vault, the job must reference the matching context.
version: 2.1
jobs:
deploy:
docker:
- image: hashicorp/vault:1.19
steps:
- checkout
- run:
name: Retrieve secrets from Vault
command: |
# Authenticate using the CircleCI OIDC token (v2)
# This example uses the v2 token together with a production context
export VAULT_TOKEN=$(vault write -field=token auth/jwt/login \
role=circleci-production-deploy \
jwt=$CIRCLE_OIDC_TOKEN_V2)
# Retrieve only the secrets this job needs
export DATABASE_PASSWORD=$(vault kv get \
-field=password secret/ci/production/db)
export API_KEY=$(vault kv get \
-field=key secret/ci/production/api)
# Pass to subsequent steps via BASH_ENV
echo "export DATABASE_PASSWORD=$DATABASE_PASSWORD" >> $BASH_ENV
echo "export API_KEY=$API_KEY" >> $BASH_ENV
- run:
name: Deploy
command: deploy.sh
workflows:
deploy:
jobs:
- deploy:
context:
# Store VAULT_ADDR and VAULT_ROLE here, not secrets
- vault-production
The job exchanges the CircleCI OIDC token for a short-lived Vault token, then
retrieves only the secrets required for the deployment. The CircleCI context
supplies shared configuration and, when used in bound_claims, adds an
additional authorization boundary.
If your pipeline needs to authenticate with a custom aud claim — for example,
to differentiate Vault tokens from other cloud provider OIDC flows in the same
job — generate a token with a custom audience using the CircleCI CLI:
- run:
name: Retrieve secrets with custom audience
command: |
CUSTOM_TOKEN=$(circleci run oidc get --claims '{"aud": "vault"}')
export VAULT_TOKEN=$(vault write -field=token auth/jwt/login \
role=circleci-production-deploy \
jwt=$CUSTOM_TOKEN)
This pattern is useful when the same job participates in multiple OIDC-based trust flows and you want Vault-specific audience separation.
Policy
The Vault policy for any role should follow least privilege. A pipeline that deploys to production should not be able to read staging secrets, and vice versa.
# Vault policy: scope to exactly the paths this pipeline needs
path "secret/data/ci/production/db" {
capabilities = ["read"]
}
path "secret/data/ci/production/api" {
capabilities = ["read"]
}
# Deny staging paths explicitly if path structure overlaps
path "secret/data/ci/staging/*" {
capabilities = ["deny"]
}
The policy limits the job to the exact production secret paths it needs. Explicit deny rules are useful when path structures overlap and you want to prevent accidental access to staging data.
Security considerations
There are several CircleCI-specific security considerations you need to align with your organizational risk tolerance and operational constraints:
- Context references and OIDC claims. CircleCI can issue OIDC tokens
without a context reference, but many Vault integration patterns use a
context to scope access and supply shared configuration. If your Vault role
binds to
oidc.circleci.com/context-ids, the job must reference the corresponding context or authentication will fail. context-idsbinding as a security gate. Binding a Vault role tooidc.circleci.com/context-idsmeans a job must have been explicitly granted access to that context by a CircleCI organization admin. This is the recommended pattern for production-scoped roles — it creates a two-factor access model where project identity alone is not sufficient to authenticate.- Forked PR builds and OIDC exposure. CircleCI does not generate OIDC
tokens for forked PR builds by default. If you enable this setting, you must
add
oidc.circleci.com/vcs-origintobound_claimsto prevent a fork from authenticating to the same Vault roles as the upstream repository. - Clock skew and token validation. A known operational issue exists where
Vault rejects CircleCI OIDC tokens with a "token not yet valid" error due to
clock skew between CircleCI's token issuance and Vault's validation. Mitigate
this by setting
clock_skew_leewayon the JWT auth configuration in Vault. - Air-gapped CircleCI Server. CircleCI Server installations in air-gapped environments may not be able to use OIDC token issuance, depending on how the deployment is configured. In those environments, AppRole with response wrapping becomes the required auth method.
For a list of additional security considerations, refer to the CI/CD security considerations page.
The CI/CD security considerations page also covers general topics such as JWT role constraints, policy least privilege, and namespace isolation.
Integrate HCP Vault Radar
Before migrating to Vault-based secrets management, Vault Radar can scan existing CircleCI pipeline definitions and connected repositories for credentials stored as hardcoded values or as CircleCI project and context environment variables that should be moving to Vault. This is particularly relevant for organizations that have distributed credentials across multiple CircleCI contexts, projects, and organizations over time.
After migration, Vault Radar can monitor repositories continuously for new secret introductions — catching cases where developers hardcode credentials that should be going through Vault, or where a pipeline references a variable that was deprecated as part of the migration.
Refer to the HCP Vault Radar quick start tutorials to learn about HCP Vault Radar.
HashiCorp resources
Vault
- Read the JWT/OIDC auth method documentation to configure Vault to validate CircleCI OIDC tokens.
- Read the Kubernetes auth method documentation to authenticate self-hosted runner pods using projected service account tokens.
- Read the AWS auth method documentation to authenticate self-hosted runners running on AWS compute.
- Read the Azure auth method documentation to authenticate self-hosted runners running on Azure compute.
- Read the GCP auth method documentation to authenticate self-hosted runners running on Google Cloud.
- Read the AppRole auth method documentation to configure bootstrap credentials for isolated environments.
- Read the TLS certificate auth method documentation to configure mTLS-based authentication for persistent runners.
- Read the Response wrapping documentation to learn how to deliver single-use secret IDs securely.
- Follow the Dynamic secrets: database credentials tutorial to generate short-lived database credentials from Vault.
- Follow the Generate cloud credentials with Vault tutorial to issue temporary cloud provider credentials for pipeline jobs.
Terraform
- Read the Vault provider for Terraform documentation to manage Vault configuration as code.
External resources
- Read Integrate CircleCI with HashiCorp Vault using OIDC for a walkthrough of the CircleCI and Vault OIDC integration.
- Read Role-based credential management with OIDC to learn how to scope Vault access by CircleCI job context.
- Read Using OpenID Connect tokens in jobs for the official CircleCI documentation on OIDC token issuance.
- Read OIDC tokens with custom claims to understand the claims available for Vault role binding.
- Read Connect CircleCI with Vault using OIDC for a field guide walkthrough of the integration.
Next steps
In this section of managing CI/CD secrets, you learned how to bind CircleCI job identity to Vault auth methods and how to select the right auth method based on where your runners are deployed. Secure CircleCI secrets with HashiCorp Vault is part of the Secure systems pillar.