Keys and scopes
A key is a credential plus a list of scopes. There is no policy language, no role hierarchy, and no inheritance to reason about — what the key can do is what is written on it.
Scope syntax
repositories:<action>:<project>/<repository><action> is pull, push, or delete. push does not imply pull; list both if the
job needs both.
The repository segment accepts * as a wildcard:
| Scope | Grants |
|---|---|
repositories:pull:acme/api |
Pull that one repository |
repositories:push:acme/api |
Push to that one repository, and nothing else |
repositories:pull:acme/* |
Pull every repository in acme |
repositories:pull:*/* |
Pull every repository you have access to |
Management scopes cover the API rather than the registry, and are only available on user-owned keys:
projects:read projects:write keys:read keys:writeProject keys and user keys
A project key is bound to one project. Its scopes cannot name any other project, so even a mistake in the form cannot widen it. This is what CI should use.
A user key acts as you, across every project you can reach. It can carry management scopes. Treat it like a password.
When in doubt, mint a project key.
Minting a key
In the panel, + → New API key, or on the project itself. Pick the repository, tick the actions, choose an expiry. The key is shown once and stored as a one-way hash — we cannot show it to you again, and neither can anyone who obtains our database.
Expiry
Every key can carry an expiry. Set one. A key with no expiry is a key you will still have in three years, on a laptop belonging to someone who left.
Expiry is enforced at token issue, so an expired key stops working on the next docker login and on the next token refresh during a long push.
Revoking
Revoke in the panel. Registry access tokens are short-lived, so a revoked key stops working within the token lifetime — seconds to a few minutes — rather than immediately mid-request. For an urgent leak, revoke the key and rotate anything it could have pushed.
Worked example: a CI key
The build job for acme/api needs to push that repository and nothing else:
repositories:push:acme/apiAttempting anything outside that fails at the registry, not in a review:
sudo docker push lazer.sh/acme/api:$GIT_SHA
# 2f9a1c: Pushed
sudo docker pull lazer.sh/acme/billing:latest
# Error response from daemon: denied: insufficient scope