Skip to main content

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)

  1. Log in to the Harbor interface.
  2. Go to Projects → Select the project → Robots.
  3. Click New Robot Account.
  4. Configure:
FieldValue
Nameci-cd-pipeline (prefix added automatically)
DescriptionRobot for CI/CD pipeline pushes
ExpirationNever or a specific date
PermissionsSelect the appropriate permissions
  1. Click Add

Permission levels

PermissionDescriptionUse case
PushPush images to the repositoryCI pipelines that build images
PullPull images from the repositoryKubernetes deployments
ReadView repository metadataMonitoring tools
DeleteDelete images and tagsCleanup jobs
CreateCreate repositoriesInitial project setup
Scanner pullRetrieve scan resultsSecurity tools

Common permission combinations

Use casePermissions
CI/CD PushPush + Create
Kubernetes PullPull + Read
Full accessPush + Pull + Read + Delete + Create
ScannerPull + 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"
}
warning

Save the secret value immediately. It is displayed only once and cannot be retrieved later.

Through the Harbor interface (system level)

  1. Log in as a system administrator.
  2. Go to AdministrationRobot Accounts.
  3. Click New Robot Account.
  4. Configure:
FieldValue
Namesystem-replication
DescriptionSystem-wide replication robot
ExpirationNever or a specific date
ScopeSystem level
PermissionsAll projects or specific projects
  1. 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

  1. Go to Projects → Select the project → Robots.
  2. 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

  1. Go to the list of robot accounts
  2. Click Edit on the robot account
  3. Modify:
  • The description
  • The expiration date
  • The permissions
  1. 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

  1. Go to the list of robot accounts
  2. Click Refresh Secret on the robot account
  3. 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"
}
warning

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

warning

Deletion is permanent. All systems that use the robot account will lose access.

Through the Harbor interface

  1. Go to the list of robot accounts.
  2. Click Delete on the robot account.
  3. 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

  1. Principle of least privilege: Grant the minimum permissions required
  2. Project scope: Use project-level robots rather than system-level robots
  3. Short expiration: Set reasonable expiration dates
  4. Secret rotation: Refresh robot account secrets regularly
  5. Never commit secrets: Use environment variables or secret management tools
  6. Audit usage: Monitor robot account activity in the audit logs

Organization

  1. Descriptive names: Use meaningful names (e.g. ci-cd-production, k8s-deploy-staging)
  2. Document the purpose: Include detailed descriptions
  3. Tag environments: Use naming conventions for environments
  4. Track ownership: Document which team/system owns each robot

Lifecycle management

  1. Regular review: Audit robot accounts quarterly
  2. Remove unused ones: Delete robot accounts that are no longer used
  3. Expiration alerts: Monitor accounts close to expiration
  4. 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

  1. Go to AdministrationAudit Log.
  2. Filter by robot account username.
  3. 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:

  1. Check the robot account username format: robot${project_name}+robot-name.
  2. Check whether the secret was refreshed recently.
  3. Check that the robot account is not disabled.
  4. Check that the permissions match the operation (pull vs push).

Issue 2: access denied

Symptom: 403 Forbidden error on push/pull.

Solutions:

  1. Check that the robot account has the correct permissions.
  2. Check that the robot account is associated with the right project.
  3. Check that the repository exists (or that the create permission is granted).
  4. Check that the project quotas are not exceeded.

Issue 3: expired robot account

Symptom: authentication fails after the expiration date.

Solutions:

  1. Update the robot account expiration.
  2. Create a new robot account if necessary.
  3. Update the secrets in all consuming systems.

Issue 4: unable to refresh the secret

Symptom: refreshing the secret fails.

Solutions:

  1. Check that you have project administrator permissions.
  2. Check that the robot account still exists.
  3. Try updating through the API instead of the interface.
  4. 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).