PastureStack is an independent community effort to preserve, audit, and modernize the Rancher 1.6 ecosystem. It is not affiliated with or endorsed by Rancher Labs or SUSE.
Upstream: rancher/rancher-ecr-credentials. This GitHub fork retains the upstream Git history, authorship, dates, and license notices unchanged; PastureStack maintenance is consolidated into one commit after the preserved upstream boundary.
ECR Credential Sync refreshes temporary Amazon Elastic Container Registry
credentials in a compatible legacy control-plane environment. It requests ECR
authorization tokens through the AWS SDK, finds the matching registry resource,
and updates its username and password. When AUTO_CREATE=true, it can create a
missing registry and credential resource.
This repository preserves the complete upstream Git history and contributor record. PastureStack contributors claim authorship only for their own changes. See ORIGIN.md for provenance and COMPATIBILITY.md for the neutral runtime contract.
- Synchronizes credentials immediately after startup and then every six hours.
- Supports the default AWS credential provider chain and optional IAM role
assumption through
AWS_ROLE_ARN. - Supports one or more account IDs through
AWS_ECR_REGISTRY_IDS. - Exposes
GET /pingon port8080by default; setLISTEN_PORTto override it. - Retries temporary ECR and environment API failures with a bounded incremental backoff. Successful requests do not wait or retry.
- Creates a missing credential record for an existing registry when
AUTO_CREATE=true. - Runs as the unprivileged numeric user
10001:10001. - Provides a
windows/amd64LTSC 2022 variant that runs asContainerUser.
| Variable | Required | Purpose |
|---|---|---|
AWS_REGION |
Yes | AWS region containing the ECR registry. |
AWS_ACCESS_KEY_ID |
Depends on AWS environment | Static access key when no role, profile, or instance identity is available. |
AWS_SECRET_ACCESS_KEY |
Depends on AWS environment | Static secret key paired with the access key. |
AWS_SESSION_TOKEN |
No | Session token for temporary AWS credentials. |
AWS_PROFILE |
No | Profile from a mounted shared AWS configuration. |
AWS_ROLE_ARN |
No | IAM role to assume before requesting ECR tokens. |
AWS_ECR_REGISTRY_IDS |
No | Comma-separated AWS account IDs to synchronize. |
AWS_ECR_ENDPOINT_URL |
No | Alternate HTTP(S) ECR API endpoint for an AWS-compatible service or isolated validation. |
AUTO_CREATE |
No | Create a missing platform registry when set to true; default is false. |
LOG_LEVEL |
No | Logrus level such as info, warn, or debug. |
LISTEN_PORT |
No | Health endpoint port; default is 8080. |
PLATFORM_URL |
Yes | Compatible environment API endpoint. |
PLATFORM_ACCESS_KEY |
Yes | Environment API access key. |
PLATFORM_SECRET_KEY |
Yes | Environment API secret key. |
New Catalog templates inject the PLATFORM_* variables documented in
COMPATIBILITY.md. During an in-place upgrade, the
executable also accepts the control plane's compatibility variable names only
when the corresponding neutral value is absent.
Use least-privilege AWS permissions that allow ECR authorization token requests.
If a shared AWS configuration is mounted under /home/pasturestack/.aws,
protect the mount as credential-bearing data.
docker run --rm \
-e AWS_REGION=us-east-1 \
-e AWS_ACCESS_KEY_ID \
-e AWS_SECRET_ACCESS_KEY \
-e PLATFORM_URL \
-e PLATFORM_ACCESS_KEY \
-e PLATFORM_SECRET_KEY \
ghcr.io/pasturestack/ecr-credential-sync:v3.1.0Windows Server 2022 hosts use the separately versioned
v3.1.2-windows-ltsc2022 image. The Catalog selects it only for Windows
environments; Linux deployments continue to use v3.1.0.
Do not publish a mutable latest tag. Deployment examples and Catalog
templates use immutable semantic version tags; release digests are retained
only in internal validation evidence.
The project uses a containerized Go 1.26.6 build environment with vendored
dependencies. The build image compiles Docker CLI 29.7.2 from its checksum- and
commit-locked official source with Go 1.26.6, and records both the binary hash
and embedded Go build information. It also locks Buildx 0.36.1 and installs
jq 1.8.1-4ubuntu2 as the fail-closed Dapper identity metadata parser. A
checksum-locked Buildx patch removes its sole compiled dependency on the legacy
Docker module and upgrades the compiled github.com/moby/go-archive and
golang.org/x/mod modules to v0.3.0 and v0.40.0.
The host build client is built twice as Buildx v0.36.1 by the repository-owned
scripts/install-locked-host-buildx verifier. GitHub Actions gives the verified
source builder an empty, caller-owned mode-0700 run root under $HOME, then
copies the byte-identical result into a separate run-owned DOCKER_CONFIG at
cli-plugins/docker-buildx. DAPPER_BUILDX_COMMAND remains bound to the
installer-returned binary, while every Dapper builder uses BuildKit v0.32.2 from
moby/buildkit:v0.32.2@sha256:28a898719c18a33f4e8000685287fa36fd0dd9560c6440227d3a732d79bb41d8.
These host-side locks are recorded in toolchain/host-build-toolchain.lock and
the source SBOM. The lock binds the exact Buildx source archive
(sha256:fb28b5c2a198d05482f0656dfb7ee161240a904e36697bf7108e5d517f23854b),
vendor/security patch
(sha256:b615fea76706a4c16e2af354b3a92d7b8b0465dce4f2d2c20b7a87bdc3100ad2),
Go 1.26.6 archive
(sha256:708effb774be8237570d0add163225abbdfaf4fca28b2611df167beba4feef89),
and resulting Linux amd64 binary
(sha256:ebb6935c31ef883684ec1721be8cc7e5d0386e5a445e90b7e81c7c8f5dac991d).
As of 2026-08-20, upstream v0.36.1 remains the latest signed Buildx release,
but its official binary still records go-archive v0.2.1 and x/mod v0.38.0;
upstream has no signed release containing both fixed module versions. Both the
Dapper and host plugins therefore use the same locked vendor upgrade instead
of an OpenVEX exception. The Ubuntu 26.04 base image is digest-pinned, and
all direct APT packages are locked to the official 20260808T000000Z Ubuntu
snapshot. Each image records its resolved dpkg inventory, and the build image
records the installed GCC, Go, Docker, Buildx, and jq binaries. The source
SBOM records the Ubuntu APT lock digest, snapshot, and exact Dapper jq version;
the Dapper image SBOM independently inventories the installed package.
Before any ordinary Go command runs, the Dapper build invokes the official
go telemetry off control and rewrites its dated mode file to the exact
off YYYY-MM-DD form using the UTC date derived from SOURCE_DATE_EPOCH.
It does not rely on a GOTELEMETRY environment variable. A shared fail-closed
readback checks the derived GOTELEMETRY and GOTELEMETRYDIR values, canonical
mode and parent metadata, and absence of local, upload, debug, weekends, and
counter state after every Go-running layer. The final mode and state manifests
are compared across both Dapper builds and described by the source SBOM.
Runtime packaging uses an isolated, run-owned docker-container builder with
that same pinned BuildKit image. It keeps rewrite-timestamp=true and
compatibility-version=20, exports to a CreateNew Docker archive, records and
reads back the archive SHA-256, and only then performs an explicit
docker image load. The Buildx IID is checked as the top-level config digest
when that field exists, or as the manifest digest when Buildx uses its documented
fallback. The loaded daemon image ID must match every available metadata config
source or the exported manifest digest, and the selected daemon-ID mode is
recorded before the package is accepted. At least one metadata config source
must exist, and all present sources must agree. Cleanup is limited to the exact
run-owned archive, Buildx instance, builder container, state volume, and—on a
failed load or identity gate—the newly created image reference; it never prunes
shared builder state.
If a development packaging host does not already provide the locked Buildx, build the verified source only under an empty, caller-owned run root:
mkdir -m 0700 "$RUN_ROOT/locked-host-buildx"
export DAPPER_BUILDX_COMMAND="$(bash scripts/install-locked-host-buildx "$RUN_ROOT/locked-host-buildx")"
"$DAPPER_BUILDX_COMMAND" versionThe helper verifies source, patch, and compiler hashes, builds twice with
GOPROXY=off and the locked vendor tree, compares dependency lists and binary
bytes, and checks the exact fixed module versions before returning the
executable path. It refuses existing, symlinked,
non-canonical, system, and global Docker plugin destinations. Every path
ancestor must be owned by root or the caller; group- or world-writable
ancestors must use the sticky bit. The helper binds subsequent operations to
the validated run-root identity and never writes to /usr or the user's global
Docker CLI plugin directory. GitHub Actions uses this same verifier and checks
the copied plugin's hash, mode, version, and commit before persisting its isolated
DOCKER_CONFIG. Its always-run cleanup removes only the two exact run roots
after their paths, ownership, modes, and directory identities are revalidated.
The development packaging harness must use this exact command for builder
create, inspect, and removal, and pass it to make with the pinned builder.
VERSION_OVERRIDE=v3.1.0 ARCH=amd64 make build
VERSION_OVERRIDE=v3.1.0 ARCH=amd64 make testThese commands are local build and test targets. CI/CD publication and release automation are outside this proof-of-concept scope.
GitHub Actions rebuilds the Linux binary and image twice without a build cache, using two isolated digest-pinned BuildKit builders. Each build applies Buildx's exact IID selection rule: the top-level configuration digest when present, or the exported manifest digest otherwise. It requires the metadata configuration sources to agree, then accepts the loaded Docker daemon ID only when it equals that configuration digest or the exported manifest digest and records which engine mode was observed. It then compares the two image IDs, configuration digests, complete RootFS DiffID lists, creation timestamps, binaries, and embedded manifests. The workflow produces source, build-image, and runtime CycloneDX SBOMs plus Trivy reports. It never logs in to a registry, pushes an image, creates a release, or changes a deployment.
The source SBOM intentionally inventories the preserved AWS SDK module even
though only its ECR and supporting packages are vendored. Module-level scanners
therefore report three S3 encryption-client advisories whose vulnerable package
is absent from both the vendor tree and the executable. The exact OpenVEX record
under security/ documents that boundary; any new or unmatched source finding
fails the supply-chain workflow.
- Go, Docker CLI, Buildx, BuildKit, GitHub Actions, Linux and Windows base images, and Trivy must use an exact version, commit, or immutable digest.
- The Ubuntu snapshot and every direct APT package version are one atomic lock;
update them together and verify the resolved
dpkgmanifests. - Operational container references remain plain semantic version tags. Do not
use
latest, branch tags, digest suffixes in user-facing image fields, or product-specific suffixes in version numbers. - A version refresh is complete only after unit and race tests, reproducibility checks, SBOM generation, vulnerability scanning, license checks, and the downstream Catalog compatibility review all pass.
Read SECURITY.md before deployment. This compatibility component handles AWS and platform credentials and must not be exposed as a public general-purpose service.
The affiliation disclaimer at the top of this README applies to all builds and distributions. Use the PastureStack repository issue tracker for project-specific reports, without including credentials, authorization tokens, or private URLs.
The project remains licensed under the existing Apache License 2.0. The license was not replaced by PastureStack. Vendored dependencies retain their own copyright, license, and notice files; redistribution must preserve them.