# Container Hardening

> Harden container images and Kubernetes workload security contexts — distroless, multi-stage, minimal attack surface.

- **Type:** Skill
- **Install:** `agentstack add skill-sawrus-agent-guides-container-hardening`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [sawrus](https://agentstack.voostack.com/s/sawrus)
- **Installs:** 0
- **Category:** [Cloud & Infrastructure](https://agentstack.voostack.com/c/cloud-infrastructure)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [sawrus](https://github.com/sawrus)
- **Source:** https://github.com/sawrus/agent-guides/tree/main/areas/devops/devsecops/skills/container-hardening
- **Website:** https://sawrus.github.io/agent-guides

## Install

```sh
agentstack add skill-sawrus-agent-guides-container-hardening
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# Skill: Container Hardening

> **Expertise:** Minimal images, distroless, multi-stage builds, security context, Dockerfile best practices, Trivy scanning.

## When to load

When building a new Dockerfile, hardening an existing image, failing Trivy scan, or setting up pod security contexts.

## Hardened Dockerfile (Python example)

```dockerfile
# ── Stage 1: Build (has build tools, not in final image) ──
FROM python:3.12-slim@sha256: AS builder

WORKDIR /app
COPY requirements.txt .
RUN pip install --user --no-cache-dir -r requirements.txt

# ── Stage 2: Runtime (minimal, no build tools) ───────────
FROM python:3.12-slim@sha256:

# Create non-root user
RUN groupadd -r appgroup --gid=1000 && \
    useradd -r -g appgroup --uid=1000 --no-create-home appuser

WORKDIR /app

# Copy only built artifacts from builder
COPY --from=builder /root/.local /home/appuser/.local
COPY --chown=appuser:appgroup src/ ./src/

# Remove SETUID binaries (attack surface reduction)
RUN find / -perm /6000 -type f -exec chmod a-s {} \; 2>/dev/null || true

# Switch to non-root
USER 1000:1000

# Read-only filesystem friendly: temp dir for app writes
VOLUME ["/tmp"]

EXPOSE 8080

# Prefer exec form (handles signals correctly)
ENTRYPOINT ["python", "-m", "uvicorn", "src.main:app", "--host", "0.0.0.0", "--port", "8080"]
```

## Distroless (Go example — smallest attack surface)

```dockerfile
FROM golang:1.23-alpine AS builder
WORKDIR /app
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build -ldflags="-w -s" -o server ./cmd/server

# Distroless: no shell, no package manager, no OS utilities
FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /app/server /server
USER nonroot:nonroot
EXPOSE 8080
ENTRYPOINT ["/server"]
```

## Pod Security Context (K8s manifest)

```yaml
spec:
  securityContext:
    # Pod-level
    runAsNonRoot: true
    runAsUser: 1000
    runAsGroup: 1000
    fsGroup: 1000
    seccompProfile:
      type: RuntimeDefault    # enables syscall filtering

  containers:
    - name: app
      securityContext:
        # Container-level
        allowPrivilegeEscalation: false
        readOnlyRootFilesystem: true
        capabilities:
          drop: ["ALL"]
          # add only if explicitly needed:
          # add: ["NET_BIND_SERVICE"]  # bind to port < 1024

      # Writable temp dir for app that needs /tmp
      volumeMounts:
        - name: tmp
          mountPath: /tmp

  volumes:
    - name: tmp
      emptyDir: {}
```

## Trivy Scan Workflow

```bash
# Scan filesystem (during build, before image creation)
trivy fs . \
  --severity CRITICAL,HIGH \
  --exit-code 1 \
  --ignorefile .trivyignore

# Scan built image
trivy image \
  --severity CRITICAL,HIGH \
  --exit-code 1 \
  --format sarif \
  --output trivy-results.sarif \
  registry.example.com/my-service:${GIT_SHA}

# Scan with SBOM (generates and scans simultaneously)
trivy image \
  --format cyclonedx \
  --output sbom.json \
  registry.example.com/my-service:${GIT_SHA}
```

## .trivyignore (CVE exceptions)

```
# CVE-2024-XXXXX - no fix available; tracked in JIRA SEC-456; review 2024-12-01
CVE-2024-XXXXX
```

## Common Hardening Failures + Fixes

| Failure | Cause | Fix |
|:---|:---|:---|
| `runAsRoot` | No USER in Dockerfile | Add `USER 1000:1000` |
| Mutable tag | `:latest` or `:main` | Pin to `@sha256:digest` |
| SETUID binary | Default OS image | Strip: `chmod a-s /usr/bin/passwd` |
| Writable root FS | `readOnlyRootFilesystem: true` blocks writes | Mount `emptyDir` for `/tmp`, `/var/run` |
| Secrets in image | `COPY .env` or `ARG password` | Multi-stage + Docker secrets |

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [sawrus](https://github.com/sawrus)
- **Source:** [sawrus/agent-guides](https://github.com/sawrus/agent-guides)
- **License:** MIT
- **Homepage:** https://sawrus.github.io/agent-guides

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** yes
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-sawrus-agent-guides-container-hardening
- Seller: https://agentstack.voostack.com/s/sawrus
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
