Spain · 2026 World Cup champions
AXTO
EngineeringJuly 23, 2026· 8 min read

Container Security Essentials: Beyond 'It Works on My Machine'

Containers changed deployment; they did not repeal security. The practical hardening layers for production Docker.

Containers isolate applications from each other — until they do not. Most container breaches walk through doors the operator left open, not kernel exploits. Closing those doors is checklist work.

Image hygiene

Pin bases to digests, not floating tags — 'latest' means 'whatever exists at build time', which is not a supply chain, it is a lottery. Build minimal: distroless or slim bases shrink the attack surface and the CVE-scanner noise. Scan in CI and fail the build on critical findings while the fix is a one-line bump — scanning production images without a gate is journaling, not security.

Runtime restraint

Never --privileged in production; it is root on the host wearing a costume. Drop capabilities by default and add back only what the process needs. Read-only root filesystem with explicit writable volumes turns many exploit chains into error messages. And do not mount the Docker socket into containers — that is handing out host control.

Secrets and networks

Environment variables leak into logs, inspect output, and crash dumps; prefer mounted secret files or a real secrets store. On the network side, containers on a default bridge can all talk to each other — define per-application networks so the blog engine cannot reach the billing database it has no business knowing exists.

Watch the runtime, not just the build

A clean scan at build time says nothing about what the container is doing at 2 a.m. The behavioral signals that matter: a container spawning shells it never spawned before, outbound connections to novel destinations, writes into paths that should be immutable. Container isolation makes those baselines tight — a service that does one thing deviates loudly when it starts doing another.

The supply chain behind every image

A container image is built from layers you did not write: a base operating system, language runtimes, libraries and tools. Each layer is part of your supply chain. Use official or verified base images from publishers you trust, keep a record of which images your services depend on, and prefer sources that publish signatures and software bills of materials so you can verify what you are running. Rebuild images regularly, even when your own code has not changed, so that security fixes in the base layers actually reach production.

Writing a safer Dockerfile

Small choices in the Dockerfile make a large difference. Use multi-stage builds so that compilers, package managers and build secrets stay in a build stage and never reach the final image. Add a non-root user and switch to it with the USER instruction, so that a compromised process does not start with root privileges inside the container. Copy only the files the application needs, and use a .dockerignore file to keep source control data, local configuration and credentials out of the build context. Set a health check so the orchestrator can detect a broken container and replace it.

Running as non-root and with fewer privileges

Running containers as a non-root user is one of the most effective hardening steps. Combine it with dropping Linux capabilities the application does not need, enabling the no-new-privileges option so processes cannot gain additional privileges through setuid binaries, and keeping the default seccomp and AppArmor or SELinux profiles enabled rather than disabling them for convenience. User namespace remapping, or rootless container runtimes, add another layer by mapping root inside the container to an unprivileged user on the host.

Resource limits as a security control

Limits on memory, CPU and the number of processes protect against more than runaway bugs. They also contain abuse: a compromised container used for cryptocurrency mining or a fork bomb cannot consume the whole host if it is capped. Set limits for every production container, and alert when containers repeatedly hit them, because unexpected resource use is often an early sign of compromise.

The host and the daemon

Containers share the host's kernel, so the host's security matters as much as the images. Keep the host minimal and patched, restrict who can run container commands — membership of the docker group is effectively root access — and never expose the Docker daemon's API over the network without strong authentication and encryption. Run only containers on production hosts, avoiding unrelated services that widen the attack surface. Enable audit logging for the daemon so that container creation and configuration changes are recorded.

Orchestration adds its own controls

When containers run under an orchestrator such as Kubernetes, many of these practices can be enforced centrally. Pod security standards can reject privileged containers and require non-root users. Network policies restrict which workloads may talk to which. Secrets objects, ideally encrypted at rest and backed by an external secrets manager, replace credentials in environment variables. Role-based access control limits who can deploy or change workloads. Admission controls can require images to come from approved registries and carry valid signatures.

Image signing and provenance

Signing images lets you verify, at deployment time, that an image was built by your pipeline and has not been altered. Open tooling makes it practical to sign images in CI and verify signatures before they run. Pair signatures with provenance information describing how and from which source an image was built, and configure deployments to reject unsigned images. This closes a common gap in which anyone able to push to a registry could replace a production image.

Incident response for containers

When a container misbehaves, preserve evidence before replacing it. Capture its logs, its configuration and, if possible, a snapshot of its filesystem changes; containers are short-lived, and the evidence disappears when they are removed. Then replace the container from a known-good image, rotate any secrets it could access and investigate how the compromise happened, because the same weakness will exist in every replica built from the same image.

A practical baseline

For every production container: a pinned, regularly rebuilt base image, scanned in CI with a gate on critical findings; a non-root user; dropped capabilities and no-new-privileges; a read-only root filesystem where possible; resource limits; secrets mounted from a secrets store; a dedicated network; no Docker socket mounts; and behavioral monitoring at runtime. None of these steps is exotic, and together they close most of the doors attackers actually use.

Registries deserve protection too

The registry that stores your images is a high-value target: whoever can push to it can replace what runs in production. Require authentication for pushes and pulls of private images, give CI pipelines push access only to the repositories they build, use separate credentials for each pipeline and rotate them. Enable vulnerability scanning in the registry as well as in CI, so that newly published vulnerabilities are flagged on images that were clean when they were built. Remove old images you no longer run; they accumulate vulnerabilities and confuse inventories.

Development environments matter

Many container compromises start on developer machines: an image pulled from an untrusted source, a container run with the host filesystem mounted, or a local registry exposed to the network. Encourage the same habits locally as in production — trusted base images, non-root users, no privileged containers — and keep development credentials separate from production ones. Tools that run containers without root privileges on the host reduce the impact of mistakes.

Logging what containers do

Containers should write logs to standard output and error, where the runtime or orchestrator can collect them centrally; logs written inside a container's filesystem vanish when it is replaced. Include enough context to investigate an incident — request identifiers, user identifiers where appropriate and clear error messages — without logging secrets or unnecessary personal data. Combine application logs with runtime events such as container starts, stops, restarts and configuration changes.

Keeping the baseline current

Container security is not a one-time project. New vulnerabilities appear in base images every week, orchestrator features change and teams add services. Review your baseline a few times a year, measure how many running images exceed it — for example, those still running as root or with critical unpatched findings — and track that number down over time. Steady improvement across the fleet matters more than perfection in a single service.

The bottom line

Containers make it easy to ship software quickly, and with a little discipline they also make it easier to run software safely: every service gets a minimal, reproducible environment with clear boundaries. The practices above are mostly configuration rather than new products. Applied consistently through templates and pipeline checks, they turn container security from an aspiration into a default that every new service inherits automatically.

Questions to ask in every review

When reviewing a new service before it reaches production, a few questions catch most problems. Which base image does it use, and who rebuilds it when fixes are published? Does it run as root, and if so, why? Which capabilities, volumes and ports does it really need? Where do its secrets come from? Which other services can it reach on the network, and which can reach it? How would we know if it started behaving differently? A service whose owner can answer these quickly is usually in good shape.

Run AI on your own terms

AXTO gives you world-class AI apps and self-hosted editions — on your own keys, your own data.