We detected you are likely not from a Russian-speaking region. Would you like to switch to the international version of the site?

К списку статей

Security-by-design: автоматическая проверка зависимостей Composer и Poetry с Dependabot и Snyk в CI, а также runtime-hardening контейнеров

Security-by-design — это не разовая «галочка» в чек-листе, а управляемый жизненный цикл безопасности: от контроля зависимостей до защиты среды исполнения. В реальных проектах на PHP и Python риски чаще всего рождаются не в собственном коде, а в цепочках поставки (supply chain): уязвимые библиотеки, подмены артефактов, устаревшие версии и незафиксированные зависимости.

Ниже — практическая архитектура для проектов с Composer (PHP) и Poetry (Python), где в CI/PR включены Dependabot и Snyk, а также добавлено runtime-hardening контейнеров. Подход построен так, чтобы обеспечивать управляемость, трассируемость решений и соответствовать актуальным требованиям РФ к защите информации и безопасной разработке.

Правовые ориентиры РФ и как перевести их в технические требования

В РФ требования к защите информации закрепляются несколькими уровнями нормативных актов и практик. На практике компании обычно ориентируются на:

  • общие требования к обеспечению безопасности информации при обработке данных;
  • требования к управлению доступами, журналированию, контролю целостности и обновлениям;
  • организационно-технические меры безопасной разработки и эксплуатации.

Технически это переводится в конкретные инженерные контролы:

  • Контроль компонентов: фиксация версий, проверка зависимостей на уязвимости до попадания в релиз.
  • Трассируемость: ведение истории изменений (PR), валидация на CI, отчеты сканеров.
  • Минимизация привилегий: runtime-hardening контейнеров, запрет небезопасных возможностей.
  • Наблюдаемость: логи сборки/сканирования, контроль артефактов.

Отдельно важно: автоматизация не отменяет необходимости внутренней политики безопасной разработки. Сканирование и принудительные правила (fail/allow) должны быть оформлены как часть процессов команды (например, через правила в репозиториях и требования к PR).

Целевая архитектура: supply chain от PR до релиза

Рекомендуемый конвейер:

  1. Dependabot генерирует PR на обновление зависимостей для Composer/Poetry.
  2. CI валидирует сборку и запускает сканирование уязвимостей зависимостей (Snyk) + проверяет SBOM/целостность.
  3. Policy gate: правила блокируют мердж, если обнаружены уязвимости выше допустимого порога или нет сопровождения (например, нет обоснования).
  4. Артефакт: собирается неизменяемый образ/пакет. Желательно хранить SBOM и результаты сканирования вместе с артефактами релиза.
  5. Runtime-hardening: контейнер запускается с ограничениями, минимальными правами и безопасными настройками.

Composer: автоматическая проверка зависимостей

Для PHP-проектов используйте зафиксированные зависимости и надежную структуру репозитория:

  • composer.json и composer.lock должны быть в Git.
  • в CI выполнять composer install строго по lock-файлу (обычно это --no-interaction --prefer-dist + режим без обновлений).

Сканирование уязвимостей Composer-экосистемы удобнее держать в одном месте — через Snyk, а Dependabot использовать для своевременного создания PR.

Poetry: автоматическая проверка зависимостей

Для Python-проектов аналогично фиксируйте зависимости:

  • pyproject.toml и poetry.lock должны быть в репозитории.
  • в CI устанавливать зависимости из lock-файла (не разрешая обновления на лету).

Dependabot с Poetry-проектами создает PR при обновлениях, а Snyk выполняет проверку уязвимостей по lock-файлу/проекту.

Dependabot: настройка для Composer и Poetry

Dependabot нацелен на поддержание актуальности зависимостей и снижение «технического долга» по безопасности. Его задача — создавать PR, а не принимать решения об исправлениях.

Пример .github/dependabot.yml (универсально, под нужды репозитория):

version: 2
updates:
  - package-ecosystem: "composer"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
    target-branch: "master"
  - package-ecosystem: "pip"
    directory: "/"
    schedule:
      interval: "weekly"
    open-pull-requests-limit: 10
    target-branch: "master"

Комментарий по Poetry: Dependabot формально опирается на стандартные манифесты. Если в репозитории используется poetry.lock, на практике часто применяют экосистему, соответствующую Python-пакетам (pip) и проверяют, что Dependabot корректно читает lock/манифесты. В ряде случаев целесообразно дополнить настройку запуском Poetry-проверок в CI и сканированием в Snyk, чтобы гарантировать, что фактические зависимости будут оценены независимо от поведения Dependabot.

