About robot accounts
This guide explains how to create and manage robot accounts for automated access to the Numspot Container Registry.
Overview
Robot accounts are service accounts used for automated interactions with Harbor, such as:
- CI/CD pipelines that push and pull images.
- Kubernetes clusters that pull images for deployments.
- Automated tools that scan or manage images.
- Cross-registry replication.
Why use robot accounts?
- Security: avoid using admin credentials in automation.
- Granular permissions: restrict access to specific projects and operations.
- Auditing: track automated operations separately from user actions.
- Credential rotation: rotate robot account tokens without affecting users.
- Accountability: clear distinction between human and automated access.
Robot account types
System-level robot accounts
- Scope: all projects in the registry.
- Created by: Harbor system administrators.
- Use case: registry-wide automation, cross-project replication.
Project-level robot accounts
- Scope: a single project only.
- Created by: project administrators.
- Use case: project-specific CI/CD, application deployments.
Create robot accounts
Through the Harbor interface (project level)
- Log in to the Harbor interface.
- Go to Projects → Select the project → Robots.
- Click New Robot Account.
- Configure:
| Field | Value |
|---|---|
| Name | ci-cd-pipeline (prefix added automatically) |
| Description | Robot for CI/CD pipeline pushes |
| Expiration | Never or a specific date |
| Permissions | Select the appropriate permissions |
- Click Add
Permission levels
| Permission | Description | Use case |
|---|---|---|
| Push | Push images to the repository | CI pipelines that build images |
| Pull | Pull images from the repository | Kubernetes deployments |
| Read | View repository metadata | Monitoring tools |
| Delete | Delete images and tags | Cleanup jobs |
| Create | Create repositories | Initial project setup |
| Scanner pull | Retrieve scan results | Security tools |
Common permission combinations
| Use case | Permissions |
|---|---|
| CI/CD Push | Push + Create |
| Kubernetes Pull | Pull + Read |
| Full access | Push + Pull + Read + Delete + Create |
| Scanner | Pull + Read + Scanner pull |
Through the API (project level)
curl -X POST "https://registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/api/v2.0/projects/{project_id}/robots" \
-u "admin:{password}" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-cd-pipeline",
"description": "Robot for CI/CD pipeline pushes",
"expires_at": -1,
"permissions": [
{
"kind": "project",
"namespace": "{project_name}",
"access": [
{"action": "push"},
{"action": "pull"},
{"action": "create"}
]
}
]
}'
Response:
{
"id": 1,
"name": "robot${project_name}+ci-cd-pipeline",
"description": "Robot for CI/CD pipeline pushes",
"expires_at": -1,
"secret": "generated-secret-token",
"creation_time": "2026-05-05T10:00:00Z"
}
Save the secret value immediately. It is displayed only once and cannot be retrieved later.
Through the Harbor interface (system level)
- Log in as a system administrator.
- Go to Administration → Robot Accounts.
- Click New Robot Account.
- Configure:
| Field | Value |
|---|---|
| Name | system-replication |
| Description | System-wide replication robot |
| Expiration | Never or a specific date |
| Scope | System level |
| Permissions | All projects or specific projects |
- Click Add
Through the API (system level)
curl -X POST "https://registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/api/v2.0/robots" \
-u "admin:{password}" \
-H "Content-Type: application/json" \
-d '{
"name": "system-replication",
"description": "System-wide replication robot",
"expires_at": -1,
"level": "system",
"permissions": [
{
"kind": "project",
"namespace": "*",
"access": [
{"action": "push"},
{"action": "pull"},
{"action": "delete"},
{"action": "create"}
]
}
]
}'
Manage robot account credentials
Save the credentials
After creating a robot account, you will receive:
- Username:
robot${project_name}+robot-name. - Secret/Token: generated token (displayed only once).
Store the credentials securely:
## Example: save in a Kubernetes secret
kubectl create secret docker-registry harbor-robot-secret \
--docker-server=registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com \
--docker-username='robot${project_name}+ci-cd-pipeline' \
--docker-password='generated-secret-token'
## Example: save in environment variables
export HARBOR_ROBOT_USER='robot${project_name}+ci-cd-pipeline'
export HARBOR_ROBOT_SECRET='generated-secret-token'
Use robot accounts
Docker Login
docker login registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com \
-u 'robot${project_name}+ci-cd-pipeline' \
-p 'generated-secret-token'
Docker Push/Pull
## Push image
docker push registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/myproject/myimage:v1.0
## Pull image
docker pull registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/myproject/myimage:v1.0
Kubernetes Image Pull Secret
apiVersion: v1
kind: Secret
metadata:
name: harbor-robot-secret
namespace: default
type: kubernetes.io/dockerconfigjson
data:
.dockerconfigjson: ewogICJhdXRocyI6IHsKICAgICJyZWdpc3RyeS17cmVnaXN0cnlJZH0uaGNwLmNsb3VkZ291di1ldS13ZXN0LTEubnVtc3BvdC5jb20iOiB7CiAgICAgICJ1c2VybmFtZSI6ICJyb2JvdCR7cHJvamVjdF9uYW1lfStjaS1jZC1waXBlbGluZSIsCiAgICAgICJwYXNzd29yZCI6ICJnZW5lcmF0ZWQtc2VjcmV0LXRva2VuIiwKICAgICAgImF1dGgiOiAiYjNvTlRtVm1kWEJwYm1samJtRjBaVG9qTVE9PSIKICAgIH0KICB9Cn0=
Kubernetes deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
template:
spec:
imagePullSecrets:
- name: harbor-robot-secret
containers:
- name: myapp
image: registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/myproject/myimage:v1.0
CI/CD (GitLab CI)
## .gitlab-ci.yml
variables:
HARBOR_REGISTRY: registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com
HARBOR_USER: robot${project_name}+ci-cd-pipeline
HARBOR_PASSWORD: generated-secret-token
docker-build:
stage: build
image: docker:latest
services:
- docker:dind
before_script:
- docker login -u "$HARBOR_USER" -p "$HARBOR_PASSWORD" $HARBOR_REGISTRY
script:
- docker build -t $HARBOR_REGISTRY/myproject/myimage:$CI_COMMIT_SHA .
- docker push $HARBOR_REGISTRY/myproject/myimage:$CI_COMMIT_SHA
CI/CD (GitHub Actions)
## .github/workflows/docker.yml
name: Docker Build and Push
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Login to Harbor
uses: docker/login-action@v2
with:
registry: registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com
username: ${{ secrets.HARBOR_ROBOT_USER }}
password: ${{ secrets.HARBOR_ROBOT_SECRET }}
- name: Build and push
uses: docker/build-push-action@v4
with:
push: true
tags: registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/myproject/myimage:${{ github.sha }}
Manage existing robot accounts
List robot accounts
Through the Harbor interface
- Go to Projects → Select the project → Robots.
- Review the list of robot accounts.
Through the API
## List project-level robots
curl -X GET "https://registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/api/v2.0/projects/{project_id}/robots" \
-u "admin:{password}"
## List system-level robots
curl -X GET "https://registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/api/v2.0/robots" \
-u "admin:{password}"
Edit a robot account
Through the Harbor interface
- Go to the list of robot accounts
- Click Edit on the robot account
- Modify:
- The description
- The expiration date
- The permissions
- Click Save
Through the API
curl -X PUT "https://registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/api/v2.0/projects/{project_id}/robots/{robot_id}" \
-u "admin:{password}" \
-H "Content-Type: application/json" \
-d '{
"description": "Updated description",
"expires_at": 1735689600,
"permissions": [
{
"kind": "project",
"namespace": "{project_name}",
"access": [
{"action": "push"},
{"action": "pull"}
]
}
]
}'
Refresh the secret
Regenerate the robot account secret:
Through the Harbor interface
- Go to the list of robot accounts
- Click Refresh Secret on the robot account
- Copy the new secret immediately (displayed only once)
Through the API
curl -X PATCH "https://registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/api/v2.0/projects/{project_id}/robots/{robot_id}" \
-u "admin:{password}" \
-H "Content-Type: application/json" \
-d '{
"secret": ""
}'
Response:
{
"secret": "new-generated-secret-token"
}
Refreshing the secret immediately invalidates the old secret. Update all systems that use the robot account.
Disable a robot account
Disable temporarily without deleting:
curl -X PUT "https://registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/api/v2.0/projects/{project_id}/robots/{robot_id}" \
-u "admin:{password}" \
-H "Content-Type: application/json" \
-d '{
"disable": true
}'
Delete a robot account
Deletion is permanent. All systems that use the robot account will lose access.
Through the Harbor interface
- Go to the list of robot accounts.
- Click Delete on the robot account.
- Confirm the deletion.
Through the API
curl -X DELETE "https://registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/api/v2.0/projects/{project_id}/robots/{robot_id}" \
-u "admin:{password}"
Best practices for robot accounts
Security
- Principle of least privilege: Grant the minimum permissions required
- Project scope: Use project-level robots rather than system-level robots
- Short expiration: Set reasonable expiration dates
- Secret rotation: Refresh robot account secrets regularly
- Never commit secrets: Use environment variables or secret management tools
- Audit usage: Monitor robot account activity in the audit logs
Organization
- Descriptive names: Use meaningful names (e.g.
ci-cd-production,k8s-deploy-staging) - Document the purpose: Include detailed descriptions
- Tag environments: Use naming conventions for environments
- Track ownership: Document which team/system owns each robot
Lifecycle management
- Regular review: Audit robot accounts quarterly
- Remove unused ones: Delete robot accounts that are no longer used
- Expiration alerts: Monitor accounts close to expiration
- Update automation: Refresh credentials in CI/CD before expiration
Robot account templates
Robot for a CI/CD pipeline
curl -X POST "https://registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/api/v2.0/projects/{project_id}/robots" \
-u "admin:{password}" \
-H "Content-Type: application/json" \
-d '{
"name": "ci-pipeline",
"description": "CI pipeline for building and pushing images",
"expires_at": -1,
"permissions": [
{
"kind": "project",
"namespace": "{project_name}",
"access": [
{"action": "push"},
{"action": "pull"},
{"action": "create"}
]
}
]
}'
Robot for a Kubernetes deployment
curl -X POST "https://registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/api/v2.0/projects/{project_id}/robots" \
-u "admin:{password}" \
-H "Content-Type: application/json" \
-d '{
"name": "k8s-deploy",
"description": "Kubernetes cluster image pull",
"expires_at": -1,
"permissions": [
{
"kind": "project",
"namespace": "{project_name}",
"access": [
{"action": "pull"},
{"action": "read"}
]
}
]
}'
Replication robot
curl -X POST "https://registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/api/v2.0/robots" \
-u "admin:{password}" \
-H "Content-Type: application/json" \
-d '{
"name": "replication-push",
"description": "Cross-registry replication",
"expires_at": -1,
"level": "system",
"permissions": [
{
"kind": "project",
"namespace": "*",
"access": [
{"action": "push"},
{"action": "pull"},
{"action": "delete"},
{"action": "create"}
]
}
]
}'
Monitor robot account usage
Through the audit logs
- Go to Administration → Audit Log.
- Filter by robot account username.
- Review the operations:
- Push/pull operations.
- Repository creation.
- Image deletion.
- Last access timestamp.
Through the API
## Retrieve the audit logs for a robot account
curl -X GET "https://registry-{registryId}.hcp.cloudgouv-eu-west-1.numspot.com/api/v2.0/projects/{project_id}/logs?username=robot%24{project_name}%2Bci-pipeline" \
-u "admin:{password}" | jq '.[] | {operation: .operation, repository: .repo_name, time: .op_time}'
Metrics to monitor
- Pull/push frequency: track usage patterns.
- Authentication failures: alert on failed login attempts.
- Last access time: identify inactive robot accounts.
- Permission violations: alert on unauthorized access attempts.
Troubleshooting
Issue 1: authentication failure
Symptom: Docker login or pull fails with a 401 error.
Solutions:
- Check the robot account username format:
robot${project_name}+robot-name. - Check whether the secret was refreshed recently.
- Check that the robot account is not disabled.
- Check that the permissions match the operation (pull vs push).
Issue 2: access denied
Symptom: 403 Forbidden error on push/pull.
Solutions:
- Check that the robot account has the correct permissions.
- Check that the robot account is associated with the right project.
- Check that the repository exists (or that the create permission is granted).
- Check that the project quotas are not exceeded.
Issue 3: expired robot account
Symptom: authentication fails after the expiration date.
Solutions:
- Update the robot account expiration.
- Create a new robot account if necessary.
- Update the secrets in all consuming systems.
Issue 4: unable to refresh the secret
Symptom: refreshing the secret fails.
Solutions:
- Check that you have project administrator permissions.
- Check that the robot account still exists.
- Try updating through the API instead of the interface.
- Contact support if the problem persists.
API reference
Create a robot account (project)
POST /api/v2.0/projects/{project_id}/robots
Authorization: Basic {base64(admin:password)}
Content-Type: application/json
{
"name": "string",
"description": "string",
"expires_at": number,
"permissions": [
{
"kind": "project",
"namespace": "string",
"access": [
{"action": "push | pull | read | delete | create"}
]
}
]
}
List robot accounts (project)
GET /api/v2.0/projects/{project_id}/robots
Authorization: Basic {base64(admin:password)}
Retrieve a robot account
GET /api/v2.0/projects/{project_id}/robots/{robot_id}
Authorization: Basic {base64(admin:password)}
Edit a robot account
PUT /api/v2.0/projects/{project_id}/robots/{robot_id}
Authorization: Basic {base64(admin:password)}
Content-Type: application/json
{
"description": "string",
"expires_at": number,
"disable": boolean,
"permissions": []
}
Refresh the secret
PATCH /api/v2.0/projects/{project_id}/robots/{robot_id}
Authorization: Basic {base64(admin:password)}
Content-Type: application/json
{
"secret": ""
}
Delete a robot account
DELETE /api/v2.0/projects/{project_id}/robots/{robot_id}
Authorization: Basic {base64(admin:password)}
Limitations
- Secret displayed only once: the secret cannot be retrieved after creation.
- Name immutability: a robot account cannot be renamed after it is created.
- Limited permission granularity: permissions at the Harbor level only.
- Expiration required: an expiration date must be set for system-level robots.
- No IP restrictions: robot accounts cannot be restricted by IP (use project permissions).