Безопасность контейнеров: практический чеклист для внедрения

Безопасность контейнеров: практический чеклист для внедрения
Photo by Naoki Suzuki / Unsplash

Контейнеры — мощный инструмент, но их неправильная настройка часто становится причиной утечек и компрометаций. Ниже — пошаговый чеклист с примерами, который можно внедрить прямо в ваших Docker и Kubernetes проектах.


1. Сборка: Multi-stage и минимальные образы

Почему:
Чем меньше пакетов и библиотек внутри контейнера, тем меньше потенциальных уязвимостей.

Пример:
Go-приложение без multi-stage сборки:

FROM golang:1.22
WORKDIR /app
COPY . .
RUN go build -o app
CMD ["./app"]

Такой образ будет весить ~1 ГБ, со множеством лишних пакетов.

С multi-stage:

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

# Runtime stage
FROM gcr.io/distroless/base
COPY --from=builder /app/app /
USER nonroot:nonroot
CMD ["/app"]

Финальный образ будет весить <100 МБ и содержать только бинарник.


2. Запуск: Только непривилегированные пользователи

Почему:
Запуск от root внутри контейнера = при побеге из контейнера атакующий получает root на ноде.

Пример в Dockerfile:

RUN adduser -u 1001 --disabled-password appuser
USER appuser

Пример в Kubernetes:

securityContext:
  runAsUser: 1001
  runAsNonRoot: true
  allowPrivilegeEscalation: false
  capabilities:
    drop: ["ALL"]

3. Политики: Pod Security Admission

Почему:
PSA автоматически запрещает запуск небезопасных подов (например, с root-привилегиями).

Пример:
Включаем baseline-политику на уровне namespace:

apiVersion: v1
kind: Namespace
metadata:
  name: secure-ns
  labels:
    pod-security.kubernetes.io/enforce: baseline
    pod-security.kubernetes.io/audit: baseline
    pod-security.kubernetes.io/warn: baseline

Если разработчик попробует запустить Pod с privileged: true, Kubernetes его просто не запустит.


4. Сканирование: Trivy в CI/CD

Почему:
CI/CD должен блокировать деплой уязвимых образов.

Пример в GitLab CI:

stages:
  - build
  - security

build_image:
  stage: build
  script:
    - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA .

scan_image:
  stage: security
  image: aquasec/trivy:latest
  script:
    - trivy image --exit-code 1 --severity HIGH,CRITICAL $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA

Если Trivy найдёт критические уязвимости — пайплайн упадёт.


5. Сетевые политики: NetworkPolicy

Почему:
По умолчанию все поды в Kubernetes могут ходить друг к другу. Это огромный риск.

Пример: API может ходить к БД, но не наоборот:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: db-allow-api
  namespace: prod
spec:
  podSelector:
    matchLabels:
      app: postgres
  ingress:
    - from:
        - podSelector:
            matchLabels:
              app: api
  policyTypes:
    - Ingress

Теперь никто кроме api не сможет подключиться к PostgreSQL.


Итог

Если внедрить эти пять шагов:
✅ Минимальные образы
✅ Запуск без root
✅ Pod Security Admission
✅ Автоматическое сканирование
✅ NetworkPolicy

— вы закроете 80% типичных ошибок безопасности контейнеров.