Google Artifact Registry
GCP runs two image registries side by side: the legacy Container Registry (gcr.io, us.gcr.io, eu.gcr.io, asia.gcr.io) and the modern Artifact Registry (<region>-docker.pkg.dev). They share Google's auth model but differ in IAM roles, repository structure, and feature set. The wizard auto-detects Artifact Registry from the *-docker.pkg.dev suffix; legacy GCR hostnames must be picked manually.
Auth options
| Method | When to use | HarborGuard fields |
|---|---|---|
| Service-account JSON key | Most common; works in cloud and sensor mode | Username _json_key, Password = entire JSON file contents |
| Workload Identity (sensor on GKE) | No long-lived keys; sensor pod inherits a Google identity | None — handled by the sensor |
| Application Default Credentials (sensor on GCE/Cloud Run) | Sensor runs on GCP compute with an attached service account | None — handled by the sensor |
| OAuth access token | Short-lived (1 hour); only useful for ad-hoc tests | Username oauth2accesstoken, Password = the token |
Add the registry
- Registries → Connect Registry.
- Registry URL:
- Artifact Registry:
us-central1-docker.pkg.dev(or your region) - Legacy GCR:
gcr.io,us.gcr.io,eu.gcr.io,asia.gcr.io
- Artifact Registry:
- The wizard tags Artifact Registry hostnames as
Google GAR Detected. For GCR, set the provider manually. - Cloud mode: enter
_json_keyas the username and paste the full service-account JSON (including the surrounding{}) as the password. Don't escape the newlines in the private key — paste verbatim. - Save.
The first sync enumerates repositories under your project. For Artifact Registry, the URL path includes <project>/<repository>/<image>; HarborGuard uses the project from the JSON key.
Required IAM roles
| Use case | Role | Granted on |
|---|---|---|
| Artifact Registry, read-only | roles/artifactregistry.reader | The repository (preferred) or the project |
| Legacy GCR, read-only | roles/storage.objectViewer on the underlying GCS bucket (artifacts.<project>.appspot.com and regional variants) | The bucket |
| Both | roles/artifactregistry.reader + roles/storage.objectViewer | Project, if you don't want to enumerate buckets |
Granular permissions actually exercised: artifactregistry.repositories.list, artifactregistry.repositories.downloadArtifacts, artifactregistry.tags.list, artifactregistry.versions.list, artifactregistry.dockerimages.get.
Push-event sync
Artifact Registry can publish to a Pub/Sub topic on every push. To wire on_push:
- Enable Artifact Registry Pub/Sub notifications in the GCP console (creates a topic like
gcrorartifact-registry). - Create a push subscription targeting
https://<your-harborguard-host>/api/webhooks/gcp. - Set the registry's schedule to
on_push.
Legacy GCR uses a different topic name (gcr) but the same flow.
Common pitfalls
- GAR vs GCR confusion. A migrated project will have both
gcr.io(read-through to Artifact Registry) and a real*-docker.pkg.devhost. Add the GAR host directly; reading through the GCR alias works but bypasses Artifact Registry's per-repository IAM. - Region encoding.
us-docker.pkg.dev(multi-region) andus-central1-docker.pkg.dev(single region) are distinct registries with different repos. - JSON key formatting. The wizard's password field must contain the full JSON object as a single value. Pasting just the
private_keyfield results in "authentication failed" with a misleading 401. - Project ID vs project number. The JSON key embeds the project ID; HarborGuard uses that, not the numeric ID. Repositories created with the project number in their path still resolve.
- Disabling the legacy GCR API. If you've enabled Artifact Registry's GCR repository, disabling the standalone Container Registry API will silently break legacy
gcr.iohostnames — keep both enabled during migration.
Troubleshooting
| Symptom | Likely cause |
|---|---|
| 401 on test, credentials look correct | Username field is something other than _json_key |
| 403 listing repositories | Service account lacks artifactregistry.repositories.list at the project level |
| GCR works but GAR returns 404 | Used the GCR alias hostname for an Artifact Registry repo — switch to *-docker.pkg.dev |
| Some images sync, others 404 | Repository-level IAM grants exist for some repos and not others |
| Sensor on GKE fails to authenticate | Workload Identity isn't bound — confirm the iam.gke.io/gcp-service-account annotation on the sensor's KSA |