Snyk: сканирование зависимостей в CI

Ключевой принцип: сканируйте не «теоретический список библиотек», а то, что реально фиксировано в lock-файлах и может быть установлено в build-среде.

Общие требования к CI-gating

  • Fail build при критичных/высоких уязвимостях (порог задается политикой).
  • Отчетность: публикуйте отчеты сканирования как артефакты CI.
  • Проверка только для PR + повтор в релизном пайплайне.

Ниже — пример для GitHub Actions. Аналогично адаптируется под GitLab CI/другие системы.

CI: пример workflow для PHP (Composer + Snyk)

# .github/workflows/security-composer.yml
name: Security Composer

on:
  pull_request:
  push:
    branches: [ "master" ]

jobs:
  composer-security:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up PHP
        uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
          tools: composer

      - name: Install dependencies
        run: composer install --no-interaction --prefer-dist

      - name: Snyk test (Composer)
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        run: |
          snyk auth $SNYK_TOKEN
          snyk test --file=composer.lock --all-projects --severity-threshold=high --fail-on=upgradable

Пояснения:

  • --file=composer.lock: сканируем точную картину зависимостей.
  • --severity-threshold: порог блокировки.
  • --fail-on — поведение на обнаружениях, требует подстройки под вашу политику.

CI: пример workflow для Python (Poetry + Snyk)

# .github/workflows/security-poetry.yml
name: Security Poetry

on:
  pull_request:
  push:
    branches: [ "master" ]

jobs:
  poetry-security:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Set up Python
        uses: actions/setup-python@v5
        with:
          python-version: '3.11'

      - name: Install Poetry
        run: pip install --no-cache-dir poetry

      - name: Install dependencies (from lock)
        run: |
          poetry config virtualenvs.create false
          poetry install --no-interaction --no-root

      - name: Snyk test (Python)
        env:
          SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
        run: |
          pip install --no-cache-dir snyk
          snyk auth $SNYK_TOKEN
          # Snyk CLI для Python-проектов часто использует pyproject/lock.
          # Если потребуется уточнение под вашу структуру — закрепите конкретный манифест:
          snyk test --file=requirements.txt || true
          # Вариант для строгой картины: экспортируйте requirements из Poetry:
          poetry export -f requirements.txt --without-hashes -o requirements.txt
          snyk test --file=requirements.txt --severity-threshold=high --fail-on=upgradable

Заметка по практике: чтобы гарантировать единообразие, полезно экспортировать зависимости из Poetry в requirements.txt и сканировать именно его в Snyk. Тогда результат будет предсказуем даже если у Snyk есть нюансы интерпретации lock/pyproject.

SBOM: формирование и встраивание в контроль релизов

Для усиления контроля цепочки поставки полезно генерировать SBOM (Software Bill of Materials). На уровне политики это помогает доказуемо ответить на вопросы:

  • какие компоненты были в релизе;
  • какие версии использовались;
  • какие сканы применялись и когда.

Один из практичных вариантов — использовать CycloneDX генерацию в CI. Пример (идея, под конкретные инструменты адаптируйте под ваши технологии):

# SBOM (идея): генерация CycloneDX
# Для Python: можно использовать cyclonedx-bom
pip install --no-cache-dir cyclonedx-bom
cyclonedx-bom -o sbom-python.json -r requirements.txt

# Для PHP: можно подключить соответствующий генератор SBOM в CI
# (выбор зависит от вашего стека инструментов)

Важное требование для зрелой безопасности: SBOM должен связываться с артефактами релиза и храниться с результатами Snyk/CI-сканирования.

Управление обновлениями: как правильно разрешать уязвимости

В реальных проектах встречаются ситуации, когда обновление зависимостей невозможно немедленно (несовместимость API, регрессии, требования заказчика). Поэтому заранее определите правила исключений:

  • Разрешения на мердж только при наличии описания риска (issue ссылка, план миграции).
  • Тайм-бокс для исключений (например, максимум N дней для критичных уязвимостей).
  • Повторная проверка при изменениях релевантных файлов (lock-файлы/манифесты).

Технически это реализуется через настройки Snyk (политики severity, suppression) и через требования к PR (шаблоны, mandatory checks).

Runtime-hardening контейнеров: защита среды исполнения

Даже при хорошей защите зависимостей остается риск эксплуатации через уязвимости в runtime-коде, неверные настройки сервиса, утечки секретов или escalation привилегий. Поэтому контейнеры должны быть защищены по принципу наименьших привилегий.

