Containers and Security: Isolation and Images
Containers changed how software is shipped: an application and everything it needs are packaged in a single unit that runs the same way on a laptop, a test server or a cloud platform. They are fast and convenient, and they also create new security questions. In this lesson you will understand what a container really is, what isolation it offers and does not offer, and a short list of practices that prevent most problems.
What is a container?
A virtual machine simulates an entire computer, including its own operating system. A container is lighter: it is an ordinary process on the host that the operating system isolates and limits, so that it sees its own files, its own network and its own list of processes. All containers on a host share the host's operating system kernel.
Analogy: a virtual machine is a separate house with its own foundations. A container is an apartment in a building: the walls are solid and each apartment has its own door, but the foundations, the pipes and the electrical system are shared. If the building's foundation has a defect, every apartment is affected.
How the isolation works, in a nutshell
- Namespaces give each container its own view of the system: its own processes, network interfaces, file system and users.
- Control groups limit how much processor, memory and other resources a container can consume.
- Capabilities and security profiles restrict the privileged operations a container may perform.
This isolation is good, but it is not the same as the strong boundary of a virtual machine. A weakness in the shared kernel, or a dangerous configuration, can let a process escape its container. Sensitive workloads sometimes use stronger isolation, such as running containers inside lightweight virtual machines.
Images: the recipe and the ingredients
A container starts from an image, a read-only package that holds an application and its dependencies. Images are built in layers, usually starting from a base image published by someone else, and stored in a registry. This supply chain is where many risks hide:
- The base image may contain known vulnerabilities in the system libraries.
- An image from an untrusted source may contain malicious code.
- An image may contain secrets, such as keys or passwords baked in during the build, and these remain in the layers even if a later step deletes the file.
- Images that are never updated become more vulnerable every month.
Good practices for images
- Use trusted, minimal base images. Fewer components mean fewer vulnerabilities and a smaller attack surface.
- Pin versions deliberately, so builds are reproducible, and update regularly to receive security fixes.
- Scan images for known vulnerabilities (the CVE entries you met in the previous course) in your build pipeline and in your registry.
- Never bake secrets into images. Provide them at run time through a proper secret management mechanism.
- Sign and verify images where possible, so that only images from your pipeline can run.
- Keep a list of components (a software bill of materials) so that when a new vulnerability is announced you can quickly tell which images are affected.
Here is a short, generic illustration of a defensive image build file. The exact syntax depends on the tool, but the ideas are universal:
FROM minimal-base-image:pinned-version
COPY app/ /app/
RUN create-unprivileged-user appuser
USER appuser
EXPOSE 8080
CMD ["/app/start"]
The important lines are the pinned minimal base, the creation of a non-privileged user and the instruction to run as that user. By default, many containers run as the all-powerful root user inside the container, which makes any compromise worse.
Good practices at run time
- Run as a non-root user.
- Drop unnecessary privileges. Remove capabilities the application does not need.
- Avoid privileged mode. A privileged container has almost the same power as the host itself; it should be exceptional and justified.
- Do not give a container control of the container engine. Mounting the engine's control socket into a container is equivalent to giving it administrator control of the host.
- Make the file system read-only when possible, and write only to designated volumes.
- Set resource limits to prevent one container from starving others.
- Limit network access. Containers should reach only the services they need.
- Mount only what is required from the host, and avoid sharing sensitive host directories.
Orchestrators and the bigger picture
In production, containers are usually managed by an orchestrator, a system that starts, stops, scales and connects containers across many machines. It introduces its own components that need protection: a control interface with powerful permissions, a place where configuration and secrets are stored, a network between workloads and role-based permissions. The same principles apply: least privilege for identities, restricted network paths between workloads, encrypted and controlled access to secrets, and thorough logging. A badly secured control interface exposed to the internet is the container equivalent of the public storage container from lesson 5.1.
What an auditor looks for
- Image provenance: where do images come from and who builds them?
- Vulnerability management: are images scanned and updated, and who acts on the results?
- Privileges: do containers run as non-root, with minimal capabilities?
- Secrets: how are they stored and delivered?
- Network exposure: what can talk to what?
- Host and orchestrator hardening: patching, access control, logging.
As always, an authorization is required to inspect someone else's environment. For practice, build your own small containers in your lab, scan them and fix what you find.
Common misunderstandings
- "Containers are secure by default." They offer useful isolation, but the defaults are not hardened.
- "An image from a public registry must be safe." Popularity is not proof; check the publisher and scan.
- "Containers are disposable, so patching does not matter." You must rebuild and redeploy images to apply fixes; running old images keeps old vulnerabilities.
- "Deleting a secret in a later layer removes it." The earlier layer still contains it.
Your turn: spot the risks
A fictional team describes its container setup. List at least five problems and fixes.
- The image is built from an unmaintained public image that nobody has updated for a long time.
- A database password is written into the image build file so the application can connect.
- The application container runs as the root user in privileged mode, "to avoid permission problems".
- The container engine's control socket is mounted into the container, "so the app can restart itself".
- There is no vulnerability scanning in the pipeline.
See a solution
- Unmaintained base image: use a trusted, maintained, minimal base and update it regularly.
- Password in the image: remove it, rotate it (consider it exposed) and provide it at run time through secret management.
- Root and privileged mode: run as a non-root user, drop capabilities and solve the underlying permission issue properly.
- Engine socket mounted: this effectively hands host control to the container. Remove it and use a safer mechanism, such as the orchestrator's own restart logic.
- No scanning: add vulnerability scanning of images in the pipeline and registry, with a defined owner and response time for the results.
Portfolio step
In 05-cloud-modern-apps, add container-hardening.md: a checklist for the build and run-time practices in this lesson, plus an annotated before-and-after example of an image build file for a fictional application. Keep it clearly labeled as a defensive guide.
Key takeaways
- Containers are isolated processes sharing the host kernel; their isolation is useful but weaker than that of virtual machines.
- Images are a supply chain: trust sources, keep them minimal, scan, update and never embed secrets.
- At run time, avoid root and privileged mode, drop capabilities, limit resources and network access, and never expose the engine socket to a container.
- Orchestrators add powerful control components that need strict access control and logging.
- Rebuild and redeploy to apply security fixes; deleting a secret in a later layer does not remove it.
The last lesson of this chapter shows how to bring all this into the daily work of development teams.