Chapter 13Lesson 03~215 minutes

CI/CD Variables, Inputs, Secrets, File Variables, Masking, Protection, and Scope: Configuration, Design Choices, and Tradeoffs

Choose between variables, typed inputs, project/group scope, protected and environment-scoped values, external secret managers, and broad inheritance using least-privilege and maintainability criteria.

Least privilegeEnvironment scopeOIDCExternal secretsInheritanceGovernance

Learning objectives

  • Choose between typed inputs and runtime variables based on mutability, validation, and trust.
  • Choose project, group, or instance scope without creating unnecessary inheritance blast radius.
  • Combine protected-ref and environment scoping deliberately rather than treating them as substitutes.
  • Compare stored CI/CD variables with OIDC-backed external secret retrieval.
  • Use pipeline-variable restrictions and current expansion behavior as part of a production governance model.
Availability baseline (verified 2026-08-21; GitLab 19.3 is the latest monthly release, released 2026-08-20). Project and group CI/CD variables, masking, hiding, protection, file variables, pipeline inputs, predefined variables, and OIDC ID tokens are available on Free/Premium/Ultimate across GitLab.com, Self-Managed, and Dedicated unless a narrower note is stated. Instance variables are Self-Managed/Dedicated administrator scope. Group-variable environment scoping is Premium/Ultimate. GitLab's built-in external-secret provider integrations are Premium/Ultimate, while the underlying ID-token/OIDC mechanism is Free. The mandatory chapter path uses only a disposable project, synthetic values, and a no-paid validation/fixture fallback.

1. Design principle: choose the narrowest mechanism that matches the data

The easiest pipeline to write is often the hardest to govern: put everything in variables, let every job inherit it, and override values when necessary. Production CI should do the opposite. First classify the data as configuration parameter, runtime setting, or secret; then choose the smallest scope and shortest lifetime that works.

2. Typed input versus variable

Question Choose input when… Choose variable when…
Who changes it? A pipeline/configuration consumer selects from a documented contract. The job needs runtime data supplied by settings/policy/system context.
Validation Type/options/regex should reject invalid configuration before jobs exist. Validation happens in application/job logic or is not required.
Mutability Value should be fixed for configuration creation. Value may be resolved/overridden according to GitLab precedence.
Sensitivity Value is non-secret configuration. A settings variable may hold sensitive data only if no better secret system exists; mask/hide/protect it.
Auditability You want an explicit reusable-template interface. You need standard CI environment-variable behavior.

Pipeline inputs are recommended over pipeline variables for run-time parameters. If inputs meet the need, restrict or disable pipeline variables so a high-precedence untyped value cannot silently override the pipeline contract.

3. Project versus group versus instance scope

Scope Good fit Risk
Project One application or repository owns the value. Duplication across many projects if the value is truly shared.
Group/subgroup Shared non-secret configuration or carefully governed shared credential used by multiple projects. Every inheriting project’s CI becomes part of the trust boundary; subgroup/project overrides can change the effective value.
Instance Self-Managed/Dedicated administrator default across the instance. Largest blast radius and administrative coupling; unavailable as a user-managed GitLab.com instance setting.

Centralization reduces duplication only when the trust domain is actually shared. Do not put a production credential at group scope merely because several projects happen to deploy to the same platform.

4. Protected ref and environment scope answer different questions

Protected asks: “Is this pipeline running on an approved protected branch or tag?” Environment scope asks: “Is this job targeting an environment whose name matches the scope?” A production deployment may need both controls, plus a protected environment and appropriate runner isolation in later chapters.

Control Protects against Example
Protected variable Untrusted/unprotected refs receiving the value. Deploy credential available only on protected main or release tags.
Environment-scoped variable Unrelated jobs/environments receiving the value. Staging endpoint available only to staging environment jobs.
Both Ref and environment must both be appropriate. Production value only in a protected-ref job targeting production.

Current GitLab supports environment scope on project variables. Environment scope for group variables is Premium/Ultimate. Do not use environment-scoped variables inside rules or include logic because those values may not be available when pipeline configuration is validated.

5. Broad inheritance versus explicit duplication

A shared group variable can simplify fleet-wide configuration, but it also makes every inheriting project's pipeline code a potential consumer. Prefer group scope for values that genuinely belong to the group trust domain. Prefer project scope when ownership, rotation cadence, or incident response differs by application.

If the same key exists at group and project levels, project wins. This override ability is useful for migration, but can also hide stale group configuration. Inventory all same-name definitions during incidents and deprecations.

6. Variable expansion: opt in only when it buys something

UI variable expansion is disabled by default in GitLab 18.6 and later. This is a safer default because values containing $ are treated literally unless expansion is intentionally enabled. Masked/hidden variables cannot use variable-reference expansion.

