GitLab CI variables are a powerful way to inject configuration and secrets into your pipelines, but storing sensitive information like API keys or passwords requires careful consideration.

Here’s a look at how GitLab CI variables work and how to use them securely.

The Problem: Insecurely Stored Secrets

Imagine you have a script in your GitLab CI pipeline that needs to deploy your application to a cloud provider. This script requires an API key. If you store this API key directly in your .gitlab-ci.yml file, it’s a massive security risk. Anyone with read access to your repository would have your API key.

deploy_job:
  stage: deploy
  script:
    - echo "Deploying with API key: $CLOUD_API_KEY" # BAD PRACTICE!
    - deploy_script --api-key $CLOUD_API_KEY

This is where GitLab CI variables come in, offering a more secure alternative.

Storing Secrets as Protected and Masked Variables

GitLab provides two key features for securing CI variables: Protected and Masked.

  1. Protected Variables: These variables are only available to jobs running on protected branches or tags. This prevents them from being exposed in pipelines for feature branches that might be more experimental or less scrutinized.

  2. Masked Variables: When a variable is masked, its value is hidden in job logs. Instead of seeing the actual secret, you’ll see a masked string like ****123abc. This prevents accidental exposure in CI logs, which are often shared or archived.

How to Set Them Up

You can set CI variables in two main places:

  • Project Settings: Go to your GitLab project -> Settings -> CI/CD -> Variables.
  • Group Settings: Go to your GitLab group -> Settings -> CI/CD -> Variables. Group variables can be inherited by all projects within that group.

When adding a variable, you’ll see options to:

  • Key: The name of the variable (e.g., CLOUD_API_KEY).
  • Value: The secret itself.
  • Environment scope: You can define variables for specific environments (e.g., production, staging).
  • Protect variable: Check this box to make it available only on protected branches/tags.
  • Mask variable: Check this box to hide its value in job logs.

Example:

Let’s say you want to store your AWS Access Key ID.

  1. Navigate to Settings -> CI/CD -> Variables.
  2. Click Add variable.
  3. Key: AWS_ACCESS_KEY_ID
  4. Value: AKIAIOSFODNN7EXAMPLE (your actual key)
  5. Check Protect variable.
  6. Check Mask variable.
  7. Click Add variable.

Now, in your .gitlab-ci.yml, you can reference this variable:

deploy_job:
  stage: deploy
  script:
    - echo "Deploying to AWS..."
    - aws s3 sync ./build s3://my-awesome-bucket --access-key-id $AWS_ACCESS_KEY_ID # Accessing the variable

When this job runs on a protected branch, $AWS_ACCESS_KEY_ID will be available to the script, but its actual value will be hidden in the job log.

Using Environment Scopes

You can also scope variables to specific environments. This is incredibly useful for managing different credentials for development, staging, and production.

For instance, you might have a PROD_API_KEY and a STAGING_API_KEY.

  1. Add PROD_API_KEY with the value for production.
  2. Add STAGING_API_KEY with the value for staging.
  3. Set the Environment scope for PROD_API_KEY to production.
  4. Set the Environment scope for STAGING_API_KEY to staging.
  5. Both should be Protected and Masked.

Then, in your .gitlab-ci.yml:

deploy_production:
  stage: deploy
  script:
    - echo "Deploying to production..."
    - deploy_script --api-key $PROD_API_KEY
  environment:
    name: production

deploy_staging:
  stage: deploy
  script:
    - echo "Deploying to staging..."
    - deploy_script --api-key $STAGING_API_KEY
  environment:
    name: staging

This setup ensures that the correct API key is used for each deployment environment and that neither key is exposed in logs or on non-protected branches.

The One Thing Most People Don’t Know

GitLab’s CI variable masking has a minimum length requirement for the masked value to be effective. If a variable’s value is shorter than 8 characters, it won’t be masked in the job logs. This is a subtle but important detail; always ensure your secrets are sufficiently long to benefit from masking. If you have a short secret, you might consider prepending it with a random string or padding it to meet the masking threshold.

Next Steps

Once you’ve mastered secure variable management, you’ll likely want to explore how to integrate external secret management tools like HashiCorp Vault or AWS Secrets Manager with your GitLab CI pipelines.

Want structured learning?

Take the full Gitlab course →