Container Security: What Every Developer Needs to Know
Containers changed how we ship software. They also changed the threat model. Traditional security focused on securing servers — containers require you to think about images, orchestration, networking, and runtime all at once. This guide demystifies container security for developers who want to ship confidently.
PandaStack runs Docker containers in production for thousands of applications. Here's what we've learned about securing them.
Why Container Security Is Different
Containers are not VMs. They share the host kernel, which means:
- A vulnerability in the kernel can affect every container on the host
- Misconfigured containers can escape to the host
- Shared image layers mean a vulnerability in a base image affects all images that build on it
Securing containers requires action at multiple layers: build time, registry, and runtime.
Step 1: Harden Your Dockerfile
Security starts at build time. Use multi-stage builds to keep your final image lean:
# Build stage
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
# Final stage — no build tools
FROM node:20-alpine
WORKDIR /app
COPY --from=builder /app/node_modules ./node_modules
COPY . .
RUN adduser -D appuser
USER appuser
EXPOSE 3000
CMD ["node", "src/index.js"]Multi-stage builds exclude compilers, package managers, and test dependencies from production images.
Step 2: Scan Images in CI
Integrate vulnerability scanning into your build pipeline:
# Install Trivy
brew install trivy
# Scan before push
trivy image --exit-code 1 --severity HIGH,CRITICAL my-app:latestThe --exit-code 1 flag fails the build if high or critical vulnerabilities are found.
Step 3: Use a Private Container Registry
Push images to a private registry, not Docker Hub public repos. Enforce image signing:
# Sign image with cosign
cosign sign --key cosign.key my-registry.io/my-app:latest
# Verify before deploy
cosign verify --key cosign.pub my-registry.io/my-app:latestOnly allow signed images to run in production.
Step 4: Limit Container Capabilities
Containers inherit Linux capabilities they don't need. Drop them all, then add back only what's required:
docker run --cap-drop ALL --cap-add NET_BIND_SERVICE --security-opt no-new-privileges my-app:latestThe no-new-privileges flag prevents privilege escalation via setuid binaries.
Step 5: Use Read-Only Root Filesystems
If your app doesn't need to write to the container filesystem, don't allow it:
docker run --read-only --tmpfs /tmp --tmpfs /var/run my-app:latestThis prevents attackers from writing malicious files if they gain code execution.
Step 6: Never Mount the Docker Socket
Mounting /var/run/docker.sock into a container gives it full control over the Docker daemon — effectively root on the host. Avoid it. Use dedicated APIs or sidecars for any use case that seems to require it.
Step 7: Network Segmentation
Containers should only communicate with the services they need. Use Docker networks to isolate groups:
# Create isolated network
docker network create --driver bridge app-network
# Attach only the containers that need to communicate
docker run --network app-network my-api
docker run --network app-network my-dbOn PandaStack, containers in the same deployment environment share a private network — external access is controlled through the platform's routing layer.
Step 8: Manage Secrets at Runtime
Never bake secrets into images. Inject them at runtime:
# Via PandaStack CLI
npm install -g @pandastack/cli
panda env:set API_KEY=my-secret-key --app my-appSecrets are encrypted at rest and injected as environment variables at container startup — they never appear in image layers or build logs.
Step 9: Set Resource Limits
Prevent a compromised or buggy container from consuming all host resources (a form of denial-of-service):
docker run --memory="256m" --memory-swap="256m" --cpus="0.25" my-appStep 10: Monitor Container Behavior at Runtime
Static security checks at build time catch known vulnerabilities. Runtime monitoring catches unexpected behavior — unusual network calls, new processes spawning, filesystem changes in unexpected locations.
PandaStack provides built-in monitoring and alerting for all container deployments. Configure thresholds and notification channels at [dashboard.pandastack.io](https://dashboard.pandastack.io).
Summary
Container security spans the full lifecycle: harden your Dockerfile, scan images in CI, use a private registry with signing, drop capabilities, use read-only filesystems, segment networks, manage secrets properly, set resource limits, and monitor at runtime. Build these practices into your workflow from day one. Full platform documentation at [docs.pandastack.io](https://docs.pandastack.io).