Prefer explicit composition in application configuration or scripts with well-quoted variables rather than nested secret expansion. Complex chains make precedence and incident response harder to reason about.

7. Pipeline variables: treat high precedence as delegated authority

Allowing a user to set pipeline variables is allowing that user to override project, group, instance, and YAML values. GitLab therefore provides a project setting for the minimum role allowed to use pipeline variables, including no_one_allowed. Use the narrowest role compatible with your workflow, and prefer inputs for ordinary operator parameters.

Production default: if a project has migrated to typed inputs and no longer requires pipeline-variable overrides, disable pipeline variables rather than leaving a legacy override channel open.

8. Stored variable versus external secret manager

Criterion Stored GitLab variable External secret manager / federated retrieval
Setup Simple; built into project/group settings. Requires provider and trust-policy configuration.
Lifetime Typically long-lived until rotated/deleted. Can return short-lived credentials per job/session.
Access model Eligible pipeline code receives the value automatically. Job explicitly authenticates/requests the secret.
Rotation Manual/API process around stored value. Provider can centralize rotation and policy.
Audit boundary GitLab settings + pipeline/job access. GitLab identity plus provider-side policy/audit.
Best fit Small synthetic labs; low-risk settings; transitional secrets with masking/hiding/protection. Production credentials and cross-system access when supported.

9. OIDC separates identity from a long-lived credential

OIDC ID tokens are Free across GitLab.com, Self-Managed, and Dedicated. GitLab signs a short-lived token for the job. The external provider validates its audience and claims, applies its own trust policy, and returns temporary access.

Provider policy should bind stable and narrow claims such as project/namespace identity and allowed ref/environment context. Treat the ID token itself as a credential: never print it, add it to artifacts, or pass it to services outside its intended audience.

10. Built-in external-secret integrations and GitLab Secrets Manager

GitLab's secrets integrations for Vault, Google Cloud Secret Manager, Azure Key Vault, and AWS Secrets Manager are Premium/Ultimate. They use ID-token-based authentication and explicitly requested secrets. The course does not require them.

GitLab Secrets Manager is fast-moving and remains optional here. GitLab's 19.3 release announcement moved the GitLab.com offering into Limited Availability as a paid add-on through GitLab Credits, while the current Self-Managed OpenBao administration documentation still labels that offering Beta and requires GitLab Runner 19.0+ for CI/CD consumption. Re-check offering, status, billing, and Runner requirements before production adoption. The stable design lesson is broader: secret retrieval should be explicit, least-privilege, and preferably short-lived.

11. Worked decision table

Scenario Choice Why
User selects lab/audit for a manual diagnostic Pipeline input Typed, validated, non-secret configuration contract.
One project needs a benign API base URL Project variable or YAML variable No cross-project trust needed; value is non-secret.
Twenty projects share a non-secret artifact mirror URL Group variable Central ownership is useful and exposure is low-risk.
Production database credential for one app External secret manager if available; otherwise masked+hidden+protected project variable as transition Minimize inherited blast radius and long-lived storage.
Certificate content required by a tool File variable or external secret returned as file Tool consumes a path; avoid printing/copying content.
Release credential only for protected release tags Protected scope plus external provider/ref policy Ref trust is part of authorization.

12. Governance checklist before adding a value

  • What classification is the data: public configuration, sensitive configuration, or secret?
  • Which jobs need it? Which jobs must never receive it?
  • Can a typed input replace a high-precedence pipeline variable?
  • Can OIDC/federation replace a stored long-lived credential?
  • What is the narrowest project/group/environment/ref scope?
  • Who can change pipeline code that receives the value?
  • Which runners execute those jobs and what else can they access?
  • How will the value be rotated, revoked, and proven removed?

Knowledge check

Why can a group variable be more dangerous than duplicating a project variable?

Does environment scope replace protected variables?

Why disable pipeline variables after migrating to inputs?

What is the main security advantage of OIDC federation?

What tier constraint matters for group-variable environment scope?

Why is GitLab Secrets Manager not mandatory in this chapter?

Summary

A production variable model begins with classification and least privilege, not with a UI field. Inputs are contracts, variables are runtime data, protected/environment scopes are separate filters, group inheritance expands trust, and OIDC-backed retrieval can replace long-lived stored secrets. The safest design is the one that sends the fewest sensitive values to the fewest jobs for the shortest time.

Official references

Next lesson

Diagnose variable failures without creating a second incident

Lesson 4 walks through missing protected values, precedence surprises, file-path confusion, masking failures, fork trust, and the correct revoke/rotate-first response to a real credential leak.

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.

Ethereum / ERC-20
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0Send only Ethereum/ERC-20 compatible assets to this address.