A private image registry
With storage in place, the provisioner creates the one private Artifact Registry repository that every navigator container image lives in, and the identities that push to and pull from it:
- A Docker-format repository (default
navigator) atyour-region-docker.pkg.dev/your-project-id/navigator. - A keep-the-last-10-versions cleanup policy — a
KEEPrule retaining the last 10 versions of each image plus aDELETErule for everything else. Retention is a count rather than an age on purpose: an age-based rule is only safe while releases outrun it, and releases are tag-driven, so a quiet fortnight under the old 7-day rule would have let the registry delete the versions production was running. A count cannot expire. Keep policies take precedence over delete policies, which is what makes the pair mean "keep ten, delete the rest" — the delete half matches every version, so it is never applied alone. - A CI push identity (
navigator-ci-pusherservice account) with a repo-scopedroles/artifactregistry.writerbinding, plus a GitHub Workload Identity federation pool and provider so CI authenticates keyless — no downloaded service-account key — pinned to this one repository and to the refs allowed to publish. - A repo-scoped
roles/artifactregistry.readerbinding for the GKE Autopilot node identity, so the cluster can pull.
Two values decide whether that federation works at all, and both are easy to get wrong in a way nothing reports:
issuerUri https://token.actions.<your-tenant>.ghe.com # NOT token.actions.githubusercontent.com
attributeCondition assertion.repository == '<owner>/<repo>'
&& (assertion.ref == 'refs/heads/main' || assertion.ref.startsWith('refs/tags/'))