Receber por email
← Voltar para o catálogo

container-security-hardening

Harden Docker/container images and runtime deployments with secure base images, non-root users, CVE scanning, SBOM/signing, seccomp/AppArmor, and Kubernetes pod security controls. Use for Dockerfile security reviews, container CVEs, image scanning, distroless images, or production hardening.

41.2kestrelas
Atualizado há 4 meses

Ver no GitHub ↗ Licença: MIT

Como adicionar

/plugin marketplace add sickn33/antigravity-awesome-skills

O comando exato pode variar conforme o repositório. Confira o README no GitHub.

Para o autor da skill

Cole no README do seu repo

Mostra que sua skill está catalogada na Skillteca, gera backlink e tráfego rastreável.

[![Skillteca](https://www.skillteca.com.br/api/badge/container-security-hardening-sickn33/svg)](https://www.skillteca.com.br/skills/container-security-hardening-sickn33)

Skills relacionadas

Ver todas de DevOps e Infra →

Alerta por categoria

Receba novas skills de DevOps e Infra toda segunda

1 email curto, só com as skills novas de DevOps e Infra. 4 minutos de leitura, sem spam, cancela com 1 clique.

Você confirma o email no primeiro envio. Sem spam. Cancela com 1 clique.

Ler descrição completa

Container Security Hardening Skill

A production-focused guide for building, scanning, and running containers securely — from Dockerfile authoring through runtime enforcement and supply chain integrity.

When to Use This Skill

  • User mentions Docker security, container hardening, or Dockerfile security review
  • User asks about distroless images, non-root containers, or read-only filesystems
  • User wants to scan images for CVEs with Trivy, Grype, or Snyk
  • User mentions seccomp, AppArmor, Linux capabilities, or runtime security
  • User asks "is my Dockerfile secure?" or "how do I reduce my image attack surface?"
  • User wants to sign/verify images with Cosign or generate SBOMs
  • User asks about Kubernetes pod security, NetworkPolicy, or RBAC hardening
  • User says "fix container CVEs" or "harden my container for production"

When NOT to Use This Skill

  • The user is primarily asking about GitHub Actions CI/CD → recommend github-actions-advanced
  • The user needs general Docker usage help (not security) → recommend docker-expert
  • The user is working with Kubernetes orchestration beyond security → recommend kubernetes-architect
  • The user needs application-level security (SQL injection, XSS) → recommend api-security-best-practices

Step 1: Understand Context Before Responding

When invoked, first detect the current state:

# Find Dockerfiles in the project
find . -name "Dockerfile*" -not -path "*/node_modules/*" | head -10

# Check for existing security tooling
ls .trivyignore .hadolint.yaml .snyk docker-compose*.yml 2>/dev/null

# Inspect base images currently in use
grep -r "^FROM" $(find . -name "Dockerfile*") 2>/dev/null

# Check if Kubernetes manifests exist
find . -name "*.yaml" -path "*/k8s/*" -o -name "*.yaml" -path "*/manifests/*" | head -10

Then adapt recommendations to:

  • The tech stack (Node, Python, Go, Java — affects base image choice)
  • Whether this is Docker-only or Kubernetes-deployed
  • The CI platform in use (for scanner integration)
  • The existing base images and how far they are from best practice

The Five Layers of Container Security

1. Image Build        → Minimal base, no secrets, non-root, read-only FS
2. Image Scanning     → CVE scanning, SBOM, secret detection, Dockerfile lint
3. Runtime Security   → Capabilities, seccomp, AppArmor, resource limits
4. Supply Chain       → Signed images, pinned digests, trusted registries
5. Kubernetes Layer   → Pod Security Admission, NetworkPolicy, RBAC, Kyverno
Work through layers in order — hardening the image first gives the most leverage.
See references/base-image-comparison.md for a full size/CVE trade-off table.

Layer 1: Dockerfile Hardening

1.1 Use a Minimal Base Image

# ❌ AVOID — massive attack surface (~100–200 CVEs typical)
FROM ubuntu:latest
FROM node:20

# ✅ BETTER — slim variants (glibc, smaller apt footprint)
FROM node:20-slim
FROM python:3.12-slim

# ✅ BEST — distroless (no shell, no package manager, built-in nonroot user)
FROM gcr.io/distroless/nodejs20-debian12
FROM gcr.io/distroless/python3-debian12
FROM gcr.io/distroless/static-debian12   # Go/Rust fully-static binaries

# ✅ ALSO GREAT — Alpine (musl libc; verify app compatibility first)
FROM alpine:3.20

# ✅ ZERO ATTACK SURFACE — for fully static binaries only
FROM scratch

See references/base-image-comparison.md for the full trade-off matrix.

1.2 Multi-Stage Build — Separate Build from Runtime

Never ship build tools, compilers, or dev dependencies in a production image.

# syntax=docker/dockerfile:1

# ── Stage 1: Install & Build ──────────────────────────────
FROM node:20-slim AS builder
WORKDIR /build
COPY package*.json ./
RUN npm ci                          # Install all deps (including devDeps)
COPY . .
RUN npm run build && npm prune --production

# ── Stage 2: Runtime — minimal, no build tools ────────────
FROM gcr.io/distroless/nodejs20-debian12@sha256:<digest>
LABEL org.opencontainers.image.source="https://github.com/org/repo"
LABEL org.opencontainers.image.revision="${BUILD_SHA}"
LABEL org.opencontainers.image.licenses="MIT"
WORKDIR /app
COPY --from=builder --chown=nonroot:nonroot /build/dist        ./dist
COPY --from=builder --chown=nonroot:nonroot /build/node_modules ./node_modules
USER nonroot:nonroot                # UID 65532 — built into distroless
EXPOSE 3000
CMD ["dist/server.js"]

Go / Rust static binary pattern:

FROM golang:1.22-alpine AS builder
WORKDIR /build
COPY go.* ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-s -w" -o app .

FROM scratch                        # Zero attack surface
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
COPY --from=builder /build/app /app
USER 65532:65532
ENTRYPOINT ["/app"]

1.3 Run as Non-Root User

# For debian/ubuntu-based images — create dedicated user
RUN groupadd -r appgroup --gid 10001 && \
    useradd -r -g appgroup --uid 10001 --no-log-init appuser

COPY --chown=appuser:appgroup . /app

USER appuser    # Switch before CMD/ENTRYPOINT — never run as root

# ─────────────────────────────────────────────────────────
# For Alpine-based images
RUN addgroup -g 10001 -S appgroup && \
    adduser -u 10001 -S appuser -G appgroup

# For distroless — nonroot (UID 65532) is already built in
USER nonroot:nonroot

1.4 Pin Base Images to Digest

# ❌ UNSAFE — tags are mutable; image can be silently overwritten (supply chain attack)
FROM node:20-slim

# ✅ SAFE — SHA256 digest is cryptographically immutable
FROM node:20-slim@sha256:a1b2c3d4e5f6789abcdef0123456789abcdef0123456789abcdef0123456789ab

Get the current digest:

docker pull node:20-slim
docker inspect node:20-slim --format='{{index .RepoDigests 0}}'

Automate digest pinning with Renovate or Dependabot:

// .renovaterc.json
{
  "extends": ["config:base"],
  "dockerfile": { "enabled": true },
  "pinDigests": true
}

1.5 Never Bake Secrets into Images

# ❌ NEVER — secret in ENV or RUN; visible in `docker history` and layer cache
ENV AWS_SECRET_ACCESS_KEY=supersecret
RUN curl -H "Authorization: Bearer $TOKEN" https://api.example.com > config.json
ARG API_KEY                         # Also unsafe — visible in build args history

# ✅ CORRECT — BuildKit secret mount (never persisted in any layer)
# syntax=docker/dockerfile:1
RUN --mount=type=secret,id=api_token \
    curl -H "Authorization: Bearer $(cat /run/secrets/api_token)" \
    https://api.example.com/config > config.json

Build with: docker build --secret id=api_token,src=./token.txt .

Check your image for leaked secrets:

docker history --no-trunc myapp:latest | grep -iE "secret|key|password|token"
trivy image --scanners secret myapp:latest

1.6 Read-Only Filesystem & No New Privileges

# In the Dockerfile — use exec form (no shell interpretation)
ENTRYPOINT ["node", "server.js"]    # ✅ exec form
# ENTRYPOINT /bin/sh -c "node..."  # ❌ shell form — spawns extra process

# Define a HEALTHCHECK
HEALTHCHECK --interval=30s --timeout=5s --start-period=10s --retries=3 \
  CMD ["node", "-e", "require('http').get('http://localhost:3000/health', r => process.exit(r.statusCode === 200 ? 0 : 1))"]

Enforce read-only at runtime (see Layer 3).

1.7 Minimal .dockerignore

# Always exclude these from build context
.git
.github
.env
.env.*
*.pem
*.key
node_modules
__pycache__
.pytest_cache
coverage/
dist/
*.log
.DS_Store
Dockerfile*
docker-compose*
README.md
docs/
tests/

1.8 Full Hardened Dockerfile Example

# syntax=docker/dockerfile:1

# ── Build stage ───────────────────────────────────────────
FROM node:20-slim AS builder
WORKDIR /build
COPY package*.json ./
RUN --mount=type=cache,target=/root/.npm \
    npm ci
COPY . .
RUN npm run build && npm prune --production

# ── Runtime stage ───────────────────────
Compartilhar X LinkedIn