Skip to content

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

  1. We will generate a token for every build,
  2. The token will be unique across GitLab,
  3. GitLab Runner will receive payload with: Build ID, and generated Build Token,
  4. For cloning sources, accessing LFS objects and pulling docker images we will use the: gitlab-ci-token, build-token (we do it now),
  5. We will authenticate this token by looking for a Ci::Build with that build-token,
  6. 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,
  7. 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,
  8. 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,
  9. Possible authorized actions will be only read-only, we will block read-write operations,
  10. There will be one exception: docker push for a project for which Ci::Build is created will be possible. This is to maintain backward compatibility,
  11. Basically a Ci::Build will have access to everything to which a user triggering build does have access,
  12. 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

  1. This open potential security hole, because it makes CI credentials to have much wider permissions,
  2. This puts much more trusty in security of runners. We trust currently runners as long person doesn't use shell and doesn't use docker in --privileged mode,
  3. 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:

  1. We can allow to use the same credentials for accessing GitLab API,
  2. Basically this approach doesn't seem to have edge cases,
  3. It works well for users that are external and have limited permissions,
  4. It will work with private, internal and public projects,
  5. CI will only get read-only permissions (with one exception read-write to own project's container registry),
  6. Admin users will have to be direct members of project for CI to access sources

Links / references