🐳 Обновление патчей безопасности в контейнерах Docker

Мануал

Контейнеры неизменяемы, что означает, что их не следует исправлять на месте, как это делается для виртуальных машин или физических серверов.

Вместо этого обновление контейнера требует повторного развертывания обновленного контейнера и уничтожения старого.

Проблемы, связанные с исправлением контейнеров

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

Контейнеры в этом отношении ничем не отличаются – многие команды опасаются уничтожать работающий контейнер, который отлично функционирует.

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

Кроме того, я пока не нашел надежного способа выявления контейнеров с уязвимым и устаревшим программным обеспечением для проведения цикла исправлений.

С другой стороны, команды, использующие Docker в полном цикле DevOps, скорее всего, будут постоянно выпускать последние исправления безопасности, что исключает эту проблему.

Давайте рассмотрим обе практики – выполнение правильного цикла DevOps и некоторые потенциальные инструменты для мониторинга!

Команды DevOps устанавливают исправления при каждом развертывании

Если ваши команды разработчиков практикуют DevOps, используют автоматизированные решения интеграции и развертывания и выпускают производственные изменения не реже, чем цикл патчей, то полное обновление контейнеров может быть включено в процесс выпуска без дополнительных усилий.

Все, что нужно, это убедиться, что ваш конвейер CI/CD перестраивает образ развертывания при каждой сборке.

Ниже я покажу очень простой пример с использованием Jenkins.

Автоматическое обновление контейнеров с помощью Jenkins

Давайте создадим простой пример, чтобы увидеть, как это работает.

Если вы еще не знакомы с Jenkins, с этого легко начать.

Сначала мы создадим и запустим контейнер Jenkins, а затем обновим его для работы с Docker.

Создайте следующий Dockerfile в новом каталоге:

# Начните с образа Jenkins
FROM    jenkins/jenkins:lts

# Установите Docker в наш образ
USER    root
RUN     apt update
RUN     apt-get install -y apt-transport-https ca-certificates wget software-properties-common
RUN     wget https://download.docker.com/linux/debian/gpg
RUN     apt-key add gpg
RUN     echo "deb https://download.docker.com/linux/debian stretch stable" > /etc/apt/sources.list.d/docker.list
RUN     apt update
RUN     apt-get install -y docker-ce

# Jenkins запускается под пользователем Jenkins, и ему потребуется 
# доступ к unix-сокету docker, который принадлежит root. 
# Обычно он должен иметь группу docker, но здесь он 
# принадлежит root:root. Мы можем изменить это, но для целей тестирования 
# я просто добавлю пользователя jenkins в группу root.
RUN     usermod -G root -a jenkins

# Switch back to jenkins user
USER    jenkins

Мы должны сделать небольшое изменение, чтобы дать пользователю jenkins доступ к сокету docker (который мы будем монтировать из хост-системы).

Давать групповой root пользователю jenkins – это не то, что я бы хотел делать, но для нашего тестового примера вполне подойдет.

Теперь давайте запустим этот контейнер:

$ docker build . -t jenkins_test
$ mkdir -p ~/jenkins_test
$ docker run \
    -p 8080:8080 \
    -p 50000:50000 \
    --name jenkins \
    --privileged=true \
    -v /home/nullsweep/jenkins_test:/var/jenkins_home \
    -v /var/run/docker.sock:/var/run/docker.sock \
    jenkins_test

Обратите внимание на несколько вещей, которые мы делаем с этим контейнером, чтобы убедиться, что он может создавать и запускать образы docker:

  • Запуск в привилегированном режиме, чтобы позволить ему запускать контейнеры братьев и сестер
  • Монтирование локального тома для тестовых конфигурационных файлов
  • Монтирование сокета docker, что дает контейнеру jenkins контроль над установкой docker на хосте.

Теперь войдите на localhost:8080 и выполните шаги по настройке Jenkins и создайте пайплайн под названием test.

Мы будем использовать это имя позже для размещения файлов проекта. В пайплайн добавьте простой скрипт в раздел “Pipeline”, тип – “Pipeline script”.

node {
    
    stage('Build image') {
        sh "docker build -t test --pull ."
    }
}

Обратите внимание, что здесь используется команда shell для сборки образа, а не плагин docker.

