harbor

Remote Rollouts

Registry Credentials

Store credentials for pulling private task images

/registry-credentials stores encrypted credentials for pulling private task images. It supports Google Artifact Registry (GAR), GitHub Container Registry (GHCR), and Amazon Elastic Container Registry (ECR).

The examples below use $BASE and $KEY. Get a key from Harbor Hub API Key.

export BASE=https://ofhuhcpkvzjlejydnvyd.supabase.co/functions/v1
export KEY=sk-harbor-...

Storing a Credential

POST /registry-credentials validates the credential, encrypts it, and returns metadata without ever returning the secret. Every request takes a registry_host and a display_name of at most 100 characters, which is how jobs later select the credential. The provider is inferred from the host, so provider is optional; if you do send it, it has to agree with the host.

ProviderHostSecret fields
gar<region>-docker.pkg.devservice_account_json
ghcrghcr.iousername, token
ecr<account-id>.dkr.ecr.<region>.amazonaws.comaccess_key_id, secret_access_key

A GAR credential:

{
  "registry_host": "us-east1-docker.pkg.dev",
  "display_name": "prod-puller",
  "service_account_json": "{...service account JSON...}"
}

Use a service account with read access to the repository you need, typically roles/artifactregistry.reader scoped to that repository.

A GHCR credential:

{
  "registry_host": "ghcr.io",
  "display_name": "github-packages-puller",
  "username": "octocat",
  "token": "ghp_..."
}

Use a classic GitHub personal access token limited to read:packages.

An ECR credential:

{
  "registry_host": "123456789012.dkr.ecr.us-east-1.amazonaws.com",
  "display_name": "production-ecr-puller",
  "access_key_id": "AKIAIOSFODNN7EXAMPLE",
  "secret_access_key": "..."
}

Use a long-lived IAM access key limited to the ECR pull permissions your task images need. Temporary session credentials, the ones beginning ASIA, are rejected because they need a session token that Harbor does not store.

A successful response looks like:

{
  "id": "00000000-0000-0000-0000-000000000003",
  "org_id": "00000000-0000-0000-0000-00000000000a",
  "provider": "gar",
  "registry_host": "us-east1-docker.pkg.dev",
  "display_name": "prod-puller",
  "fingerprint": "harbor-puller@my-project.iam.gserviceaccount.com",
  "status": "active",
  "created_at": "2026-08-13T14:30:00Z"
}

Reusing an existing display_name returns 409 replacement_required with the existing record's fingerprint; confirm it with supersede_credential_id exactly as with secrets. Each organization can hold at most 20 active registry credentials.

For GAR, build the request from the service account file to avoid shell quoting problems:

curl -sS -X POST "$BASE/registry-credentials" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d "$(jq -n --rawfile sa ./gar-puller.json \
    '{registry_host:"us-east1-docker.pkg.dev", display_name:"prod-puller", service_account_json:$sa}')"

Listing and Revoking Registry Credentials

GET /registry-credentials lists active credentials and returns metadata only. Use status=revoked or status=all to include other states.

curl -sS "$BASE/registry-credentials?status=active" \
  -H "Authorization: Bearer $KEY"

DELETE /registry-credentials revokes a credential by default. Set purge to true only when the stored record should be permanently deleted.

curl -sS -X DELETE "$BASE/registry-credentials" \
  -H "Authorization: Bearer $KEY" \
  -H "Content-Type: application/json" \
  -d '{"credential_id":"00000000-0000-0000-0000-000000000003","purge":false}'

Using a Credential In a Job

Pin a stored credential by display name or ID in registry_credentials, as a sibling of config:

{
  "config": {
    "job_name": "private-image-job",
    "agents": [
      {
        "name": "terminus-2",
        "model_name": "openai/gpt-4o",
        "secrets": ["OPENAI_API_KEY"]
      }
    ],
    "datasets": [
      {
        "name": "my-org/private-image-dataset",
        "ref": "latest"
      }
    ]
  },
  "registry_credentials": {
    "us-east1-docker.pkg.dev": "prod-puller"
  },
  "job_secrets": {
    "OPENAI_API_KEY": "sk-..."
  }
}

That mapping reads: for images on us-east1-docker.pkg.dev, use the stored credential named prod-puller. Keys have to be supported registry hosts, and you can send at most 20 entries.

If exactly one active credential is available for a host you can leave registry_credentials out entirely. When several match, the launch has to pick one by display name, credential ID, or the owner-qualified display name Harbor shows.

On this page