← Harden & defendkeep a popped container from becoming a popped host

keep a popped container from becoming a popped host

$trivy

a popped container should stay popped, not spread

containers get treated like magic isolation boxes. they're not. they're just processes with some kernel namespacing and cgroup boundaries wrapped around them. if your app inside that container gets compromised and the container is running as root with full capabilities and a writable filesystem, the attacker just got handed a much bigger playground than "one hacked app." this post is about shrinking that playground before it ever ships.

stop running as root

this is the single dumbest, most common mistake in container images and it's also the easiest to fix. if your app runs as root inside the container and something breaks out of that container context, root inside is a lot closer to root outside than people want to admit. add a dedicated user in your dockerfile:

RUN adduser --disabled-password --gecos "" appuser
USER appuser

put that near the end of your dockerfile, after you've installed everything and set permissions on the files your app actually needs. once you switch to USER appuser, anything that tries to write outside its lane or escalate privileges has a much harder time.

drop capabilities you don't need

docker containers by default get a chunk of linux capabilities even when they don't need most of them. things like NET_RAW, SYS_ADMIN, SYS_PTRACE sitting around unused are just extra tools for whoever pops your app. drop everything and only add back what's required:

docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE your-image

most web apps don't need to bind low ports, trace other processes, or mess with raw sockets. if you're not sure what your app actually needs, run it with everything dropped first and see what breaks. that's your real capability list, not the default one docker assumes you want.

make the filesystem read-only

a writable container filesystem means an attacker who gets code execution can drop tools, modify binaries, or persist a backdoor right there in the container layer. flip that off:

docker run --read-only --tmpfs /tmp your-image

the --tmpfs /tmp part matters because plenty of apps still need somewhere to write temp files or sockets. give them a small ephemeral spot instead of the whole filesystem. anything that tries to write somewhere else just fails, which is exactly the point.

scan the image before you ship it, not after

none of the runtime hardening above matters if the image itself is full of known cves because you pulled a base image from six months ago and never looked back. this is where trivy comes in, it's a free scanner that checks your image against vulnerability databases:

trivy image your-image:latest

it'll spit out a list of cves by severity, tied to the specific packages and versions baked into your layers. run it before every build ships, not as a once-a-quarter fire drill. you can even fail your ci pipeline on high or critical findings:

trivy image --exit-code 1 --severity HIGH,CRITICAL your-image:latest

that one line turns "we'll patch it eventually" into "this doesn't merge until it's fixed." trivy also scans dockerfiles and iac configs for misconfigurations, so it's worth running against your whole repo, not just the final image.

the takeaway

none of this stops an app from getting exploited, that's a different fight. what it does is make sure the blast radius stays inside the container instead of turning into a host compromise, a lateral movement path, or a full cluster takeover. run as a non-root user, drop capabilities down to the bare minimum, lock the filesystem to read-only, and scan every image with trivy before it ships. do those four things consistently and a popped app stays a contained, annoying incident instead of a resume-generating event. go check your own dockerfiles today, most people find at least one of these missing.

watch the reel ↗
the weekly drop

one command a week that makes you harder to hack.

a single tool, explained in plain english, every week. straight to your inbox.

no spam. one email a week. unsubscribe anytime.