Gymterview
middle

Как организовать процесс обновления и патчинга базовых образов?

Уязвимости обнаруживаются постоянно — образ, безопасный сегодня, завтра может содержать критическую CVE. Регулярное обновление базовых образов и зависимостей является обязательным процессом для банковских систем и требованием стандартов безопасности (PCI DSS Requirement 6).

1. Стратегия фиксации (pin) версий:

Пример
# ПЛОХО — неизвестно, что получим при следующей сборке
FROM eclipse-temurin:21-jre

# ЛУЧШЕ — фиксация конкретной минорной версии
FROM eclipse-temurin:21.0.4_7-jre-alpine

# ЛУЧШЕЕ — pin по digest (неизменная ссылка на конкретный образ)
FROM eclipse-temurin@sha256:1a2b3c4d5e6f...

Тег (например, 21-jre) может указывать на разные образы в разное время — разработчики базового образа обновляют теги при выпуске патчей. Digest (@sha256:...) — это криптографический хеш, однозначно идентифицирующий конкретную версию образа. Pin по digest гарантирует воспроизводимость сборки, но требует дисциплины при обновлениях.

2. Автоматическое обнаружение обновлений с Renovate/Dependabot:

Renovate и Dependabot — инструменты, автоматически создающие Pull Request при появлении новых версий зависимостей. Они поддерживают Dockerfile, docker-compose, Maven, Gradle и другие экосистемы.

Пример
// renovate.json
{
  "$schema": "https://docs.renovatebot.com/renovate-schema.json",
  "extends": ["config:base"],
  "docker": {
    "enabled": true,
    "pinDigests": true
  },
  "packageRules": [
    {
      "matchDatasources": ["docker"],
      "matchPackageNames": ["eclipse-temurin"],
      "automerge": false,
      "schedule": ["every weekday"],
      "groupName": "base-image-updates"
    }
  ],
  "vulnerabilityAlerts": {
    "enabled": true,
    "labels": ["security"]
  }
}

Параметр pinDigests: true автоматически добавляет digest к тегам при создании PR. Параметр automerge: false означает, что PR с обновлением базового образа требует ручного review — для банковских систем автоматический merge обновлений обычно запрещён политиками безопасности.

Пример
# .github/dependabot.yml
version: 2
updates:
  - package-ecosystem: "docker"
    directory: "/"
    schedule:
      interval: "weekly"
    reviewers:
      - "security-team"
    labels:
      - "docker"
      - "dependencies"

  - package-ecosystem: "maven"
    directory: "/"
    schedule:
      interval: "daily"
    open-pull-requests-limit: 10

3. Периодическое пересканирование развёрнутых образов:

Новые CVE появляются ежедневно. Образ, не имевший известных уязвимостей при деплое, может стать уязвимым через неделю. Поэтому необходимо регулярно пересканировать уже развёрнутые образы:

Пример
# CronJob для ежедневного сканирования всех образов в кластере
apiVersion: batch/v1
kind: CronJob
metadata:
  name: image-scan
  namespace: security
spec:
  schedule: "0 6 * * *"  # Каждый день в 6:00
  jobTemplate:
    spec:
      template:
        spec:
          containers:
          - name: scanner
            image: aquasec/trivy:latest
            command:
            - /bin/sh
            - -c
            - |
              # Получить список уникальных образов во всех namespace-ах
              for image in $(kubectl get pods -A -o jsonpath='{.items[*].spec.containers[*].image}' | tr ' ' '\n' | sort -u); do
                echo "Scanning: $image"
                trivy image --severity CRITICAL,HIGH --exit-code 0 "$image"
              done
          restartPolicy: OnFailure
          serviceAccountName: image-scanner-sa

4. Процесс патчинга для банковского проекта:

Пример
1. Обнаружение (автоматическое):
   +-- Renovate/Dependabot создаёт PR с обновлением зависимости
   +-- Trivy обнаруживает CVE при ежедневном пересканировании
   +-- Подписка на security advisories (GitHub Advisory, Alpine SecDB, Spring Security)

2. Оценка (определение приоритета):
   +-- CVSS >= 9.0 (Critical)  -> патч в течение 24 часов
   +-- CVSS 7.0-8.9 (High)    -> патч в течение 7 дней
   +-- CVSS 4.0-6.9 (Medium)  -> патч в следующем плановом релизе
   +-- CVSS < 4.0 (Low)       -> в бэклог

3. Патчинг:
   +-- Обновить базовый образ в Dockerfile
   +-- Обновить зависимости (Maven/Gradle)
   +-- Прогнать полный набор тестов (unit, integration, e2e)
   +-- Сканировать новый образ на уязвимости
   +-- Деплой через стандартный CI/CD пайплайн

4. Верификация:
   +-- Повторное сканирование после деплоя (подтверждение устранения CVE)
   +-- Мониторинг стабильности сервиса в течение контрольного периода

SLA по патчингу (24 часа для Critical, 7 дней для High) — типичное требование PCI DSS и внутренних политик безопасности банков. Каждое исключение из SLA должно быть задокументировано с обоснованием и планом устранения.

5. Пересборка образов по расписанию:

Пример
# GitHub Actions: еженедельная пересборка для актуализации базового образа
name: Weekly Rebuild
on:
  schedule:
    - cron: '0 2 * * 1'  # Каждый понедельник в 2:00 UTC
  workflow_dispatch: {}   # Возможность ручного запуска

jobs:
  rebuild:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v4
    - name: Build with latest base image
      run: docker build --pull --no-cache -t banking-service:weekly .
    - name: Scan
      run: trivy image --exit-code 1 --severity CRITICAL banking-service:weekly
    - name: Push if clean
      run: docker push registry.bank.local/banking-service:weekly

Флаг --pull гарантирует, что Docker скачает свежую версию базового образа, а не использует локальный кэш. Флаг --no-cache отключает кэш слоёв, обеспечивая полную пересборку. В результате все пакеты ОС и зависимости будут обновлены до последних доступных версий.