This article covers the secrets
keyword in GitLab CI/CD, explaining its utility in securely passing external secrets (like those from HashiCorp Vault) into your pipeline jobs. We will explore how to define secret variables, specify their providers, and manage their access within your CI/CD configuration, ensuring sensitive information remains protected while enabling secure interactions with external services.
Understanding the secrets
Keyword in GitLab CI/CD
The secrets
keyword in GitLab CI/CD is used to define external secrets that a job requires. Unlike regular CI/CD variables (even protected ones), the secrets
keyword is specifically designed for integration with external secret management systems, primarily HashiCorp Vault. It allows you to inject sensitive data from these external sources into your pipeline jobs in a controlled and secure manner, without exposing them directly in your .gitlab-ci.yml
file or as regular environment variables.
Why Use the secrets
Keyword?
Using the secrets
keyword offers significant advantages for security and secret management:
- Enhanced Security: Prevents sensitive data from being hardcoded or directly exposed in your
.gitlab-ci.yml
file or in job logs. - Centralized Secret Management: Integrates with dedicated secret management systems (like Vault), which are designed for secure storage, access control, and auditing of secrets.
- Dynamic Secret Generation: Allows for dynamic generation of credentials (e.g., short-lived database credentials), improving security by reducing the lifetime of secrets.
- Reduced Secret Sprawl: Avoids scattering secrets across various CI/CD variables or environments.
- Compliance: Helps meet compliance requirements for handling sensitive information.
Configuring secrets
in .gitlab-ci.yml
The secrets
keyword is defined at the job level. When a job with secrets
runs, GitLab contacts the configured secret management provider (e.g., Vault), retrieves the specified secrets, and injects them as environment variables into the job’s execution environment.
Basic secrets
Definition (HashiCorp Vault Example)
To use the secrets
keyword, you first need to have GitLab integrated with HashiCorp Vault. This involves configuring the Vault server and the GitLab Runner to communicate with it. Once configured, you can define secrets like this:
# .gitlab-ci.yml
production_deploy:
stage: deploy
script:
- echo "Deploying to production using secrets..."
- >
# Access secrets as environment variables
# VAULT_DB_USERNAME and VAULT_DB_PASSWORD are automatically set
# by GitLab from the Vault path
./deploy_app.sh "$VAULT_DB_USERNAME" "$VAULT_DB_PASSWORD"
secrets:
VAULT_DB_USERNAME:
vault: secret/data/production/webapp/db:username # Path to secret in Vault
VAULT_DB_PASSWORD:
vault: secret/data/production/webapp/db:password # Path to secret in Vault
rules:
- if: '$CI_COMMIT_BRANCH == "main"'
when: manual # Only deploy to prod manually from main branch
In this example:
VAULT_DB_USERNAME
andVAULT_DB_PASSWORD
: These are the local environment variable names that will be created in the job’s environment. You can choose any valid variable name.vault
: This indicates that the secret is coming from a HashiCorp Vault integration.secret/data/production/webapp/db:username
: This is the path to the secret in Vault, followed by a colon:
and the key within that secret whose value you want to retrieve.secret/data/production/webapp/db
: The full path to the secret in your Vault.username
: The specific key within that secret.
When production_deploy
job runs, GitLab will:
- Authenticate with the configured HashiCorp Vault server.
- Read the secret at
secret/data/production/webapp/db
. - Extract the values for
username
andpassword
. - Inject these values as environment variables
VAULT_DB_USERNAME
andVAULT_DB_PASSWORD
into the job’s shell environment.
Defining Multiple Secrets and Providers
You can define multiple secrets under the secrets
keyword. While currently primarily used with HashiCorp Vault, the structure is designed to support other secret providers in the future.
deploy_with_multiple_secrets:
stage: deploy
script:
- echo "Using multiple secrets from Vault..."
- ./configure_service.sh "$VAULT_API_KEY" "$VAULT_QUEUE_ACCESS_TOKEN"
secrets:
VAULT_API_KEY:
vault: production/api/service:api_key
VAULT_QUEUE_ACCESS_TOKEN:
vault: common/messaging/queue:access_token
Secret Defaults (default
)
(GitLab Premium/Ultimate) You can define default settings for secrets
at the top level of your .gitlab-ci.yml
, which jobs can then override or extend.
# .gitlab-ci.yml
secrets:
default:
vault:
engine: 'kv-v2' # Specify the Vault KV engine version
path: 'secret/data' # Default base path in Vault
stages:
- deploy
deploy_backend:
stage: deploy
script:
- echo "Deploying backend with default secret path..."
- ./deploy_backend.sh "$DB_CONN_STR"
secrets:
DB_CONN_STR:
vault: 'backend/config:connection_string' # This path will be relative to default.path if engine is 'kv-v2' and path isn't absolute.
# Full path would be secret/data/backend/config:connection_string
The secrets:default
block, especially for vault
, allows you to configure global parameters for Vault integration, such as the engine
(e.g., kv-v2
for KV Secret Engine – Version 2) and path
(a default base path for secrets). This reduces repetition in individual job definitions.
How Secrets are Accessed in Jobs
Once defined with secrets
, the values are injected as environment variables into the job’s shell. This means you can access them using standard shell syntax (e.g., $VAULT_DB_USERNAME
in Bash, %VAULT_DB_USERNAME%
in Windows Batch).
GitLab runners ensure that these variables are:
- Not exposed in job logs: Their values are masked.
- Available only during the job’s execution: They are not persisted after the job completes.
- Accessible within the job’s script context: Any command or script executed by the job can use them.
Pre-requisites and Setup
To use the secrets
keyword with HashiCorp Vault:
- HashiCorp Vault Server: You need a running and accessible HashiCorp Vault server.
- GitLab Instance/Project Integration: Your GitLab instance (or specific project) must be configured to integrate with HashiCorp Vault. This typically involves:
- Enabling the Vault integration in GitLab settings.
- Configuring the Vault address and an authentication method (e.g., JWT, AppRole).
- Ensuring the GitLab Runner has network access to the Vault server.
- Configuring Vault policies to grant GitLab read access to the necessary secret paths.
- Secrets Stored in Vault: The secrets you reference in your
.gitlab-ci.yml
must exist at the specified paths and keys within your Vault.
Best Practices for Using secrets
- Integrate with a Dedicated Secret Manager: Always use a dedicated secret management solution like HashiCorp Vault for sensitive data rather than relying solely on CI/CD variables for highly critical information.
- Least Privilege: Configure Vault policies to grant GitLab (and specifically, the pipeline’s identity) only the minimum necessary read permissions to the secret paths it requires.
- Use Specific Paths/Keys: Reference specific secret paths and keys within Vault to minimize the scope of access. Avoid overly broad permissions.
- Masking in Logs: While
secrets
are automatically masked, be careful not toecho
their values explicitly in yourscript
unless absolutely necessary for debugging and you understand the risks. - Short-Lived Credentials (Dynamic Secrets): If your Vault configuration supports it, use dynamic secrets (e.g., dynamically generated database credentials) to further reduce the risk associated with long-lived credentials.
- Regular Auditing: Regularly audit access to your secrets in Vault and monitor GitLab CI/CD job logs for any suspicious activity.
- Consider Environments: Scope your secrets in Vault by environment (e.g.,
production/db-creds
,staging/db-creds
) to align with your deployment strategy and prevent accidental use of production secrets in lower environments.
FAQs – GitLab CI/CD Secrets
What is the secrets
keyword in GitLab CI/CD?
The secrets
keyword in GitLab CI/CD is used to securely inject secrets (like passwords, credentials, API keys, tokens, etc.) into your job at runtime. These secrets are managed using GitLab’s built-in Vault integration, allowing access to ephemeral, scoped, and revocable secret values.
How is secrets
different from variables
in GitLab CI/CD?
variables
: Stored in GitLab (project/group-level), encrypted at rest, but exposed as environment variables during job execution.secrets
: Pulled from an external secrets manager (Vault) and are not stored in GitLab. Secrets are dynamically retrieved and safer for sensitive data.
How do I configure secrets
in a GitLab CI/CD job?
To use secrets
, you must first connect GitLab to HashiCorp Vault (or use GitLab’s internal Vault). Then define secrets in your job like this:
deploy:
stage: deploy
script:
- echo "$MY_SECRET_VAR"
secrets:
MY_SECRET_VAR:
vault: production/db/password
Here, MY_SECRET_VAR
will hold the secret fetched from the Vault path production/db/password
.
Do I need to install Vault separately to use secrets in GitLab?
No. GitLab provides a built-in Vault integration (available in GitLab Premium/Ultimate and GitLab.com).
You need to enable it in project settings under CI/CD → Vault and configure access policies.
How are secrets injected into a job using the secrets
keyword?
Secrets defined under the secrets:
block are injected as environment variables just like CI/CD variables. However, they are retrieved at job runtime, reducing the risk of exposure.
Can I use secrets from an external Vault server (self-managed)?
Yes. GitLab supports integration with external Vault servers. You must:
- Enable JWT authentication in Vault.
- Configure policies to allow secret access.
- Register your Vault details in GitLab’s project settings.
Can I use secrets in all GitLab plans?
No. The secrets
keyword requires:
- GitLab Premium (self-managed)
- GitLab.com Premium or Ultimate
- GitLab 14.4+ for basic support, full features in later versions
It is not available on the Free tier.
What happens if a secret is not accessible or Vault is misconfigured?
If the Vault integration fails or the secret path is inaccessible:
- The job will fail with an error
- GitLab Runner logs will indicate the problem
- You should check Vault policies, paths, and integration settings
Can I specify multiple secrets in a job?
Yes. You can list multiple secret variables under the secrets
block:
job:
script:
- echo "Using secrets"
secrets:
AWS_ACCESS_KEY:
vault: aws/creds/key
AWS_SECRET_KEY:
vault: aws/creds/secret
Each secret is injected as its own environment variable.
Can I limit which jobs can access specific secrets?
Yes. Secrets are job-scoped, and access is defined by Vault policies. You can:
- Restrict which paths a job token can access in Vault.
- Use dynamic path templating (e.g., use
$CI_JOB_ID
,$CI_COMMIT_BRANCH
).
This enhances security by minimizing access exposure.
Are secrets masked in GitLab job logs?
Yes. Secrets injected using the secrets
keyword are automatically masked in logs, just like masked CI/CD variables. However, you should still avoid echoing them.
Can I use secrets in child pipelines or included YAML files?
Yes. The secrets
keyword is fully supported in all job contexts, including:
- Child pipelines (
trigger
) - External includes
- Dynamic
.gitlab-ci.yml
generation
Just ensure that Vault access is properly configured across pipeline scopes.
What is an example of a complete .gitlab-ci.yml
using secrets
with Vault?
stages:
- deploy
deploy_prod:
stage: deploy
script:
- echo "Deploying using secret: $DB_PASSWORD"
secrets:
DB_PASSWORD:
vault: production/database/password
Assuming Vault contains a secret at production/database/password
, the value is injected as DB_PASSWORD
.
Can I use secrets
with Kubernetes or Docker runners?
Yes. The secrets
keyword works with all runner types, as long as Vault integration is configured. For Kubernetes runners, this is often paired with service accounts or injected tokens.
Author

Experienced Cloud & DevOps Engineer with hands-on experience in AWS, GCP, Terraform, Ansible, ELK, Docker, Git, GitLab, Python, PowerShell, Shell, and theoretical knowledge on Azure, Kubernetes & Jenkins. In my free time, I write blogs on ckdbtech.com