- aws-kubectl Docker Image
- Contents
- Why this image?
- Prerequisites
- Getting started
- Pinning guidance
- Features
- Supply chain
- Tag management
- Breaking Changes in v2.0
- Mounting credentials
- Running the Container
- Build Instructions
- Local Build & Test (using the repo script)
- Security Notes
- Run as root (override)
- Standardization reference
- About the maintainer
This image streamlines work with Amazon Web Services (AWS) and Kubernetes by bundling AWS CLI v2 (aws) and kubectl on Ubuntu 24.04. It also includes jq, curl, unzip, and envsubst (from gettext-base). Perfect for CI/CD steps, automation, and reproducible local scripting.
🐳 Docker Hub: heyvaldemar/aws-kubectl
| Need | This image | amazon/aws-cli |
bitnami/kubectl |
Alpine + scripts |
|---|---|---|---|---|
| AWS CLI v2 | ✅ | ✅ | ❌ | manual |
| kubectl | ✅ | ❌ | ✅ | manual |
| jq, envsubst, curl, unzip | ✅ | ❌ | ❌ | manual |
| Multi-arch (amd64/arm64) | ✅ | ✅ | ✅ | depends |
| Cosign signatures | ✅ | ✅ | ❌ | ❌ |
| SBOM (SPDX) | ✅ | ❌ | ❌ | ❌ |
| SLSA build provenance | ✅ | ❌ | ❌ | ❌ |
| OpenSSF Scorecard | 7.8/10 | N/A | N/A | N/A |
| Non-root default (UID 10001) | ✅ (v2.0+) | ❌ | ❌ | depends |
| Weekly base rebuild | ✅ | ✅ | ✅ | manual |
One image instead of three. Full supply-chain attestations. OpenShift-compatible out of the box.
- Docker installed locally. Quick check:
docker version. The image ships AWS CLI v2 andkubectlinside, so you don't need either installed on your host. Multi-arch (amd64 + arm64) — works on Linux, macOS (Intel + Apple Silicon), Windows + WSL2. - (Optional) AWS credentials in
~/.aws/if you want to run AWS commands. Create withaws configurefrom any machine that has aws-cli — or copy from an existing setup. The image mounts the dir read-only by convention. - (Optional)
kubeconfigin~/.kube/if you want to runkubectlcommands against an existing cluster. Create withaws eks update-kubeconfig --name <cluster>or your tool of choice.
You can also run the container with no mounts for aws --version, kubectl version --client, or any tool that doesn't need cloud/cluster credentials.
# List S3 buckets (requires ~/.aws)
docker run --rm --user "$(id -u):0" \
-v ~/.aws:/home/app/.aws \
heyvaldemar/aws-kubectl aws s3 ls
# Get Kubernetes nodes (requires ~/.kube)
docker run --rm --user "$(id -u):0" \
-v ~/.kube:/home/app/.kube \
heyvaldemar/aws-kubectl kubectl get nodes
# Interactive shell with both
docker run -it --user "$(id -u):0" \
-v ~/.aws:/home/app/.aws \
-v ~/.kube:/home/app/.kube \
heyvaldemar/aws-kubectl bashRuns as non-root by default (UID 10001). See Mounting credentials for permission details.
🚨 Existing v1.x user and v2.0 broke your workflow? Pin
heyvaldemar/aws-kubectl:v1-maintenancefor security updates through July 2026. Migration details →
For production use, pin to immutable semver tags:
- ✅ Stable:
heyvaldemar/aws-kubectl:2.0.0— immutable on Docker Hub, never purged ⚠️ Fragile:heyvaldemar/aws-kubectl:sha-1dfda81— short-SHA tags are deleted after 90 days
If you pin by manifest digest (recommended for maximum supply chain integrity), make sure the digest is also referenced by a semver tag. Otherwise the digest may become unpullable once short-SHA cleanup runs. To resolve a tag to its current digest:
docker buildx imagetools inspect heyvaldemar/aws-kubectl:2.0.0 \
--format '{{.Manifest.Digest}}'- Ubuntu 24.04 base for stability.
- AWS CLI v2 for full AWS management.
- kubectl (pin a specific version or use the latest stable at build time).
jq,curl,unzip,envsubst, andca-certificatespreinstalled.- Multi-stage build: build-only intermediates (AWS CLI zip, extracted tree, kubectl archive) never enter the final image.
- Checksum verification for
kubectlduring build. - Multi-arch ready (amd64/arm64) when built/pushed with
buildx. - OCI labels (
org.opencontainers.image.*) on every published image. - Resolved kubectl version written to
/etc/kube-versioninside the image.
Default user is non-root (UID 10001, GID 0) as of v2.0. If you need root — e.g. to install additional
aptpackages at runtime — override with--user 0:0. See Breaking Changes in v2.0 for migration details.
- GitHub Actions / GitLab CI pipelines — one image instead of installing aws-cli + kubectl + jq separately in every job
- EKS cluster operations — AWS auth via aws-cli, then kubectl against the cluster, in a single container
- OpenShift / restricted PodSecurityPolicy environments — non-root default (UID 10001, GID 0) works out of the box
- Multi-cluster scripting — consistent tooling across dev/staging/prod kubeconfigs
- Air-gapped or restricted networks — pre-built image with checksum-verified binaries, no runtime
curl | bash
- Base image pinned by
sha256digest (ubuntu:24.04@sha256:…). Dependabot'sdockerecosystem bumps the digest weekly. - Multi-stage
Dockerfilekeeps build-only intermediate artefacts (the downloaded AWS CLI archive, extracted tree, kubectl tarball, and checksum file) out of the published image. kubectlbinaries are verified against the upstreamsha256checksum published atdl.k8s.ioduring build.- Weekly scheduled rebuilds pick up Ubuntu base-image security updates (
cron: "0 6 * * 1"). - CI lints the Dockerfile with
hadolintand shell scripts withshellcheckbefore any build runs. - All third-party GitHub Actions are pinned to a commit SHA with a version comment.
- Build arguments
VCS_REFandBUILD_DATEare stamped intoorg.opencontainers.image.revisionandorg.opencontainers.image.created, and the resolved kubectl release is exposed viaio.heyvaldemar.kubectl.versionand/etc/kube-version. - Every published digest is cosign-signed via Sigstore keyless OIDC using the GitHub Actions identity for this repository.
- SBOM (SPDX, generated by BuildKit) and SLSA build provenance (
provenance: mode=max) are attached to every published image. - GitHub native build provenance is attested via
actions/attest-build-provenanceand stored in GitHub Attestations. Registry push is disabled because Docker Hub's OCI referrer credential handoff proved unreliable in early Phase 2 hotfix testing — see CHANGELOG[2.0.0]CI section for context. - Trivy scans the published image on every push; CRITICAL and HIGH fixable findings are uploaded as SARIF to the repository's GitHub Security tab.
cosign verify heyvaldemar/aws-kubectl:latest \
--certificate-identity-regexp "https://github.com/heyvaldemar/aws-kubectl-docker/.*" \
--certificate-oidc-issuer "https://token.actions.githubusercontent.com"Tags fall into five categories:
- Exact semver (
:2.0.0,:v2.0.0) — immutable on Docker Hub; the digest under these tags never changes after first push. Recommended for production pins. - Rolling semver (
:2.0,:2) — mutable; re-targets to the newest patch (and minor) within the major on each release. Kept forever. - Floating channels (
:latest,:edge,:v1-maintenance) — updated on every main build; kept forever. - Kubernetes-version pin (
:kube-v1.36.0) — generated only on semver releases. Tracks the kubectl release packaged into the image at the time of that release. Immutable on Docker Hub; kept forever. - Short-SHA builds (
:sha-<7char>) — produced by CI for every commit to main. Immutable while live; retained for 90 days, then automatically deleted by theDocker Hub Tag Cleanupworkflow.
Cosign signatures (:sha256-<digest>.sig) are managed by Sigstore and are not deleted.
Starting with v2.0.0, this image runs as a non-root user (UID 10001, GID 0) by default. This aligns with modern container security best practices and is required for compatibility with OpenShift, restricted Kubernetes PodSecurityPolicy profiles, and enterprise security scanners.
If you use this image for one-off CI commands (aws s3 sync, kubectl apply),
v2.0 works identically to v1.x.
If you mount a host directory or Kubernetes PVC, you may need to adjust file ownership or run the container with a matching UID:
Docker:
docker run --rm -v "$PWD:/home/app" --user "$(id -u):0" \
heyvaldemar/aws-kubectl:latest aws s3 lsKubernetes:
spec:
securityContext:
runAsUser: 10001
runAsGroup: 0
fsGroup: 0If v2.0 breaks your workflow and you need time to migrate, pin to the v1 maintenance track:
docker pull heyvaldemar/aws-kubectl:v1-maintenanceThe v1-maintenance tag will receive security updates through July 20, 2026,
after which it will be frozen.
~/.aws– AWS credentials/config (credentials,config). Mount to/home/app/.awsinside the container.~/.kube– kubeconfig(s). Mount to/home/app/.kubeinside the container.
The container's default user is UID 10001 with
HOME=/home/app. Pass--user "$(id -u):0"when mounting host files so the container can read them.
Interactive shell with both configs (mount under /home/app — the non-root user's HOME — and match your host UID so the container can read the mounted files):
docker run -it \
--user "$(id -u):0" \
-v ~/.aws:/home/app/.aws \
-v ~/.kube:/home/app/.kube \
heyvaldemar/aws-kubectl bashIf you pulled an amd64-only tag on an ARM/M-series Mac:
docker run --platform linux/amd64 -it \
--user "$(id -u):0" \
-v ~/.aws:/home/app/.aws \
-v ~/.kube:/home/app/.kube \
heyvaldemar/aws-kubectl bash# List S3 buckets
docker run --rm \
--user "$(id -u):0" \
-v ~/.aws:/home/app/.aws \
heyvaldemar/aws-kubectl aws s3 ls
# Get Kubernetes nodes
docker run --rm \
--user "$(id -u):0" \
-v ~/.kube:/home/app/.kube \
heyvaldemar/aws-kubectl kubectl get nodesThe Dockerfile accepts the following build arguments:
| ARG | Default | Purpose |
|---|---|---|
KUBE_VERSION |
latest |
Pin a specific kubectl release (e.g. v1.30.6). latest fetches the current stable from dl.k8s.io. |
VCS_REF |
unknown |
Commit SHA, stamped into org.opencontainers.image.revision. |
BUILD_DATE |
unknown |
ISO-8601 build timestamp, stamped into org.opencontainers.image.created. |
TARGETARCH |
auto | Target architecture (amd64/arm64). Supplied automatically by buildx. |
# From the folder with the Dockerfile
docker build -t aws-kubectl:local .docker build --build-arg KUBE_VERSION=v1.30.6 \
-t aws-kubectl:local .If KUBE_VERSION is omitted, the build fetches the latest stable from dl.k8s.io.
docker build \
--build-arg KUBE_VERSION=v1.30.6 \
--build-arg VCS_REF="$(git rev-parse HEAD)" \
--build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
-t aws-kubectl:local .docker buildx create --name x --use || docker buildx use x
# Generic tag (no OS name in the tag)
docker buildx build \
--platform linux/amd64,linux/arm64 \
--build-arg VCS_REF="$(git rev-parse HEAD)" \
--build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
-t heyvaldemar/aws-kubectl:latest \
--push .
# Or pin kubectl in a tag users can reason about
KUBE_VERSION=v1.30.6
docker buildx build \
--platform linux/amd64,linux/arm64 \
--build-arg KUBE_VERSION=$KUBE_VERSION \
--build-arg VCS_REF="$(git rev-parse HEAD)" \
--build-arg BUILD_DATE="$(date -u +'%Y-%m-%dT%H:%M:%SZ')" \
-t heyvaldemar/aws-kubectl:kube-$KUBE_VERSION \
--push .Verify:
docker buildx imagetools inspect heyvaldemar/aws-kubectl:latestOptional supply-chain flags (if you want SBOM/provenance):
--sbom=true --provenance=true
This repo includes scripts/smoke-test.sh to validate the tools in the image.
- Build locally
docker build -t aws-kubectl:local .- Run the smoke test
chmod +x scripts/smoke-test.sh
./scripts/smoke-test.sh # defaults to aws-kubectl:local
./scripts/smoke-test.sh your/tag:dev # test any tag you passThe script checks:
- OS/arch
- Versions: AWS CLI, kubectl (client), jq, envsubst, curl, unzip
- That
/etc/kube-versionmatcheskubectl version --client - Binary locations & CA bundle
- HTTPS reachability (header-only)
- (Optional) AWS STS +
kubectlcluster calls if you mount~/.aws/~/.kube
Quick verification one-liners (click to expand)
IMG=aws-kubectl:local
# OS/arch
docker run --rm $IMG sh -lc 'uname -a; echo -n "Arch: "; uname -m'
# Core tools & versions
docker run --rm $IMG aws --version
docker run --rm $IMG kubectl version --client --output=yaml
docker run --rm $IMG jq --version
docker run --rm $IMG envsubst --version
docker run --rm $IMG sh -c 'curl --version | head -n1'
docker run --rm $IMG sh -c 'unzip -v | head -n2'
# Resolved kubectl release stamped at build time
docker run --rm $IMG cat /etc/kube-version
# Binaries present where expected
docker run --rm $IMG sh -c 'ls -l /usr/local/bin/kubectl; for b in aws jq envsubst curl unzip; do command -v "$b"; done'
# CA bundle present + HTTPS sanity
docker run --rm $IMG sh -c 'ls -lh /etc/ssl/certs/ca-certificates.crt'
docker run --rm $IMG sh -c 'curl -fsSI -o /dev/null -w "HTTPS OK (%{http_code})\n" https://kubernetes.io'# AWS identity (requires valid creds)
docker run --rm --user "$(id -u):0" \
-v ~/.aws:/home/app/.aws \
aws-kubectl:local aws sts get-caller-identity
# Current k8s context & nodes (requires valid kubeconfig)
docker run --rm --user "$(id -u):0" \
-v ~/.kube:/home/app/.kube \
aws-kubectl:local kubectl config current-context
docker run --rm --user "$(id -u):0" \
-v ~/.kube:/home/app/.kube \
aws-kubectl:local kubectl get nodes -o wide- Runs as non-root by default (UID 10001, GID 0) as of v2.0.
kubectlbinaries are checksum-verified during build.- APT is minimal (
--no-install-recommends) and lists are cleaned. - Pin
KUBE_VERSIONin CI for reproducibility.
If a specific workflow requires root inside the container (e.g. installing additional apt packages at runtime, or restoring pre-v2.0 behaviour), override the user:
docker run --rm --user 0:0 heyvaldemar/aws-kubectl bashThe patterns in this image are codified as a reusable standard at heyvaldemar/self-host-repo-hardening-runbook → IMAGE-PUBLISHING-RUNBOOK.md. If you maintain a Dockerfile-based repo and want to follow the same standard, the runbook covers:
- Multi-stage Dockerfile with base-image digest pinning
- Full OCI labels (
org.opencontainers.image.*) - BuildKit attestations (SBOM + SLSA
provenance: mode=max) - Cosign keyless signing via Sigstore (with rationale for pinning Cosign v2.6.1 over v3.x)
- Tag retention + Docker Hub immutability policy
- Weekly base-image rebuild via cron
- Pinning guidance documentation for downstream consumers
Six mandatory phases plus an optional non-root migration phase for repos with existing :latest audiences. Eight production-grounded pitfalls drawn from this repo's own PR history.
Maintained by Vladimir Mikhalev — Docker Captain · IBM Champion · AWS Community Builder