Keep your GitLab project's configuration in a file. Put it into a git repository and track all changes to GitLab project's configuration. Keep it in GitLab's project itself to do MRs against the configuration and discuss changes. Or make configuration changes at the same time as related changes to the code. Revert to previous versions of configuration. Duplicate configuration between projects. In short, GitLab project's configuration as code.
Features:
- gitlab-config is able to retrieve existing GitLab project's configuration and store it into a YAML file.
- Configuration file is automatically annotated with comments describing each setting.
- gitlab-config can update GitLab project's configuration to match the configuration file.
- Designed to be future proof and many API requests are made directly using fields as stored in the configuration file. This means that gitlab-config does not have to be updated to support new GitLab API changes.
- Can run as a CI job.
Planned:
- Not all GitLab API endpoints are integrated at this point. #16
- There are known issues with some GitLab API endpoints on their side.
Releases page contains a list of stable versions. Each includes:
- Statically compiled binaries.
- Docker images.
You should just download/use the latest one.
The tool is implemented in Go. You can also use go install
to install the latest stable (released) version:
go install gitlab.com/tozd/gitlab/config/cmd/gitlab-config@latest
To install the latest development version (main
branch):
go install gitlab.com/tozd/gitlab/config/cmd/gitlab-config@main
The tool provides three commands:
get
allows you to retrieve existing configuration of GitLab project and store it into an editable YAML file.set
updates the GitLab project's configuration based on the configuration in the file.sops
integrates SOPS fork as a command. The fork supports using comments to select values to encrypt and computing MAC only over values which end up encrypted.
This enables multiple workflows:
- You can use
gitlab-config get
to backup project's configuration. - You can first use
gitlab-config get
and thengitlab-config set
to copy configuration from one project to another. - You can use
gitlab-config set
inside a CI job to configure the project every time configuration file stored in the repository is changed. - You can have one repository with configuration files for many projects. A CI job then configures projects when their configuration files change.
- Somebody changed project's configuration through web UI and you want to see
what has changed, comparing
gitlab-config get
output with your backup.
Output of gitlab-config get
can change through time even if you have not
changed configuration yourself because new GitLab versions can introduce
new configuration options. Regularly run gitlab-config get
and merge
any changes with your configuration file.
To see configuration options available, run
gitlab-config --help
You can provide some configuration options as environment variables.
You have to provide an access token
using the -t/--token
command line flag or GITLAB_API_TOKEN
environment variable.
Use a personal access token
or project access token with api
scope
and at least maintainer role permissions.
Notes:
- Project's name and visibility can be changed only by owners and is because of that
not exposed by default in configuration as returned by
gitlab-config get
. You can manually add them if you want them in there, but then you have to use an access token with owner role even if you are not changing them. - Fork relationship between projects can be changed only by owners.
gitlab-config get
returns it because owner role permissions are required only if you want to change the relationship. - Project's path cannot be changed through the API. #13
You can add to your GitLab CI configuration a job like:
sync_config:
stage: deploy
image:
name: registry.gitlab.com/tozd/gitlab/config/branch/main:latest-debug
entrypoint: [""]
script:
- /gitlab-config set
rules:
- if: '$GITLAB_API_TOKEN && $CI_COMMIT_BRANCH == "main"'
changes:
- .gitlab-conf.yml
- .gitlab-avatar.png
Notes:
- Job runs only when
GITLAB_API_TOKEN
is present (e.g., only on protected branches) and only on themain
branch (e.g., one with the latest stable version of the configuration file). Change to suit your needs. - Configure
GITLAB_API_TOKEN
as GitLab CI/CD variable. Protected and masked. - The example above uses the latest version of the tool from the
main
branch. Consider using a Docker image corresponding to the latest released stable version. - Use of
-debug
Docker image is currently required. See this issue for more details.
The configuration above is suitable when you want to manage configuration of a project
using a configuration file inside project's repository itself.
Downside of this approach is that all CI jobs running on the main
branch get access to an
access token with at least maintainer role permissions. So care must be taken to control
what runs there.
An alternative is to have a separate repository which contains only the configuration file for a project (or files, for multiple projects) and you provide the access token only there. Downside of this approach is that you cannot change code and project's configuration at the same time through one MR.
It is important to understand that some configuration values are sensitive and should be handled with care, e.g., CI/CD variables. There are few options available to you:
- Never make configuration obtained using
gitlab-config get
public and handle the whole file in a security-conscious way. - Do not manage configuration sections which include sensitive values using
gitlab-config
. This is supported by removing (or setting tonull
) those sections in the configuration file (e.g.,variables: null
).gitlab-config
will detect that and skip them. This is different than setting them to empty values (e.g.,variables: []
) which makesgitlab-config
configure GitLab's project accordingly (e.g., remove all CI/CD variables). - Encrypt the file or just sensitive values in the file using a suitable tool, e.g., SOPS which supports encrypting with AWS KMS, GCP KMS, Azure Key Vault, age, and PGP.
- Use the fork of SOPS integrated with
gitlab-config
which supports using comments to select values to encrypt and computing MAC only over values which end up encrypted. This is the option we recommend andgitlab-config
makes it easy to use it.
gitlab-config get
automatically adds sops:enc
comments to values which are
known to be generally sensitive (you can use --enc-comment
flag to control this
behavior, together with alternative --enc-suffix
flag). But those are just defaults.
You can remove comments for values you know are not sensitive and you can add comments
also to other values which are sensitive in your particular configuration. Once you do that,
run the file through gitlab-config sops --encrypt
to encrypt sensitive values in the file.
An example using age:
$ age-keygen -o keys.txt
Public key: age1ey5p0k4072a3nctp38xz0wh6q93s2h5qwnr0fmftuld8yxfkke9sk47feg
$ cat > .sops.yaml
creation_rules:
- path_regex: ^\.gitlab-conf\.yml$
age: age1ey5p0k4072a3nctp38xz0wh6q93s2h5qwnr0fmftuld8yxfkke9sk47feg
^D
$ export SOPS_AGE_KEY_FILE=keys.txt
$ gitlab-config sops --encrypt --mac-only-encrypted --in-place --encrypted-comment-regex sops:enc .gitlab-conf.yml
If you want to edit the file decrypted temporarily and re-encrypted on save, you can run:
SOPS_AGE_KEY_FILE=keys.txt gitlab-config sops .gitlab-conf.yml
If you want to simply decrypt the file, run:
SOPS_AGE_KEY_FILE=keys.txt gitlab-config sops --decrypt --in-place .gitlab-conf.yml
You can safely store configuration file with encrypted values into the git repository.
If you want to run gitlab-config inside a CI pipeline, then CI job needs access to the
age private key. You can use gitlab-config itself to configure that. Add to your .gitlab-conf.yml
variables:
- environment_scope: "*"
key: SOPS_AGE_KEY_FILE
masked: false
protected: true
# sops:enc
value: |
# created: 2021-12-22T22:06:09+01:00
# public key: age1ey5p0k4072a3nctp38xz0wh6q93s2h5qwnr0fmftuld8yxfkke9sk47feg
AGE-SECRET-KEY-<the rest of contents of keys.txt>
variable_type: file
Encrypt it using gitlab-config sops --encrypt
and use gitlab-config set
to configure
your GitLab project. After this, CI jobs will be able to run gitlab-config set
as well,
automatically decrypting .gitlab-conf.yml
file as needed.
Do keep in mind that given above configuration all CI jobs running on protected branches get access to the age private key. So care must be taken to control what runs there.
Because there are many (supported) changes you might have done to the file: change comments, remove/nullify sections, add SOPS comments or field suffixes, encrypt or not values, there might even be additional API fields you have added for an updated API endpoint. Automatically meaningfully merging updates into those changes is not possible. So just generate a new file and compare with the old version yourself, resolving differences with your preferred tool.
To see projects which use this tool and how their configuration looks like, check out these projects:
Feel free to make a merge-request adding yours to the list.
- GitLabForm – A similar tool written in Python. It targets configuring many projects and not just an individual one like gitlab-config. On the other hand gitlab-config's design is to have 1:1 mapping between configuration file and API endpoints and do that well. E.g., gitlab-config makes sure you can safely commit your configuration file into a public git repository, if you want (secrets are encrypted). gitlab-config is great for open source projects or any project where you want transparency about how the project is configured and to allow contributors to contribute to project configuration as well. gitlab-config allows you to version full project configuration and manage changes to it.
- GitLab provider for Terraform – Supports configuring GitLab projects using Terraform. A big hammer if you just want to use it for one project. Moreover, it uses a custom language to define configuration. gitlab-config's configuration file directly matches GitLab API.
There is also a read-only GitHub mirror available, if you need to fork the project there.