https://github.com/hops-ops/aws-ecr-registry-cache
ECR pull-through cache rules for platform image registries.
https://github.com/hops-ops/aws-ecr-registry-cache
Last synced: about 1 month ago
JSON representation
ECR pull-through cache rules for platform image registries.
- Host: GitHub
- URL: https://github.com/hops-ops/aws-ecr-registry-cache
- Owner: hops-ops
- Created: 2026-06-06T21:16:01.000Z (about 2 months ago)
- Default Branch: main
- Last Pushed: 2026-06-06T22:19:52.000Z (about 2 months ago)
- Last Synced: 2026-06-07T00:07:43.671Z (about 2 months ago)
- Language: KCL
- Size: 21.5 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 3
-
Metadata Files:
- Readme: README.md
- Changelog: CHANGELOG.md
Awesome Lists containing this project
README
# aws-ecr-registry-cache
ECR pull-through cache rules for platform image registries.
`ECRRegistryCache` manages Amazon ECR pull-through cache rules in one AWS
account and region. It can also create repository creation templates for the
repositories ECR creates on first pull, and it can optionally own registry-wide
enhanced scanning through Amazon Inspector.
This XR does not rewrite image references by itself. Consumers still pull from
the private ECR registry URI, for example:
```text
123456789012.dkr.ecr.us-east-2.amazonaws.com/ghcr/hops-ops/aws-auto-eks-cluster:v0.11.0
```
## Getting Started
Create no-auth cache rules for public upstreams:
```yaml
apiVersion: aws.hops.ops.com.ai/v1alpha1
kind: ECRRegistryCache
metadata:
name: platform
namespace: default
spec:
accountId: "123456789012"
region: us-east-2
rules:
- name: ecr-public
ecrRepositoryPrefix: ecr-public
upstreamRegistryUrl: public.ecr.aws
repositoryCreationTemplate:
enabled: true
- name: kubernetes
ecrRepositoryPrefix: kubernetes
upstreamRegistryUrl: registry.k8s.io
repositoryCreationTemplate:
enabled: true
```
The first pull creates the cached repository:
```bash
docker pull 123456789012.dkr.ecr.us-east-2.amazonaws.com/ecr-public/docker/library/busybox:latest
```
## Growing
Authenticated upstreams such as Docker Hub and GHCR require existing AWS
Secrets Manager secrets. AWS requires those secret names to start with
`ecr-pullthroughcache/`, and the secret must live in the same account and
region as the rule.
```yaml
apiVersion: aws.hops.ops.com.ai/v1alpha1
kind: ECRRegistryCache
metadata:
name: platform
namespace: default
spec:
accountId: "123456789012"
region: us-east-2
rules:
- name: docker-hub
ecrRepositoryPrefix: docker-hub
upstreamRegistryUrl: registry-1.docker.io
credentialArn: arn:aws:secretsmanager:us-east-2:123456789012:secret:ecr-pullthroughcache/docker-hub-AbCdEf
repositoryCreationTemplate:
enabled: true
imageTagMutability: MUTABLE
- name: ghcr
ecrRepositoryPrefix: ghcr
upstreamRegistryUrl: ghcr.io
credentialArn: arn:aws:secretsmanager:us-east-2:123456789012:secret:ecr-pullthroughcache/ghcr-AbCdEf
repositoryCreationTemplate:
enabled: true
imageTagMutability: MUTABLE
```
Do not make pull-through cache repositories immutable by default. AWS refreshes
cached tags over time, and immutable tags can prevent ECR from updating a
repository when the upstream reuses a tag.
Repository creation template `resourceTags` are not inherited from top-level
`spec.tags`. Set them explicitly only after verifying first-pull repository
creation can tag repositories in the target account; otherwise ECR can fail to
auto-create the cache repository.
## Enterprise Scale
Enhanced scanning is registry-wide and disabled by default because it makes
this XR the owner of ECR scanning configuration for the account and region and
can create Amazon Inspector cost.
```yaml
spec:
enhancedScanning:
enabled: true
scanFrequency: CONTINUOUS_SCAN
rules:
- name: ghcr
ecrRepositoryPrefix: ghcr
upstreamRegistryUrl: ghcr.io
credentialArn: arn:aws:secretsmanager:us-east-2:123456789012:secret:ecr-pullthroughcache/ghcr-AbCdEf
```
When `repositoryFilters` is omitted, the composition creates one `WILDCARD`
filter per rule prefix, such as `ghcr/*`. Operators can set explicit filters
when another owner already manages part of registry scanning.
## Crossplane ImageConfig
Crossplane package pulls need `ImageConfig` objects in the control plane that
consumes packages:
```yaml
apiVersion: pkg.crossplane.io/v1beta1
kind: ImageConfig
metadata:
name: ecr-ghcr-rewrite
spec:
matchImages:
- type: Prefix
prefix: ghcr.io
rewriteImage:
prefix: 123456789012.dkr.ecr.us-east-2.amazonaws.com/ghcr
registry:
authentication:
pullSecretRef:
name: ecr-registry-credentials
```
`xpkg.crossplane.io` is not a supported ECR pull-through cache upstream in this
XR. Crossplane dependency packages from `xpkg.crossplane.io` need to stay
outside this cache path, be republished to a supported upstream such as GHCR,
or be mirrored into ECR by a separate mechanism.
## Current Hops Registry Audit
The local and `pat-local` clusters currently pull from these registry families:
| Registry family | Examples observed | ECR pull-through support |
|---|---|---|
| Docker Hub | `docker.io/istio/*`, `docker.io/grafana/*`, `postgres`, `redis`, `busybox`, `nats`, `listmonk/listmonk` | Supported through `registry-1.docker.io`; requires Secrets Manager credentials. |
| GHCR | `ghcr.io/hops-ops/*`, `ghcr.io/fluxcd/*`, `ghcr.io/external-secrets/*`, `ghcr.io/cloudnative-pg/*` | Supported through `ghcr.io`; requires Secrets Manager credentials. |
| ECR Public | `public.ecr.aws/eks/aws-load-balancer-controller`, `public.ecr.aws/docker/library/node` | Supported through `public.ecr.aws`; no auth required. |
| Kubernetes registry | `registry.k8s.io/nginx-slim`, `registry.k8s.io/external-dns/*`, `registry.k8s.io/metrics-server/*` | Supported through `registry.k8s.io`; no auth required. |
| Quay | `quay.io/argoproj/argocd`, `quay.io/jetstack/*`, `quay.io/prometheus/*`, `quay.io/kubescape/*` | Supported through `quay.io`; no auth required. |
| Crossplane package registries | `xpkg.crossplane.io/crossplane-contrib/*`, `xpkg.upbound.io/wildbitca/*` | Not supported by ECR pull-through cache. Needs republish, mirror, or direct pull. |
| Google registries | `gcr.io/knative-releases/*`, `mirror.gcr.io/*`, `us-docker.pkg.dev/fairwinds-ops/*` | Not supported by ECR pull-through cache. Needs mirror or direct pull. |
| Other registries | `reg.kyverno.io/kyverno/*` | Not supported by ECR pull-through cache. Needs mirror or direct pull. |
## Import Existing
For existing pull-through cache rules, set `managementPolicies` to observe and
update without delete until the adoption is verified:
```yaml
apiVersion: aws.hops.ops.com.ai/v1alpha1
kind: ECRRegistryCache
metadata:
name: existing-platform
namespace: default
spec:
accountId: "123456789012"
region: us-east-2
managementPolicies:
- Create
- Observe
- Update
- LateInitialize
rules:
- name: ghcr
ecrRepositoryPrefix: ghcr
upstreamRegistryUrl: ghcr.io
credentialArn: arn:aws:secretsmanager:us-east-2:123456789012:secret:ecr-pullthroughcache/ghcr-AbCdEf
```
## Status
```yaml
status:
ready: true
registry:
id: "123456789012"
host: 123456789012.dkr.ecr.us-east-2.amazonaws.com
scanning:
enabled: false
scanType: ""
rules:
- name: ghcr
ready: true
ecrRepositoryPrefix: ghcr
upstreamRegistryUrl: ghcr.io
pullPrefix: 123456789012.dkr.ecr.us-east-2.amazonaws.com/ghcr
```
## Development
```bash
make render # Render all examples
make validate # Validate rendered output against schemas
make test # Run KCL composition tests
make e2e # Run E2E tests (requires AWS credentials)
```
For local control plane iteration:
```bash
hops config install --path xrs/aws/ecr-registry-cache --context colima
kubectl --context colima apply -f local/ecrregistrycache.yaml
```
## References
- AWS ECR pull-through cache: https://docs.aws.amazon.com/AmazonECR/latest/userguide/pull-through-cache.html
- AWS ECR repository creation templates: https://docs.aws.amazon.com/AmazonECR/latest/userguide/repository-creation-templates.html
- Crossplane ImageConfig: https://docs.crossplane.io/latest/packages/image-configs/
## License
Apache-2.0