This article focuses on container security in Azure Kubernetes Service (AKS), with emphasis on the earlier stages of the container lifecycle, where many security issues originate.
Why containers are not secure by default
There’s a widespread assumption in engineering teams: “We’re running in Kubernetes, so we’re good.” This is understandable, as containers feel isolated, AKS abstracts away a lot of infrastructure complexity, and Azure manages the control plane. But isolation is not the same as security.
Containers share the host kernel. A misconfigured pod can read secrets from other namespaces, reach internal services it has no business talking to, or run as root with full filesystem write access. The attack surface in a containerised workload spans the entire lifecycle, from the moment you write a Dockerfile to the moment a pod is serving production traffic.
Think of it as four stages, each with its own risk category:
Build → Registry → Deploy → Runtime
Each stage introduces different threats. Each stage also has well-understood controls. The goal here is to walk through all of them, not as a compliance checklist, but as a practical map of where the leverage is.
Note: Security defaults in Kubernetes are permissive by design, as the project prioritised operational flexibility over hardening. AKS inherits this. Hardening is not enabled by default and must be configured.
Image Security: The First Line of Defence
Everything starts with the image. A vulnerable or bloated base image carries its problems all the way to production, regardless of what you do at the cluster level.
Base image hygiene
The single highest-leverage decision is your choice of base image. The smaller and more minimal, the smaller the attack surface. Three patterns dominate production environments:
- Distroless images – contain only your app and its runtime dependencies. No shell, no package manager, no unnecessary binaries. An attacker who gains code execution has almost nothing to work with. Google maintains a well-known set of distroless images for most major runtimes.
- Alpine-based images – tiny, but do include a shell and a package manager. A practical middle ground when you need some tooling at build time and can live with slightly more surface area.
- Full OS images (ubuntu, debian) – avoid in production unless you have a specific reason. Every preinstalled package is a potential CVE waiting to be discovered.
Beyond the base image, use multi-stage builds. This means running your build process (SDK, compiler, test tooling) in one stage and copying only the compiled output into a clean runtime image. The final image never sees your build tools.
And one rule that sounds obvious but gets skipped constantly: never run your container as root. Add a non-root USER in your Dockerfile. If the application gets compromised, a non-root process has dramatically fewer options for lateral movement.
# Stage 1: build
FROM mcr.microsoft.com/dotnet/sdk:8.0 AS build
WORKDIR /src
COPY . .
RUN dotnet publish -c Release -o /app
# Stage 2: runtime only — no SDK, no build tools
FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY --from=build /app .# Never run as root
USER 1001
ENTRYPOINT ["dotnet", "MyApp.dll"]Image scanning
Building a clean image is one thing. Knowing what CVEs are lurking in your dependencies is another. Image scanning tools analyse layers and manifests against known vulnerability databases – NVD, OSV, vendor advisories.
The main open-source options here are Trivy (by Aqua Security, excellent general-purpose scanner) and Grype (by Anchore, particularly strong on SBOM workflows). Both drop cleanly into a CI pipeline and can fail a build if critical vulnerabilities are found. Azure Container Registry also has built-in vulnerability scanning powered by Microsoft Defender, which is useful if you want findings surfaced directly in the Azure portal without extra tooling.
The key practice: scan on every build, not just on a schedule. A CVE that ships silently in a dependency update is a problem. A CVE that fails the pipeline is a task.
Registry & Supply Chain
Once an image is built, it lives in a registry. The registry is not just storage, it is part of your trust boundary.
Azure Container Registry
ACR is the natural choice in an AKS environment. It integrates directly with AKS through managed identity, meaning your cluster can pull images without credentials in manifests. Enable private endpoints to ensure traffic between ACR and AKS never traverses the public internet.
Stop using :latest
The :latest tag is an anti-pattern in production. It is mutable the image it points to can change between deployments without any visible change in your manifests. Pin images to a specific digest (the immutable SHA256 hash of the image content). This ensures that what you tested is exactly what runs.
image: myregistry.azurecr.io/myapp@sha256:a3f2...Image signing
Pulling an image from your registry does not guarantee it hasn’t been tampered with in transit or that the registry itself hasn’t been compromised. Image signing addresses this. Tools like Notation (the CNCF standard) or cosign (from Sigstore) allow you to cryptographically sign images at build time and verify signatures at deploy time. AKS can be configured with admission controllers (like Ratify) to reject unsigned or unverified images before they ever start.
Software Bill of Materials (SBOM)
An SBOM is a machine-readable inventory of everything inside your image, including every library, every version, and every licence. It sounds like a compliance artefact, but it is genuinely operationally useful: when a new CVE drops, you can immediately query your SBOMs to know which services are affected rather than manually tracing dependencies. Trivy and Syft can both generate SBOMs as part of a standard CI pipeline.
At this stage, the process establishes the foundation: teams build, scan, and store the image in a controlled registry.
The next layer of controls applies at deployment and runtime, where configuration and runtime behaviour define the effective security posture.
This includes controls such as Security Contexts, Network Policies, runtime detection, and secrets management, which are covered in the next part.
👉 Continue reading: Container Security in AKS: From Image to Runtime (Part 2 – Deploy & Runtime)
