# Container Security

> Hardening rules for Dockerfile, OCI images, Kubernetes manifests, and Helm charts — Applies to: when generating a Dockerfile or OCI image build; when generating Kubernetes / Helm / Kustomize manifests; when reviewing container changes in PR

- **Type:** Skill
- **Install:** `agentstack add skill-shieldnet-360-secure-vibe-container-security`
- **Verified:** Pending review
- **Seller:** [ShieldNet-360](https://agentstack.voostack.com/s/shieldnet-360)
- **Installs:** 0
- **Category:** [Cloud & Infrastructure](https://agentstack.voostack.com/c/cloud-infrastructure)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [ShieldNet-360](https://github.com/ShieldNet-360)
- **Source:** https://github.com/ShieldNet-360/secure-vibe/tree/main/dist/claude-skills/.claude/skills/container-security

## Install

```sh
agentstack add skill-shieldnet-360-secure-vibe-container-security
```

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

## About

# Container Security

Hardening rules for Dockerfile, OCI images, Kubernetes manifests, and Helm charts

## ALWAYS

- Use **multi-stage builds**: separate builder/test stages from the final runtime image so build toolchains and source aren't shipped. The last stage should be `FROM distroless`, `FROM scratch`, `FROM alpine:`, or another minimal base — pinned by SHA256 digest, not just tag.
- Run as a non-root user: `USER ` (numeric UID >= 10000 for K8s `runAsNonRoot` policies to be enforceable). Set USER explicitly on the **final stage** — omitting USER entirely leaves the container running as root by default, which is the same as `USER root`.
- Use **`npm ci`** (and equivalents `pnpm install --frozen-lockfile`, `yarn install --frozen-lockfile`) in container builds, not `npm install`. `npm install` mutates the lockfile and resolves versions per-build, producing non-deterministic images that drift from the lockfile.
- Add a `.dockerignore` excluding `.git`, `node_modules`, `.env`, `*.pem`, `*.key`, `target/`, `.terraform/`, `dist/`, `coverage/`.
- Enable **BuildKit** (`DOCKER_BUILDKIT=1` or `# syntax=docker/dockerfile:1`) for `--mount=type=secret` support and better cache isolation.
- Emit an **SBOM** (`docker buildx --sbom=true` / `syft`) and attach it to the image so downstream scanners can audit the dependency set.
- Pin **apt** packages and clean lists in the same layer: `apt-get install -y --no-install-recommends pkg=1.2.3 && rm -rf /var/lib/apt/lists/*`. Unpinned installs make image contents non-reproducible.
- Set explicit `HEALTHCHECK` for long-running services and matching `livenessProbe` / `readinessProbe` / `startupProbe` in K8s.
- Set resource `requests` and `limits` on every container (CPU and memory).
- Drop all Linux capabilities then add back only what's needed: `securityContext.capabilities.drop: [ALL]`.
- Apply a seccomp profile (`RuntimeDefault` at minimum) and AppArmor / SELinux where available.
- Mark filesystem read-only: `readOnlyRootFilesystem: true`; use `emptyDir` volumes for the few paths that must be writable.
- Scan every image in CI (Trivy, Grype, Snyk, or your registry's scanner) and fail builds on CRITICAL or HIGH severity findings.
- Pull base images by SHA256 digest in production manifests, not by mutable tag.
- For **multi-tenant** workloads (per-user/per-customer sessions on shared infra), isolate tenants at the **kernel boundary**: a separate VM — or gVisor / Kata — per tenant, never just separate containers on one shared daemon. Drop `privileged`, enable user namespaces, and give each tenant its own network. A privileged container on a shared host escapes to the host trivially, so on shared infra that is full compromise of *every* co-tenant.
- Expose container orchestration to clients only through a **scoped, authenticated broker API** that performs the few operations a client may request (start/stop *my* session). The client must never hold direct daemon or cluster access.

## NEVER

- Run containers as root or with `privileged: true` / `allowPrivilegeEscalation: true` outside of explicit, audited system pods (e.g., CNI plugins).
- Use **end-of-life base images**. As of mid-2026 this includes `node:` if the runtime is unfamiliar.
- Mount the host docker socket (`/var/run/docker.sock`) inside an application container. It's effectively root on the host.
- Expose the container **daemon API over the network** (`tcp://…:2375`, or `:2376` even with TLS) to clients or apps. The daemon API is root-on-host: whoever reaches it runs arbitrary privileged containers and mounts the host filesystem. (A desktop/CLI app talking straight to a remote daemon is the same anti-pattern as a mounted `docker.sock`, just over TCP.)
- Ship a **single shared client credential** (one mTLS cert/key, token, or kubeconfig bundled into every copy of a distributed app) to reach that daemon or cluster. Every install holds the same key — trivially extracted from the app bundle — so it grants every user identical access and cannot be revoked per-user. Issue per-user / per-session, short-lived, scoped credentials.
- Run a tenant's container `privileged` on a host shared with other tenants, or attach tenant containers to a **shared external bridge network** — the first gives container-escape → co-tenant takeover, the second gives cross-tenant L3 reachability.
- Embed secrets in image layers via `ENV`, `ARG`, `COPY`, or by `echo`-ing them to a file. Even if `--squash`'d, BuildKit cache and registry layers leak.
- Run `curl … | sh` or `wget -O- … | sh` in a `RUN` — piping an unverified remote script to a shell is arbitrary remote code at build time. Download, verify a pinned SHA-256, then execute.
- Use `latest`, `stable`, `slim`, or unversioned tags as the final image base — builds become non-reproducible and quietly pick up CVEs.
- Use `ADD ` to fetch remote resources during build (use `curl --fail` with a checksum verify and `RUN` instead, or vendor the artifact).
- Disable `automountServiceAccountToken` when the workload needs the K8s API, but DO disable it (`automountServiceAccountToken: false`) when it doesn't.
- Use `hostNetwork: true`, `hostPID: true`, or `hostIPC: true` for application pods.
- Run pods in the `kube-system` namespace, or any namespace without a `NetworkPolicy` and PodSecurity admission policy.

## KNOWN FALSE POSITIVES

- Operators that legitimately need cluster-admin access (kubelet, CSI drivers, CNI plugins) require elevated privileges; they belong in `kube-system` or a dedicated namespace with auditing, not in application namespaces.
- Bare-metal Kubernetes nodes sometimes legitimately disable `seccomp` for drivers that aren't compatible; document the exception.
- One-shot debugging pods (kubectl debug, ephemeral containers) intentionally bypass many of these controls; they should not be persisted as YAML in the repo.
- A remote Docker / K8s endpoint over mTLS (`:2376`) is acceptable for an **operator's own** CI / build farm where each operator holds a personal, revocable cert — the anti-pattern is shipping **one shared** cert inside a distributed end-user app.
- `privileged` or a shared bridge network within a **single trust domain** (one team's own microservices, or a sim stack on the developer's own machine) is lower-risk than the multi-tenant case; these rules target the shared-host, cross-tenant blast radius specifically.

## Source & license

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

- **Author:** [ShieldNet-360](https://github.com/ShieldNet-360)
- **Source:** [ShieldNet-360/secure-vibe](https://github.com/ShieldNet-360/secure-vibe)
- **License:** MIT

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:** yes
- **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: flagged — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-shieldnet-360-secure-vibe-container-security
- Seller: https://agentstack.voostack.com/s/shieldnet-360
- 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%.
