agentsclimarketplace

Nethserver containerfile

Skill NethServer/agents/skills/nethserver-containerfile

Write and review secure, production-ready Containerfiles following NethServer container best practices. Use when creating a new Containerfile, reviewing an existing container image, or mentions "/Containerfile". Supports: (1) Rootless container configuration with non-root USER, (2) Multi-stage build separation of build and runtime, (3) Minimal and pinned base image selection (Alpine/Debian-slim), (4) Vulnerability scanning guidance with Trivy and layer inspection with Dive, (5) Renovate setup for automated dependency updatesFrom its SKILL.md

Install
npx -y skills add NethServer/agents --skill nethserver-containerfile

Assembled from the repository path, not quoted from the project. Check it against their README if it does not work.

One thing to look at

  • 1 stars1 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.

SKILL.md

4.9 KB, as published. Nobody here has run it

NethServer Secure Containerfile

Overview

Write and review Containerfiles following NethServer container security best practices. Source: NethServer Development Handbook — Creating Secure Containers


Rules (apply all unless explicitly overridden)

1. Rootless containers

Always run the container as a non-root user. Add a dedicated user at the end of the build stage:

RUN adduser -D -u 1001 appuser
USER appuser

If the upstream image already defines a non-root user (e.g., node, nobody), use it. Only omit this if the software cannot run rootless and you explicitly document why.

2. Multi-stage builds

Separate the build environment from the runtime image to keep the final image small and free of build tools:

# Stage 1: Build
FROM golang:1.22 AS builder
WORKDIR /app
COPY . .
RUN go build -o myapp

# Stage 2: Runtime
FROM alpine:3.20
WORKDIR /app
COPY --from=builder /app/myapp .
USER nobody
CMD ["./myapp"]

Use multi-stage builds for any compiled language (Go, Rust, Java, C/C++) and for Node.js apps that require a build step.

3. Minimal base images

Prefer minimal base images to reduce attack surface:

  • First choice: alpine:X.Y — smallest, fewest packages
  • Fallback (MUSL incompatibility): debian:X.Y-slim or ubuntu:X.Y
# Preferred
FROM alpine:3.20

# Fallback when Alpine is not compatible
FROM debian:12-slim

Never use bare distro images (FROM ubuntu, FROM debian) without the slim or minimal variant unless strictly required.

4. Pin image versions — never use latest

Always specify the exact version tag:

# Good
FROM alpine:3.20
FROM node:20-alpine3.20

# Bad — never do this
FROM alpine:latest
FROM node

Pinned versions ensure reproducible builds and prevent unexpected breakage from upstream changes.

5. Dependency pinning (optional, project-dependent)

When installing packages, you may pin versions for reproducibility:

# Alpine
RUN apk add --no-cache openssl=3.3.0-r0

# Debian/Ubuntu
RUN apt-get install -y --no-install-recommends openssl=3.0.11-1

Trade-off: strict pinning improves reproducibility but can delay security patches. Use Renovate (see below) to automate updates when pinning is used.

6. Automate dependency updates with Renovate

Add a renovate.json to the repository to keep base image versions and dependencies updated automatically. The NethServer default Renovate config is available at NethServer/.github.

7. No secrets in layers

  • Never COPY .env files, private keys, or credentials into the image.
  • Never pass secrets as ARG or ENV variables that end up in the final layer.
  • Use Docker secrets or environment injection at runtime instead.

Checklist before finishing a Containerfile

  • Final stage uses a non-root USER
  • Multi-stage build separates build and runtime (for compiled/built apps)
  • Base image tag is pinned (no latest)
  • Base image is minimal (alpine or *-slim)
  • No secrets or credentials baked into layers
  • Renovate is configured for automated updates
  • Image analyzed with Dive to inspect layers
  • Image scanned with Trivy for CVEs and secrets
  • SBOM generated with Trivy in CycloneDX format (.cdx.json) and attached to the release

Scanning and tooling

Trivy — vulnerability scan

# Scan a local image
trivy image myapp:latest

# Generate CycloneDX SBOM
trivy image --format cyclonedx --output myapp.cdx.json myapp:latest

Dive — layer inspection

dive myapp:latest

Use Dive to spot unnecessary files, leftover build artifacts, or accidentally included secrets.


Example: complete secure Containerfile (Go application)

# Stage 1: Build
FROM golang:1.22-alpine3.20 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o myapp .

# Stage 2: Runtime
FROM alpine:3.20
RUN apk add --no-cache ca-certificates tzdata \
    && adduser -D -u 1001 appuser
WORKDIR /app
COPY --from=builder /app/myapp .
USER appuser
EXPOSE 8080
CMD ["./myapp"]

Keep looking

Skills are one crate of 627,801. Ordering is by how many stacks a row turns up in, so the top of any crate is what has actually been picked rather than what has the most stars.