При использовании плагина можно получить сообщения, связанные с ошибкой Jenkins 31507 java.io.IOException: Cannot retrieve .Id from ‘docker inspect base AS final’.

Замена docker на команду оболочки исправила ситуацию.

# test в приведенном ниже пути - это имя пайплайна, настроенного в Jenkins
$ cd ~/jenkins_test/workspace/test
$ cat Dockerfile
FROM   nullsweep/test:latest
CMD    sh echo "I ran!"

Вернувшись в Jenkins, запустите сборку, нажав “Build Now”, и вы должны увидеть успешный пайлайн.

Пайплайн запускает скрипт оболочки для вызова docker и передает параметр –pull для принудительной перекомпоновки базовых образов.

Теперь у нас есть зачатки пайплайна, который будет отправлять последние исправления для ОС с каждым выпуском кода (при условии, что базовые образы поддерживаются в актуальном состоянии в своих репозиториях).

Никаких больше переносов патчей!

Мониторинг с помощью WatchTower

Что делать, если вы не выпускаете код хотя бы раз в месяц?

Это часто случается с контейнерами, такими как контейнеры баз данных или полностью готовые контейнеры приложений, такие как контейнеры WordPress.

В этих случаях мы можем рассмотреть возможность использования такого инструмента, как WatchTower, для мониторинга и автоматического обновления наших контейнеров.

Обзор WatchTower

WatchTower – это сопровождающий контейнер, который отслеживает все запущенные контейнеры на хосте на предмет наличия обновлений в их образе.

Если обновление найдено, он может автоматически остановить, обновить и перезапустить контейнер.

Он имеет достаточное количество опций для мониторинга, удаленного мониторинга, чатопсов и уведомлений.

Пример WatchTower

Мы создадим пользовательский базовый образ с файлом версии:

FROM    alpine:latest

RUN     echo "1.0" >> version.txt
CMD     echo "Version: " && cat version.txt

Мы разместим его в публичном репозитории docker под названием watch_base.

$ docker build . -t nullsweep/watch_base
$ docker push nullsweep/watch_base

И мы укажем его в новом образе, который мы хотим развернуть в качестве нашего приложения:

FROM    nullsweep/watch_base

RUN     printf "while [ 1 ] \n \
           do \n \
               echo 'Version: ' \n \
               cat version.txt \n \
               sleep 5s \n \
           done \n" >> version.sh
CMD     source version.sh

Этот образ создает скрипт оболочки, который выводитт файл version.txt каждые 5 секунд.

Давайте разместим его в новом публичном репозитории.

$ docker build . -t nullsweep/watch
$ docker push nullsweep/watch
# В первом терминале: скачайте и запустите контейнер для контроля:
$ docker pull nullsweep/watch
$ docker run --name watch nullsweep/watch:latest
Version:
1.0

# Во втором терминале запустите WatchTower:
$ docker pull v2tec/watchtower
$ docker run \
    -d \
    --name watchtower \
    -v /var/run/docker.sock:/var/run/docker.sock \
    v2tec/watchtower -i 5 --debug watch

Система запустит watchtower с парой пользовательских флагов: мониторинг только нашего собственного контейнера и проверка обновлений образа каждые 5 секунд вместо стандартных 5 минут.

В любой момент вы можете просмотреть журналы watchtower, выполнив команду:

$ docker logs watchtower

Вернувшись за пределы виртуальной машины, вы можете выполнить два теста:

  • Обновите образ watch_base, чтобы увеличить номер версии, и отправьте его в репозиторий. WatchTower не заметит этого изменения.
  • Пересоберите образ приложения (тот, который я назвал watch выше) и отправьте его в репозиторий. WatchTower вытащит его и перезапустит виртуальную машину с новой версией. Теперь у нас есть исправленный контейнер!

Заключение

Контейнеры создают некоторые уникальные проблемы, связанные с исправлениями, но могут действительно упростить работу по обеспечению безопасности, если их поместить в конвейер CI/CD, который автоматически собирает новейшие контейнеры.

Хотя я считаю, что на данный момент у нас нет подходящего решения для мониторинга исправлений в контейнерах, WatchTower – это кандидат, который со временем может развиваться в этом направлении.

 

Добавить комментарий