# Base Image Selection Standards
## Rule
All container images MUST use approved base images. Prefer minimal images to reduce attack surface. Pin versions by digest for reproducibility.
## Approved Base Images (Priority Order)
1. **Distroless** — no shell, no package manager, smallest attack surface
2. **Alpine** — minimal Linux with musl libc, ~5MB base
3. **Slim variants** — Debian slim, Ubuntu minimal
4. **Full OS images** — only when dependencies require it (document reason)
## Examples
### Good
```dockerfile
# Best — Distroless for production
FROM gcr.io/distroless/nodejs20-debian12@sha256:abc123...
# Good — Alpine with pinned version
FROM node:20.11-alpine3.19
# Acceptable — Slim variant with pin
FROM python:3.12-slim-bookworm
```
### Bad
```dockerfile
# Bad — latest tag (unpinned, changes without notice)
FROM node:latest
# Bad — full OS image without justification
FROM ubuntu:22.04
# Bad — no version pin
FROM python
```
## Multi-Stage Build Pattern
```dockerfile
# Build stage — can use full image
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Production stage — minimal image
FROM gcr.io/distroless/nodejs20-debian12
COPY --from=build /app/dist /app/dist
COPY --from=build /app/node_modules /app/node_modules
WORKDIR /app
CMD ["dist/server.js"]
```
## Update Policy
- Base images must be updated within 7 days of a security advisory
- Run weekly automated scans of all base images in use
- Track base image versions in a central registry
## Anti-Patterns
- Using `latest` tag (unpredictable, breaks reproducibility)
- Using full OS images for simple applications
- Not using multi-stage builds (build dependencies in production)
- Pinning tags but not digests (tags can be moved)
- Never updating base images after initial setup