devopsApache-2.0 License Verified
Docker Container Hardening
Multi-stage Docker builds, non-root user execution, minimal distroless/Alpine base images, and vulnerability layer minimization.
#Docker#Containers#Security#Alpine#Distroless#Multi-Stage
Install for:
npx domoskills add docker-container-hardening
Security verified • Score: 90/100
Installs into:
.agent/skills/docker-container-hardeningSKILL.md Prompt Instructions
Read by AI agent on demand---
name: docker-container-hardening
description: Docker image security, multi-stage builds, non-root users, read-only filesystems, resource limits, and supply chain verification.
license: MIT
version: 1.8.0
---
# Docker Container Hardening
## Overview
A default Docker container runs as root, uses a mutable filesystem, and has no resource bounds. Container hardening removes these attack surfaces and limits blast radius if a container is compromised.
## 1. Multi-Stage Builds — Minimal Final Image
```dockerfile
# Stage 1: Build
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci --frozen-lockfile
COPY . .
RUN npm run build
# Stage 2: Runtime — only what is needed
FROM node:20-alpine AS runner
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs && \
adduser --system --uid 1001 nextjs
COPY --from=builder --chown=nextjs:nodejs /app/.next/standalone ./
COPY --from=builder --chown=nextjs:nodejs /app/.next/static ./.next/static
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
USER nextjs
EXPOSE 3000
ENV NODE_ENV=production PORT=3000 HOSTNAME="0.0.0.0"
CMD ["node", "server.js"]
```
## 2. Non-Root User (Required)
```dockerfile
RUN groupadd -r appgroup && useradd -r -g appgroup -u 1001 appuser
USER appuser
```
Verify: docker run --rm your-image id — must NOT print uid=0(root).
## 3. Read-Only Root Filesystem
```yaml
services:
app:
image: myapp:latest
read_only: true
tmpfs:
- /tmp:uid=1001,gid=1001,size=100m
- /run:uid=1001,gid=1001
```
## 4. Drop Linux Capabilities
```yaml
services:
app:
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE # Only if binding to ports < 1024
```
## 5. Resource Limits (Required)
```yaml
services:
app:
deploy:
resources:
limits:
cpus: "1.5"
memory: 512M
reservations:
cpus: "0.25"
memory: 128M
```
Without limits, a single runaway container can starve the host.
## 6. Image Scanning in CI
```yaml
- name: Scan image
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:latest
format: table
exit-code: 1
severity: HIGH,CRITICAL
ignore-unfixed: true
```
## 7. Image Signing (Supply Chain)
```sh
# Cosign keyless signing with GitHub OIDC
cosign sign --yes ghcr.io/myorg/myapp:latest
# Verify
cosign verify ghcr.io/myorg/myapp:latest \
--certificate-identity=https://github.com/myorg/myapp/.github/workflows/build.yml@refs/heads/main \
--certificate-oidc-issuer=https://token.actions.githubusercontent.com
```
## 8. .dockerignore
```
.git
.env
.env.local
node_modules
dist
*.log
tests/
.github/
```
## 9. Anti-Patterns
- FROM ubuntu:latest — pinless tags break reproducibility; use ubuntu:22.04@sha256:...
- RUN apt-get install without --no-install-recommends — bloats image.
- Storing secrets in Dockerfile ENV or ARG — visible in image history via docker history.
- --privileged containers — grants ALL Linux capabilities, equivalent to root on the host.
- Mounting /var/run/docker.sock — allows container escape.Ecosystem Radar & Recommended Companions
Standard Connectors
Antigravity (.agent)Claude Code (.claude)Cursor (.cursor)
Docker Container HardeningActive Capability
Frequently Stacked With