Pimp your GitLab pipeline permissions

Johann Gyger
ITNEXT
Published in
3 min readMar 21, 2021

--

Photo by Pankaj Patel on Unsplash

Let’s assume you have a GitLab CI/CD pipeline that changes a repository. Or maybe you want to leverage full access to the GitLab API. What are the options?

Option 1: Use a personal access token (PAT)

You can create a personal access token and define it as a custom environment variable. You could put it in .gitlab-ci.yml, but this would be the wrong choice because your token is not protected. Another option is to define the variable in the UI where it is possible to restrict the usage to protected branches and mask the output in job logs.

This approach has two drawbacks. First, the personal access token is personal, and all audit trails will be tied to this specific user, hiding the effective user. Second, your token may leak to other users. It’s pretty easy to reveal the token contents even if you mask the variable.

As a sub-variant, you could use a project access token. Despite not being tied to a personal user, those tokens are limited to self-hosted GitLab instances and paid SaaS plans. Plus, the token can still leak.

Option 2: Use a CI job token

GitLab generates a token for each CI job and puts it into a predefined variable:

CI_JOB_TOKEN: A token to authenticate with certain API endpoints. The token is valid as long as the job is running.

Due to security reasons, you’re only allowed to use a subset of the GitLab API, such as reading from a GitLab package or container registry, getting job artifacts, triggering pipelines, and creating a release. However, you cannot access a repository or use other parts of the API.

Note that the CI job token has the same permissions as the user that triggered the pipeline and the token expires after the job ends.

There is a proposal to redesign this feature, leaving us with the last option.

Option 3: Leverage the CI job JWT

GitLab generates another token for each job, and it’s also available as a predefined variable:

CI_JOB_JWT: A RS256 JSON web token (JWT) to authenticate with third-party systems that support JWT authentication, for example, HashiCorp’s Vault.

Unfortunately, GitLab only creates the JWT, but you can’t use it for authentication with GitLab. For this reason, I wrote a tiny GitLab proxy (called GiLP) which accepts HTTP requests for Git and API resources, supports authentication with the CI_JOB_JWT, and uses a personal access token to communicate with GitLab on behalf of the pipeline:

Basic functionality of GitLab Proxy (GiLP)

You can find all the details of GiLP here: https://gitlab.com/johanngyger/gilp.

The main advantage of GiLP is that the PAT does not leak. Also, you can audit all requests to GiLP, and if you know how to program Go, then it’s pretty easy to adapt the permission model according to your organization's needs.

The drawback is that you have to deploy and maintain a separate component. GiLP runs perfectly fine on Google Cloud Run or Azure Container Instances (ACI). See my other blog post on how to pimp ACI for automatic HTTPS.

Conclusion

GitLab pipeline permissions are somewhat of a pain, and I hope that there will be a sustainable solution soon. GiLP is your friend in the meantime!

--

--