Практики Docker/Kubernetes hardening

  • Непривилегированный пользователь: не запускать контейнер от root.
  • read-only root filesystem + отдельные writable директории.
  • drop capabilities, не добавлять лишние привилегии.
  • Запрет privilege escalation (например, allowPrivilegeEscalation=false).
  • Ограничение ресурсов (CPU/memory limits) для снижения impact при отказе.
  • Секреты — через secrets manager/встроенные механизмы, исключить из образа.
  • Сетевая сегментация: минимальные порты/ingress, ограничение egress при возможности.

Пример Dockerfile: минимизация поверхностной атаки

# Пример для PHP (идея; адаптируйте под ваш проект)
FROM php:8.2-fpm-alpine

# Создаем non-root пользователя
RUN addgroup -S app && adduser -S app -G app
WORKDIR /var/www/app

# Копирование без лишних прав
COPY --chown=app:app . /var/www/app

# Убираем возможность записи в корень (в Docker это частично, лучше на уровне runtime)
USER app

# Минимизируем зависимости базового образа — выбирайте slim/alpine обоснованно
# CMD остается стандартным
CMD ["php-fpm", "-F"]

Для Python аналогично: использовать slim-образы, создавать non-root пользователя и избегать установки лишних build-утилит в финальном stage (multi-stage build).

Пример Kubernetes SecurityContext

apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  template:
    spec:
      containers:
        - name: myapp
          image: myapp:1.0.0
          securityContext:
            runAsNonRoot: true
            runAsUser: 10001
            readOnlyRootFilesystem: true
            allowPrivilegeEscalation: false
            capabilities:
              drop: ["ALL"]
          volumeMounts:
            - name: tmp
              mountPath: /tmp
              readOnly: false
      volumes:
        - name: tmp
          emptyDir: {}

Дополнительно (в зависимости от кластера):

  • PodSecurity admission (baseline/restricted);
  • NetworkPolicy;
  • ограничение serviceAccount, RBAC по принципу минимально необходимых прав.

Связь CI-сканирования и runtime-hardening в единую систему

На практике зрелая система безопасности выглядит так:

  • Dependabot делает обновления зависимостей и инициирует PR.
  • Snyk в CI оценивает уязвимости и блокирует рискованные мерджи.
  • SBOM сохраняется и привязывается к релизному артефакту.
  • Контейнеры запускаются с ограничениями, которые исключают типовые сценарии компрометации.
  • Все решения документируются в репозитории (PR, отчеты CI), что повышает управляемость и аудитопригодность.

Рекомендуемая матрица контроля (коротко)

УровеньЧто делаемЧем подтверждаем
PRDependabot обновляет зависимостиPR в GitHub/GitLab
CIСборка + Snyk сканирование по lock/requirementsЛоги CI, отчеты Snyk, статус checks
РелизФормирование SBOM, сохранение артефактовSBOM-файл + результат сканов в хранилище релиза
RuntimeNon-root, readOnly FS, drop capabilities, limitsKubernetes/Docker конфигурация, admission policies

Типовые ошибки и как их избежать

  • Сканирование не того файла: например, требования без фиксации. Решение — сканировать lock/экспорт из lock.
  • Разрешение мерджей “по зеленому билду” без checks. Решение — mandatory CI checks и fail on severity.
  • Отсутствие исключений в политике: “можно ли пропустить?” — должно быть регламентировано.
  • Runtime не защищен: даже идеальные зависимости не исключают неверные настройки контейнеров.

Заключение

Security-by-design для Composer/Poetry — это связка автоматизации обновлений (Dependabot), проверки уязвимостей (Snyk), доказуемого контроля поставки (SBOM) и технической защиты среды исполнения (runtime-hardening контейнеров). Такой подход снижает риски компрометации, ускоряет исправления и делает процесс аудита и управления безопасностью существенно проще.

Если вы хотите внедрить это в действующий CI/CD пайплайн и контейнерный контур — команда РыбинскЛАБ поможет спроектировать архитектуру, настроить политики безопасности, интегрировать Snyk/Dependabot и выполнить hardening контейнеров под ваш инфраструктурный ландшафт.

Обратитесь в РыбинскЛАБ — предлагаем услуги по разработке и внедрению безопасных CI/CD практик.

Материал подготовлен и отредактирован для практического применения. Перед внедрением в продакшен проверьте код и команды на своём окружении.

Поделиться материалом

Нужна сложная backend-разработка?

Проектирование архитектуры, PHP/Python backend, интеграции API, боты, автоматизация и оптимизация существующих систем.

Обсудить проект
Поддержать проект