Skip to content

rohitrsrohit/day-10-container-security

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

1 Commit
 
 
 
 
 
 
 
 

Repository files navigation

🔒 Day 10 — Container Security Hardening

30 Days of DevOps | Day 10/30 — Docker & Containerization

A complete container security toolkit: a side-by-side vulnerable vs secure Dockerfile comparison, a 10-check automated security audit script, live hardening demos (read-only FS, capability dropping, non-root users), a restrictive seccomp profile, and Trivy CVE scanning integration.


🎯 What This Project Covers

1. Non-root user           — adduser + USER instruction
2. Read-only filesystem    — --read-only + --tmpfs /tmp
3. Capability dropping     — --cap-drop=ALL + add only what's needed
4. No privilege escalation — --no-new-privileges
5. Hardcoded secrets       — detect in ENV vars and Dockerfile
6. Image size              — Alpine, multi-stage, layer optimization
7. Health checks           — HEALTHCHECK instruction
8. Base image pinning      — exact version or @sha256 digest
9. Trivy CVE scanning      — HIGH/CRITICAL vulnerability detection
10. seccomp profile        — restrict syscall surface

📁 Project Structure

day-10-container-security/
├── sample-apps/
│   ├── vulnerable-app/
│   │   └── Dockerfile.vulnerable    # ← What NOT to do (annotated)
│   └── secure-app/
│       ├── Dockerfile.secure        # ← Best practices (annotated)
│       ├── .dockerignore            # ← Excludes .env, .git, tests
│       └── src/
│           ├── index.js
│           └── package.json
├── scripts/
│   ├── audit.sh                     # 10-check security audit
│   └── harden_demo.sh               # live before/after demos
├── tests/
│   └── test_security.sh             # 15 automated tests
├── configs/
│   └── seccomp-profile.json         # restrictive syscall allowlist
├── docker-compose.yml               # secure service config
├── docs/
│   └── checklist.md                 # security checklist
├── .gitignore
└── README.md

🚀 Quick Start

git clone https://github.com/YOUR_USERNAME/day-10-container-security.git
cd day-10-container-security
chmod +x scripts/*.sh tests/*.sh

# Run pre-flight tests
bash tests/test_security.sh

# Run hardening demo (side-by-side secure vs insecure)
bash scripts/harden_demo.sh alpine:latest

# Run security audit on any image
bash scripts/audit.sh nginx:alpine
bash scripts/audit.sh ubuntu:latest
bash scripts/audit.sh node:18-alpine

# Audit your own image with Dockerfile check
bash scripts/audit.sh myimage:latest sample-apps/secure-app/Dockerfile.secure

# Build and audit the secure app
docker build -t day10-secure:latest \
  -f sample-apps/secure-app/Dockerfile.secure \
  sample-apps/secure-app/
bash scripts/audit.sh day10-secure:latest sample-apps/secure-app/Dockerfile.secure

🆚 Vulnerable vs Secure Dockerfile

Issue Vulnerable Secure
Base image ubuntu:latest node:18.19-alpine3.18
Base tag :latest (unpinned) Exact version
User root appuser (UID 1001)
Secrets ENV DB_PASSWORD=secret Injected at runtime
COPY COPY . . (everything) Only src/
CMD form Shell form Exec form ["node","..."]
HEALTHCHECK None Configured
.dockerignore None Excludes .env, .git, tests
Build stages Single Multi-stage (no devDeps)

🔒 Hardened docker run Command

docker run \
  --read-only \                        # read-only root filesystem
  --tmpfs /tmp:rw,size=64m \           # writable RAM-only /tmp
  --user 1001:1001 \                   # non-root user
  --cap-drop=ALL \                     # drop all Linux capabilities
  --cap-add=NET_BIND_SERVICE \         # add back only what's needed
  --no-new-privileges \                # no privilege escalation
  --security-opt no-new-privileges:true \
  --security-opt seccomp=configs/seccomp-profile.json \
  --memory=256m \                      # max 256MB RAM
  --cpus=1.0 \                         # max 1 CPU core
  --pids-limit=100 \                   # max 100 processes
  --network my-app-net \               # specific network
  -e DB_PASSWORD="${DB_PASSWORD}" \    # secret at runtime only
  -p 8080:3000 \                       # unprivileged internal port
  day10-secure:latest

🔍 CVE Scanning with Trivy

# Install Trivy
brew install trivy            # macOS
apt install trivy             # Debian/Ubuntu

# Or via Docker (no install)
docker run aquasec/trivy image nginx:alpine
docker run aquasec/trivy image ubuntu:latest

# Scan for HIGH + CRITICAL only
trivy image --severity HIGH,CRITICAL nginx:alpine

# Scan Dockerfile for misconfigurations
trivy config sample-apps/secure-app/Dockerfile.secure

📋 Security Checklist

  • Non-root USER in Dockerfile
  • Pinned base image (not :latest)
  • Alpine or slim base (minimal attack surface)
  • Multi-stage build (no devDeps in final image)
  • .dockerignore excludes .env, .git, node_modules
  • No ENV secrets in Dockerfile
  • HEALTHCHECK configured
  • CMD uses exec form (["node","..."])
  • --read-only at runtime
  • --cap-drop=ALL at runtime
  • --no-new-privileges at runtime
  • Resource limits (--memory, --cpus)
  • Trivy scan passing (no HIGH/CRITICAL)
  • seccomp profile applied
  • Specific Docker network (not default bridge)

🤝 Part of 30 Days of DevOps

Day Topic
Days 6–9 ✅ Docker Fundamentals
Day 10 ✅ Container Security Hardening (this project)
Day 11 GitHub Actions CI Pipeline

📄 License

MIT — free to use, modify, and distribute.

About

day-10-container-security

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors