Filter CI variables per job
Release notes
The recent Codecov security issue highlighted how weak our supply chains can be, by exposing all the CI environment to malicious users. GitLab is adding today a new protection for your variables, especially secrets and other tokens: They can be filtered out for some jobs. Therefore, Protected variables are only available for the jobs that need them, and nothing more. This is the principle of least privilege applied to your jobs!
Problem to solve
Defining CI protected variables is a good way to prevent secret variables from being used in branches and forks. Nevertheless, as stated in our documentation:
Malicious code pushed to your .gitlab-ci.yml file could compromise your variables and send them to a third party server regardless of the masked setting. If the pipeline runs on a protected branch or protected tag, malicious code can compromise protected variables. Review all merge requests that introduce changes to the .gitlab-ci.yml file [...]
This is especially true because all these protected variables are available to all the jobs of the pipeline. It seems obvious that not all of them are necessary all the time, and therefore, we're exposing variables unnecessarily.
By filtering what variables are available for jobs, we can protect them with a fine grained configuration.
Intended users
User experience goal
The user should be able to defined in their GitLab-CI configuration file what variables should be available or removed.
Proposal
Updated from #329209 (comment 714218033)
We can keep the current variables to avoid a breaking change. They would still be accessible and visible by every job in the pipeline.
To filter out variables, we could add a new "Secrets" section similar to "Variables". These secrets are only made explicitly available to jobs through the existing secrets
key:
job:
secrets:
DATABASE_PASSWORD:
gitlab: DATABASE_PASSWORD_MAPPING_KEY_HERE
file: false
or even just
job:
secrets:
DATABASE_PASSWORD:
file: false
where the mapping to the DATABASE_PASSWORD
is implicit.
This create a migration path for users, where they can still use the existing variables
feature, and move their secrets one by one, project by project, to the new secrets feature.
Note: Since secrets are considered sensitive data, they would be available only in the project settings, and not through a new secrets
YAML key allowing to define them. We don't want to leave tokens in clear in the CI/CD files.
Old proposal
I would find it odd to have to list jobs in the UI, whereas jobs are defined in a file. Therefore, my suggestion would be to add new keys to jobs definition.
The variables
dictionary could be updated to have only
and except
keywords, but they would be mixed with real variables, so I don't think it's a viable solution:
job1:
variables:
TEST_VAR_JOB: "Only job1 can use this variable's value"
only:
- PYPI_TOKEN
script:
- echo $PYPI_TOKEN and $TEST_VAR_JOB
Instead, it's probably better to have this kind of key:
job1:
variables:
TEST_VAR_JOB: "Only job1 can use this variable's value"
variables_only:
- PYPI_TOKEN
script:
- echo $PYPI_TOKEN and $TEST_VAR_JOB
This could be also mutually exclusive with variables_except
.
This is similar to how secrets are managed by Kubernetes. Secrets are mounted only in the pods that need them.
Further details
The chosen solution will let the users defined precisely what variables are available for jobs.
The filter will only occur for variables defined in the UI, and won't have any effect on those defined by the variables
keyword (which should never contain secrets).
If one job is compromised, like for example the codecov recent issue, the job would not have access to ALL the environment. It's common for opensource projects to have multiple tokens (PyPi, Docker hub, ...), and sharing them with all the jobs (understand: images) is taking a risk for no added value.
Permissions and Security
Documentation
Update https://docs.gitlab.com/ee/ci/variables/#cicd-variable-security
Availability & Testing
Available Tier
- Free
What does success look like, and how can we measure that?
What is the type of buyer?
Is this a cross-stage feature?
No
Links / references
Credits go to @thiagocsf for suggesting this idea.