Cross-project permissions for CI tokens
Description
Developers need to perform actions on multiple projects at once. e.g. running CI on a project that uses sub-modules from another project. Or using a docker image from one project in a CI pipeline for another project. We need to provide some way to allow this access in a secure and convenient way.
Per-build CI tokens act as the user that triggers the build, but with read-only access outside of the current project.
It works for git clone
, git-LFS, git sub-modules, docker pull
, and images: foo
, but not for triggers (because they're user-less) or any API calls (e.g. fetching build artifacts from another SHA/project).
The scope is read-only outside of the current project, and the token expires when the build is finished so exposure is limited.
This slightly increases risk of runners in that the tokens that they have access to are slightly more powerful (access to more than 1 project) so protecting them is even more important (always use https, protect the runner instances, protect project token registration tokens).
Proposal
- We will generate a token for every build,
- The token will be unique across GitLab,
- GitLab Runner will receive payload with: Build ID, and generated Build Token,
- For cloning sources, accessing LFS objects and pulling docker images we will use the:
gitlab-ci-token
,build-token
(we do it now), - We will authenticate this token by looking for a Ci::Build with that build-token,
- We will authorize access to the resource by getting from Ci::Build information about a person who run this build, it could be: pusher of
git push
, person who did retry a build, person who did merge a changes, - We will run normal authorization checks for a resource as that user, basically allowing to use
gitlab-ci-token:build-token
credentials as temporary credentials of the build, - These credentials will only be accessible when build will be in state
running
, it means that it's assigned to runner and is being processed by him, - Possible authorized actions will be only
read-only
, we will blockread-write
operations, - There will be one exception:
docker push
for a project for whichCi::Build
is created will be possible. This is to maintain backward compatibility, - Basically a
Ci::Build
will have access to everything to which a user triggering build does have access, - Artifacts will be downloaded using the same build token delivered in payload.
Triggers
Currently Build triggers are user-less. We will have to make triggers to be executed by specific user. We will extend Build triggers similarly to how we implement Mirroring: allow to specify an user who is running a build.
Problems
- This open potential security hole, because it makes CI credentials to have much wider permissions,
- This puts much more trusty in security of runners. We trust currently runners as long person doesn't use
shell
and doesn't usedocker
in--privileged
mode, - This puts much more trusty in security of data channel: receiving payload by runner. We do have customers using HTTP for accessing the GitLab. However, this has the same problems as connecting from the browser.
Summary
Given above problems this seems to be a future proof solution:
- We can allow to use the same credentials for accessing GitLab API,
- Basically this approach doesn't seem to have edge cases,
- It works well for users that are external and have limited permissions,
- It will work with private, internal and public projects,
- CI will only get read-only permissions (with one exception read-write to own project's container registry),
- Admin users will have to be direct members of project for CI to access sources
Links / references
- Smaller step: #18993 (closed)
- Git submodules cannot be checked-out / updated with CI token #18107 (closed)