Add ECR auto-refreshing upstream authentication - #278
Conversation
There was a problem hiding this comment.
Pull request overview
Adds automatic AWS ECR authentication for OCI upstreams with region-scoped token caching and refresh.
Changes:
- Adds
type: ecrwith optional AWS region configuration. - Implements ECR token retrieval through the AWS SDK credential chain.
- Adds tests, dependencies, documentation, and configuration examples.
Reviewed changes
Copilot reviewed 7 out of 8 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Summary |
|---|---|
internal/server/server.go |
Integrates ECR authentication routing. |
internal/server/ecr_auth.go |
Fetches and caches ECR tokens. Critical: error handling can trigger an incorrect Bearer retry instead of preserving the original 401 (1 vote). Moderate: concurrent cache misses can cause redundant token requests; refreshes should be coordinated (4 votes). |
internal/server/ecr_auth_test.go |
Tests ECR token behavior, caching, refresh, and routing. |
internal/config/config.go |
Adds ECR authentication and region configuration. |
go.sum |
Updates dependency checksums. |
go.mod |
Adds AWS ECR SDK dependencies. |
docs/configuration.md |
Documents ECR configuration and permissions. |
config.example.yaml |
Adds an ECR configuration example. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| if err != nil { | ||
| e.logger.Error("fetching ECR authorization token", "region", region, "error", err) | ||
| return "", "" |
There was a problem hiding this comment.
This is the existing behaviour of internal/httpclient.Transport.RoundTrip for every auth type, not something the ECR provider introduces: on a 401 with a Bearer challenge it drains the original response and returns registry authentication: %w when the token fetch fails (transport.go:89-93). A misconfigured type: basic against ECR or GHCR takes the identical path today. The provider logs the SDK error (no credentials, AccessDenied, etc) before returning empty, which is more actionable than the bare 401 would be. Changing the surfaced status means changing RoundTrip to return the original 401 when the token fetch fails, which affects every registry and is out of scope here; updated the doc comment on header() to describe the actual failure path.
- Add "ecr" auth type to upstream.auth config with optional region - Cache ecr:GetAuthorizationToken results per region and refresh shortly before expiry via the AWS SDK default credential chain - Route type: ecr through the token cache in Server.authForURL - Document the new type in config.example.yaml and docs/configuration.md Fixes #276
Drops the internal/server package below the goconst min-occurrences threshold for the Authorization literal.
62b5364 to
b907438
Compare
Concurrent cache misses for the same region now share a single GetAuthorizationToken call instead of each issuing their own, avoiding a request burst against the ECR API at cold start and at each 12-hour refresh. golang.org/x/sync is already a direct dependency.
Adds
type: ecrtoupstream.authso the proxy can front private AWS ECR registries without a static credential in config. On first request (and again shortly before the 12-hour expiry) it callsecr:GetAuthorizationTokenvia the AWS SDK default credential chain and sends the result as HTTP Basic to the ECR host; the existing OCI Bearer-challenge handling ininternal/httpclienttakes it from there.AWS credentials come from the SDK default chain (IRSA on EKS, EC2/ECS instance profiles,
AWS_*env vars,~/.aws/credentials). The identity needsecr:GetAuthorizationTokenplus pull permissions on the target repositories.regionis optional and falls back to the SDK default resolution.Implementation:
AuthConfiggains aRegionfield;Server.authForURLroutestype: ecrto a small per-region token cache ininternal/server/ecr_auth.gothat mirrors the expiry-with-skew pattern already used by the OCI token cache ininternal/httpclient/transport.go.AuthConfig.Header()and theAuthFuncsignature are unchanged; on SDK error the provider logs and returns no header so the upstream 401 surfaces normally.Dependency impact:
aws-sdk-go-v2is already linked viagocloud.dev/blob/s3blob, so this only addsgithub.com/aws/aws-sdk-go-v2/service/ecr. Stripped linux binary grows from 35,848,352 to 36,044,960 bytes (+192 KB, +0.55%);go.sumnet +2 lines.Fixes #276.