GitLab Container Registry
GitLab's registry is built into every GitLab instance, but unlike most registries the registry hostname and port may differ from the GitLab web UI host (registry.gitlab.com for SaaS; commonly gitlab.example.com:5050 for self-managed). The registry trusts JWTs signed by the matching GitLab instance, so the auth token type matters as much as its scope.
Auth options
| Token type | When to use | Scope |
|---|---|---|
| Personal access token (PAT) | Per-user, broad scope | read_registry (and read_repository if you want HG metadata) |
| Project access token | Bound to one project; rotated easily | read_registry |
| Group access token (Premium+) | One token, many projects | read_registry |
| Deploy token | Stable, no user attached, project-scoped | Check read_registry when creating |
CI job token ($CI_JOB_TOKEN) | Inside a pipeline only — not for HarborGuard's stored connection | n/a |
The username depends on the token type — see "Common pitfalls" below.
Add the registry
- Registries → Connect Registry.
- Registry URL:
- SaaS:
registry.gitlab.com - Self-managed: typically
gitlab.example.com:5050(check your instance'sAdmin Area → Settings → Packages and Registries)
- SaaS:
- The wizard tags
GitLab Detectedwhen the URL containsgitlab.comor:5050. - Cloud: enter the username + token.
- Save.
For self-managed instances using a self-signed certificate, deploy a sensor inside the network rather than connecting cloud-side.
Required permissions
| Token | Username field | Notes |
|---|---|---|
| PAT | Your GitLab username | Token scope: read_registry |
| Project / group access token | The token's bot username (shown when created) | Token scope: read_registry |
| Deploy token | The deploy token's username (set at creation, not your GitLab login) | Permission: read_registry |
Push-event sync
GitLab supports project-level webhooks for container registry events (Premium and above; Free in newer versions of self-managed).
- Project → Settings → Webhooks.
- URL:
https://<your-harborguard-host>/api/webhooks/gitlab. - Trigger: Container Registry events.
- Set the registry's schedule to
on_push.
For a group with many projects, configure the webhook at the group level if your tier supports it.
Common pitfalls
- Wrong host. The registry hostname is rarely the same as the GitLab web URL on self-managed instances. It's printed when you
docker login; check there if unsure. - Port
:5050. Self-managed installs almost always expose the registry on:5050. Forgetting the port produces a misleading "connection refused" — the GitLab web UI on:443won't speak/v2/. - Deploy token username ≠ GitLab login. Deploy tokens have their own username, set at creation time. Using your personal login with the token's password produces 401s.
- Self-signed TLS. Cloud-mode connections to a self-managed instance with a private CA will fail. Either install a sensor or expose the registry behind a publicly trusted cert.
- Per-project visibility. A PAT only sees registries for projects the user can read. Switching from a personal PAT to a group access token after onboarding fixes most "I created a project, but it never appeared" issues.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| 401 immediately on test | Wrong username (deploy token vs PAT mix-up) |
404 on /v2/ | URL points at the GitLab UI, not the registry; missing :5050 |
| TLS error in cloud mode | Self-signed cert on a self-managed instance |
| Push webhook fires but no scan | Schedule still daily; switch to on_push |
| "Insufficient scope" on token | Token has read_repository but not read_registry |