Migration Guide: Manual Tokens to Self-Service Runners
How to migrate from manually-managed runner registration tokens to the
automated self-service model using gitlab_user_runner.
Before: Manual Token Management
The legacy setup required operators to:
- Generate runner registration tokens in the GitLab UI.
- Set
TF_VAR_*_runner_tokenenvironment variables per runner type:TF_VAR_docker_runner_token=glrt-... TF_VAR_dind_runner_token=glrt-... TF_VAR_rocky8_runner_token=glrt-... TF_VAR_rocky9_runner_token=glrt-... TF_VAR_nix_runner_token=glrt-... - Rotate tokens manually when they expired or were revoked.
- Use
ci-templates/withextends:to reference shared job definitions.
Problems: token sprawl, manual rotation, no audit trail, tight coupling between templates and downstream projects.
After: Automated Self-Service
The new model uses the gitlab_user_runner Terraform resource to register
runners at the group level automatically. Tokens are managed by OpenTofu and
stored in Kubernetes secrets.
Downstream projects use include: component: syntax instead of extends:.
Migration Steps
Step 1: Set the GitLab Group ID
In your runner stack tfvars (e.g., tofu/stacks/runners/{environment}.tfvars):
gitlab_group_id = 12345678
When gitlab_group_id is set to a non-zero value, the module creates
gitlab_user_runner resources and manages tokens automatically.
Step 2: Provide a GitLab Token
Set a GitLab personal access token (or group token) with the create_runner
scope:
export TF_VAR_gitlab_token=glpat-XXXX
This token is used only by OpenTofu to create runner registrations. It is not the runner authentication token.
Step 3: Apply the Stack
ENV=<environment> just tofu-plan gitlab-runners
ENV=<environment> just tofu-apply gitlab-runners
OpenTofu will:
- Create
gitlab_user_runnerresources for each runner type. - Store the generated authentication tokens in Kubernetes secrets.
- Configure the runner deployments to read tokens from secrets.
Step 4: Remove Legacy Token Variables
Once the automated runners are healthy, remove the old TF_VAR_*_runner_token
variables from your CI/CD settings and any local .envrc files.
Step 5: Migrate CI Templates
See the CI template migration section below.
Backward Compatibility
When gitlab_group_id = 0 (the default), the module falls back to manual
token management. The TF_VAR_*_runner_token variables are used as before.
This means you can migrate clusters independently. For example, migrate
dev-cluster first while prod-cluster continues using manual
tokens.
CI Template Migration
Before: ci-templates with extends
# Old pattern
include:
- project: "{org}/projects/iac/attic-cache"
file: "ci-templates/docker.yml"
ref: main
build:
extends: .docker-job
script:
- make build
After: CI/CD Components
# New pattern
include:
- component: $CI_SERVER_FQDN/{org}/projects/iac/attic-cache/docker-job@main
inputs:
stage: build
script: make build
Key Differences
| Aspect | ci-templates (legacy) | Components (new) |
|---|---|---|
| Syntax | include: project/file |
include: component: |
| Customization | extends: + overrides |
inputs: parameters |
| Versioning | ref: on include |
@ref suffix on component |
| Validation | None | Input schema validation |
| Discoverability | Read the YAML | GitLab CI/CD catalog |
Migration Mapping
| Legacy Template | Component |
|---|---|
ci-templates/docker.yml |
docker-job |
ci-templates/dind.yml |
dind-job |
ci-templates/rocky8.yml |
rocky8-job |
ci-templates/rocky9.yml |
rocky9-job |
ci-templates/nix.yml |
nix-job |
ci-templates/docker-build.yml |
docker-build |
ci-templates/k8s-deploy.yml |
k8s-deploy |
Deprecation Timeline
| Date | Milestone |
|---|---|
| Now | Components available, ci-templates still supported |
| +30 days | ci-templates emit deprecation warnings in job logs |
| +90 days | ci-templates frozen (no new features or bug fixes) |
| +180 days | ci-templates removed from main branch |
Projects should migrate to components within the 90-day window. After removal,
pipelines referencing ci-templates/ will fail.