Reduce workload attack surface with distroless image
These days workloads should be containerized because it's easier to manage and reproduce. However, vulnerabilities do and will exist in the base image. Because base images that you are familiar with - alpine, debian, ubuntu - all contain shell and package manager. This means that if you can somehow access the shell through vulnerabilities, you can do pretty much anything.
It's possible for a web service to have vulnerabilities that allow an attacker to access the shell:
- Privileged pod escalations in Kubernetes and GKE
- Amazon EKS Flaws Expose AWS Credentials and Enable Privilege Escalation
- React2Shell (CVE-2025-55182)
This means your cloud credentials can be compromised, and many things can happen to your cloud account. An attacker spawning VMs to mine bitcoins, that would mean you are losing money, but it'll be worse if they exfiltrate your data and distribute it on the dark web, or mine it themselves.
If you use distroless images, it means that your workload can run normally, but they can't access the shell, which limits what an attacker can do. It's like crippling them, which is a good thing. Distroless images do provide a debug tag with shell access, in case you need to debug something (but you should never use the debug tag for production).
If you are working with compiled languages like Go and Rust, it'll be very easy to use distroless image. gcr.io/distroless/static-debian13 should work for most cases, but if your workload depends on glibc, you probaby need to use gcr.io/distroless/cc-debian13. Also note that for multi-stage docker build, the build layer also needs to use debian, since alpine image uses musl libc.
With Python, it's a bit more complicated, but this recipe works for me.
And for an extra measure, add grype to your CI to check for vulnerabilities in the built image and halt the pipeline if there are any.