Secrets Management, External Secret Providers, Protected Data, Rotation, and Least-Privilege Patterns: Concepts, Architecture, and Mental Model
Secrets are not just variables with more careful names. A production secret has an owner, storage system, authorization decision, retrieval path, lifetime, rotation and revocation procedure, exposure surface, and audit trail. This lesson separates those states so a pipeline can prove who was allowed to retrieve which secret reference without ever treating log masking as the security boundary.
Learning objectives
- Separate secret storage, authorization, retrieval, consumption, log redaction, rotation, revocation, and audit evidence instead of calling all of them “secret management.”
- Explain why masked/hidden/protected CI/CD variables are useful controls but are not equivalent to an external secrets-management system.
- Describe the job-identity → provider trust policy → narrow secret request → temporary materialization → cleanup lifecycle for external secrets.
- Explain why OIDC/ID-token audience and provider-side claims are authorization boundaries, and why an ID token must never be printed or persisted.
- Identify the minimum evidence needed to prove secret access without preserving the secret value itself.
1. The problem: a hidden string is not a secret lifecycle
A pipeline can store a value in GitLab settings, mark it masked, hide it in the UI, protect it to a branch, and still have a weak secret-management design. Once an authorized job receives the value, repository-controlled code can read it. If the value is long-lived, shared broadly, never rotated, or copied into artifacts, the real risk exists outside the masking feature.
A production secret therefore needs several independently reviewable states: where it is stored, which workload identity may request it, which exact secret reference/version is requested, how it reaches the process, how long it remains valid, how it is rotated or revoked, and what evidence can be retained without retaining the secret.
2. The secret-lifecycle mental model
flowchart TD
A[Pipeline source + immutable SHA] --> B[Authorized job identity]
B --> C[Provider trust policy]
C --> D[Secret reference + version]
D --> E[Narrow retrieval]
E --> F[Temporary file / in-memory use]
F --> G[Application or tool]
G --> H[Redacted non-secret evidence]
H --> I[Rotation / revocation]
I --> J[Audit + incident evidence]
The critical arrow is job identity → provider trust policy. A provider does not become safe because GitLab generated a token. The provider must validate issuer, audience, project/ref/environment or other claims that match the intended trust boundary. Retrieval then requests one specific secret—not every credential in a vault.
3. Core objects: name each boundary before using it
| Object | Meaning | Evidence without secret value |
|---|---|---|
| Secret reference | A provider/path/name identifying sensitive material. | Provider name, logical path/name, version/rotation metadata. |
| Job identity | The workload allowed to request a secret. | Pipeline/job ID, source/ref/SHA, ID-token claims decoded only when safe, runner identity. |
| Provider trust policy | Rules deciding which identities may authenticate/authorize. | Expected issuer/audience/project/ref/environment bindings; provider policy revision. |
| Secret material | The sensitive bytes used by a tool/process. | Presence, temporary path, byte count, digest only when appropriate; never raw value. |
| Rotation | Replacement of active material with a newer version. | Old/new version IDs, change timestamp, owner, validation result. |
| Revocation | Removal of the old credential’s ability to authorize. | Denied old version/token and provider/audit event. |
| Audit evidence | Non-secret record of what happened. | Who/what requested which reference, when, with which result. |
4. Variables are a transport/configuration mechanism, not a complete vault
GitLab’s pipeline-security guidance explicitly treats CI/CD variables as less secure than dedicated secret-management providers for sensitive data. Variables are convenient, but they are stored in project/group/instance settings, can be overridden according to precedence, and can be exposed by misconfigured or malicious job code.
If sensitive data must temporarily remain in a CI/CD variable, use the available controls together: mask it, hide it, protect it where practical, scope it narrowly, restrict who can run code in the trusted context, and keep the lifetime short. Those controls reduce accidental exposure; they do not replace rotation, provider authorization, or incident response.
5. External providers change the retrieval model
Current GitLab supports integrations with HashiCorp Vault, Google Cloud Secret Manager, Azure Key Vault, and AWS Secrets Manager. Unlike ordinary CI/CD variables that can be present in jobs by configuration scope, external secrets are explicitly requested by the job. GitLab’s documented provider integrations are currently Premium/Ultimate.
The design benefit is not simply “the secret lives somewhere else.” A mature provider supplies a separate authorization policy, versions, rotation, revocation, access audit, and narrower retrieval. The CI configuration should identify the required secret reference while the provider decides whether the job identity is allowed to receive it.
6. Federated identity: authenticate the job, not a copied long-lived key
GitLab id_tokens can mint OIDC-compatible ID tokens for
a job. ID tokens are available across GitLab tiers, but the external
service must still validate the token correctly. Use an explicit
aud that represents the intended relying service and
bind provider policy to meaningful GitLab claims.
secret_consumer:
id_tokens:
VAULT_ID_TOKEN:
aud: https://vault.example.invalid
script:
- test -n "$VAULT_ID_TOKEN"
- echo "id_token_present=yes" # never print the token
This proves only that the job received an ID token. It does not prove the provider will authorize the job. Provider-side trust policy should restrict the intended issuer/audience and relevant project/ref/environment identity rather than accepting every token from the GitLab instance.
7. The secrets keyword requests narrow material
For supported integrations, GitLab Runner resolves a job’s requested secret before or around job execution according to current provider semantics. A Vault example uses a job ID token plus a specific provider path. By default, retrieved secret values are commonly exposed as temporary files and the environment variable contains the file path.
vault_consumer:
id_tokens:
VAULT_ID_TOKEN:
aud: https://vault.example.invalid
secrets:
DB_PASSWORD:
vault: lab/db/password@ops
token: $VAULT_ID_TOKEN
script:
- test -f "$DB_PASSWORD"
- printf 'secret_file_present=yes\n'
- printf 'secret_bytes=%s\n' "$(wc -c < "$DB_PASSWORD")"
example.invalid and lab/db/password are
documentation placeholders. Do not copy a production secret path,
token, or provider endpoint into course evidence.
8. GitLab Secrets Manager is a separate, evolving product boundary
GitLab now documents a native Secrets Manager for projects and groups. At the current documentation baseline it is Premium/Ultimate, Limited Availability on GitLab.com, Beta on Self-Managed, and uses GitLab Credits/billing semantics on GitLab.com. CI access currently requires GitLab Runner 19.0 or later.
That makes it useful to understand architecturally, but unsuitable as a mandatory beginner lab dependency. The required course path stays free/disposable-compatible with a faithful local provider simulation. When evaluating the native manager in a real organization, re-check availability, permissions, Runner compatibility, branch/environment scope, billing, and deletion/transfer semantics at that time.
9. Rotation and revocation are different completion conditions
Rotation creates or activates new material. Revocation proves old material no longer authorizes access. A rotation procedure is incomplete if the old key/token still works indefinitely.
- Create/activate v2 while v1 still exists if the service needs overlap.
- Update the authorized consumer to use v2 and verify the exact workload.
- Revoke/deactivate v1.
- Prove v1 is denied and v2 succeeds.
- Record evidence and remove temporary material from the runner/workspace.
For an exposed credential, rotate/revoke first; merely deleting the job log or repository line does not make the leaked credential safe again.
10. Read-only inspection before any secret mutation
printf 'pipeline_source=%s\n' "$CI_PIPELINE_SOURCE"
printf 'pipeline_id=%s job_id=%s\n' "$CI_PIPELINE_ID" "$CI_JOB_ID"
printf 'ref=%s sha=%s\n' "$CI_COMMIT_REF_NAME" "$CI_COMMIT_SHA"
printf 'runner_id=%s\n' "${CI_RUNNER_ID:-unknown}"
printf 'runner_desc=%s\n' "${CI_RUNNER_DESCRIPTION:-unknown}"
# Inspect only metadata for the specific synthetic secret/provider you own.
# Never run: env, printenv, set -x, or token-decoding that prints credentials.
For real providers, record the provider name, secret reference/version, trust-policy identity, and retrieval result—not the secret value. For project/group variables, inspect visibility/protection/scope metadata only.
11. Secret-management mistakes to eliminate early
- “Masked means safe from malicious jobs.” It does not; code receiving the secret can transform or exfiltrate it.
- “Protected branch means every job on it deserves every secret.” Secret authorization should still be workload-specific and least privilege.
- “Moving a password to a group variable creates centralized secrets management.” It centralizes storage but can broaden inheritance and does not add provider-side lifecycle controls.
- “OIDC removes authorization design.” OIDC authenticates identity; provider trust policy decides what that identity may do.
- “Rotation is done when v2 works.” You must also prove v1 is revoked.
- “Deleting leaked output fixes exposure.” Treat the credential as compromised and rotate/revoke it.
Knowledge check
Why is a masked CI/CD variable not equivalent to a secrets manager?
Masking mainly reduces accidental log disclosure. It does not supply independent provider authorization, narrow retrieval, version lifecycle, rotation/revocation, or protection against malicious job code that receives the value.
What must an external provider validate besides “this token came from GitLab”?
The intended audience and meaningful workload claims such as project/path/ref/environment or other context that defines the allowed job identity.
What proves a rotation is complete?
The new version works for the intended consumer and the old version/credential is demonstrably revoked or denied.
Should an evidence packet contain a raw secret so an auditor can reproduce the run?
No. Preserve identity, reference/version, timestamps, authorization result, digests/metadata where appropriate, and pipeline/job context—not reusable secret material.
Why is the native GitLab Secrets Manager optional in this chapter?
Its current tier/availability/billing/Runner requirements are evolving; the mandatory course path must remain free and disposable-compatible.
Official references and version notes
- Pipeline security — current guidance that CI/CD variables are less secure than dedicated secret-management providers and that sensitive values should use stronger secret-management controls where possible.
- CI/CD variables — masking, hiding, protection, fork/MR behavior, file variables, and explicit warnings that masking is not a defense against malicious job code.
- External secrets in CI/CD — current supported provider integrations and tier/offering requirements.
- OIDC authentication using ID tokens — job-scoped ID tokens, audiences, claims, and third-party trust boundaries.
-
HashiCorp Vault secrets
—
id_tokens,secrets:vault, file materialization, and provider-side authorization. - GitLab Secrets Manager — current limited/beta availability, permissions, branch/environment scoping, Runner requirements, rotation reminders, and file-by-default behavior.
- Secret detection — defense-in-depth for accidentally committed credentials; detection is not a substitute for rotation after exposure.
Secret-management behavior in this chapter was rechecked against current primary GitLab documentation on 2026-09-11. External-secret integrations documented by GitLab are currently Premium/Ultimate; ID tokens are available on Free/Premium/Ultimate. GitLab Secrets Manager is availability/billing sensitive and currently requires GitLab Runner 19.0 or later for CI access, so it is discussed as an optional current-platform path rather than a mandatory lab dependency. The mandatory exercises use generated synthetic values and a local provider simulation.
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this
address.