GitLab Secrets Manager expands to Kubernetes and Terraform to unify secret management
GitLab extends its OpenBao-powered Secrets Manager to the External Secrets Operator, Terraform, and a direct API, beyond CI/CD alone. The pitch: replace scattered secret stores across CI/CD, Kubernetes, and IaC with a single audited source of truth.
August 6, 2026. GitLab announces that its Secrets Manager now reaches beyond the CI/CD pipeline. The service, powered by OpenBao and exposed through a Vault-compatible KV v2 API, can now feed Kubernetes via the External Secrets Operator, Terraform and OpenTofu, and any external automation through a dedicated API. It closes a familiar loop: the secret scattered across three stores that nobody can correlate.
The starting problem is well known. A team keeps one vault for CI/CD, another for Kubernetes workloads, a third — often .tfvars files committed by mistake — for Terraform. Three tools to operate, three access models to keep in sync, and an audit trail impossible to reconstruct when a secret leaks. GitLab’s promise is simple: one source of truth. And that source has to be auditable: when a secret leaks, the first question — who had access, and since when — should be answered in a single query, not across three tools.
What actually changes
GitLab’s Secrets Manager is not new. It is in public beta for Premium and Ultimate customers, and CI/CD has accessed it since version 19.0. What changed is the opening beyond the pipeline, along three paths.
First, Kubernetes. The External Secrets Operator (ESO) syncs secrets from the Secrets Manager through its Vault provider. A workload carries a short-lived JWT, which ESO exchanges for an OpenBao token, then writes the value into a native Kubernetes Secret. The core of the setup is two objects:
apiVersion: external-secrets.io/v1
kind: SecretStore
metadata:
name: gitlab-secrets-manager
namespace: my-app
spec:
provider:
vault:
server: https://secrets.gitlab.com
path: secrets/kv
version: v2
namespace: org_5/group_42/project_99
auth:
jwt:
path: api_jwt/cel
role: all_api
secretRef:
name: gitlab-access-token
key: token
---
apiVersion: external-secrets.io/v1
kind: ExternalSecret
metadata:
name: my-secret
namespace: my-app
spec:
refreshInterval: 45m
secretStoreRef:
name: gitlab-secrets-manager
kind: SecretStore
target:
name: synced-secret
data:
- secretKey: value
remoteRef:
key: explicit/<secret_name>
property: value The namespace field on the SecretStore maps the GitLab hierarchy — organization, group, project — and bounds what this store can reach. The ExternalSecret then pulls values every refreshInterval, so a rotation propagates without a redeploy.
The security model: short tokens, strict scopes
Under the hood, everything runs on short-lived tokens. No workload holds a permanent credential: GitLab mints a JWT with a limited lifetime, which ESO, Terraform, or the API exchange for an ephemeral OpenBao token. It is just-in-time authentication at work: the exposure window for a stolen secret is measured in minutes, not months.
The namespace acts as the boundary. Each SecretStore is scoped to a precise GitLab hierarchy — an organization, a group, a project — and can only read the secrets that live there. It mirrors the existing GitLab permission model: a project sees only its own secrets, never its neighbor’s. For a platform team, that removes the classic shared-vault scenario where one service token ends up opening every door.
The benefit shows in incident response. With short-lived tokens and per-project namespaces, a leaked credential has a small blast radius and expires on its own — you don’t have to rotate a fleet of long-lived service accounts. That is the difference between a cleanup measured in minutes and one measured in weeks.
Terraform and OpenTofu, without .tfvars
The second path targets IaC. .tfvars and the Terraform state remain two of the biggest sources of leaked credentials: the value ends up on disk or pushed into a repository. GitLab proposes reading the secret as a data source, authenticating with a JWT minted at plan or apply time:
data "external" "gitlab_secrets_token" {
program = ["bash", "${path.module}/scripts/mint_token.sh"]
query = { project_id = var.gitlab_project_id }
}
provider "vault" {
address = data.external.gitlab_secrets_token.result.server
namespace = data.external.gitlab_secrets_token.result.namespace
auth_login_jwt {
mount = data.external.gitlab_secrets_token.result.auth_path
role = data.external.gitlab_secrets_token.result.role
jwt = data.external.gitlab_secrets_token.result.jwt
}
}
data "vault_kv_secret_v2" "my_secret" {
mount = data.external.gitlab_secrets_token.result.mount
name = "${data.external.gitlab_secrets_token.result.secrets_path}/<secret_name>"
}
output "secret_value" {
value = data.vault_kv_secret_v2.my_secret.data["value"]
sensitive = true
} Nothing passes through a CI/CD variable or a local file: the secret is read at runtime, then surfaced as a sensitive output. The third path, the Secrets Manager API, covers everything else — a script, a home-grown operator, an observability tool — that previously had to hardcode credentials.
What it costs, and what it demands
The commercial model deserves a read before you commit. The Secrets Manager is free during the beta; at general availability it becomes a paid feature, billed through GitLab Credits, with an explicit opt-in and advance notice. Availability covers GitLab.com and Self-Managed; GitLab Dedicated follows.
The architecture rests on OpenBao, the community fork of Vault born after HashiCorp’s license change. In practice, anything that speaks Vault — the vault CLI, ESO, the Terraform providers — can connect. That is both the product’s strength and its limit: GitLab is not reinventing the wheel, it is standardizing on an already widely deployed API, which lowers adoption friction but also narrows differentiation against a self-hosted Vault or OpenBao.
What is missing today, for now: there is no dynamic secrets engine or PKI backend yet, and the audit surface — who read which secret, when — is younger than Vault’s. Teams with heavy compliance needs should treat those gaps as a checklist, not a blocker.
Why OpenBao, and what it changes for you
The choice of OpenBao is not a detail. When HashiCorp moved Vault to the BUSL license, part of the community forked it to create OpenBao, kept under MPL-2.0. By standardizing its Secrets Manager on a Vault-compatible KV v2 API, GitLab avoids two pitfalls: reinventing a proprietary protocol, and depending on a license some customers find restrictive.
The practical consequence: the entire existing Vault ecosystem — the CLI, the Terraform providers, ESO, the SDKs — works as-is. You don’t retrain teams on a new tool; you plug in what they already know. Against a self-hosted OpenBao, GitLab brings no secret extra capability: it brings integration, and the disappearance of a server to operate.
Migrating without breaking anything
The trap of such a tool is wanting to switch everything at once. Don’t. The cautious sequence has three steps: inventory the secrets and their consumers, switch scope by scope — start with a non-critical project, wire up ESO then Terraform — and coexist for a few weeks, the old store and the new running in parallel.
One point people forget: the exit. The day GitLab starts billing the feature, or the day you change your mind, you’ll need a way back. Document the provenance of every secret — where it’s stored, who reads it, how often — before you migrate. A secret whose trail you’ve lost is a secret you can no longer rotate without breakage. Treat the migration like any other infrastructure change: reversible, observable, and rolled back by the same automation that rolled it forward.
The cold verdict
If you are already on GitLab Premium or Ultimate and juggling several secret stores, the consolidation is worth it: you drop a tool to operate and, more importantly, you get back a single audit trail — something security teams have asked for for years. The ESO provider covers the most common Kubernetes case, and the data source read fixes the committed-.tfvars problem.
If you are multi-cloud, multi-CI, or need fine-grained dynamic secrets — dynamic secrets, PKI, rotation at scale — stay on self-hosted Vault or OpenBao: GitLab Secrets Manager is still young, and its advanced capabilities are limited next to a mature Vault.
In all cases, don’t migrate production secrets during the beta. Today’s free tier hides a future billing model that is not yet defined; wait for GA, the GitLab Credits price, and test recovery on a non-critical scope. A secret is not something you migrate casually.