🐳 Как защитить TCP-сокет Docker с помощью TLS

Мануал

API Docker по умолчанию полностью незащищен, за исключением прав файловой системы на сокете Unix.

Вы должны настроить TLS при передаче Docker API по TCP, чтобы Docker Engine и ваши клиенты могли проверять личность друг друга.

В противном случае любой человек, имеющий доступ к TCP-порту, сможет просматривать ваши контейнеры Docker, запускать новые и выполнять действия с правами root в вашей системе.

Настроенный TLS потребует от клиентов предъявления действительного сертификата, подписанного удостоверяющим центром сервера.

Чтобы заставить его работать, необходимо создать SSL-сертификаты, а затем настроить Docker Engine на требование TLS-соединений.

Клиенты Docker CLI также должны быть настроены на ожидание TLS-сервера.

Эксплуатация TCP-сокета

Вы можете открыть TCP-сокет Docker, используя флаг -H для определения дополнительной конечной точки при запуске процесса dockerd.

Этот флаг можно повторить несколько раз; в данном примере будут доступны и сокет Unix, и сокет TCP:

/usr/bin/dockerd -H unix:///var/run/docker.sock -H tcp://0.0.0.0:2375

Порт 2375 обычно используется для незашифрованных соединений Docker.

Вместо него следует использовать порт 2376 после настройки TLS.

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

Добавьте переопределение в /etc/systemd/system/docker.service.d/override.conf, которое изменит строку ExecStart:

[Service]
ExecStart=/usr/bin/dockerd -H ...

Перезагрузите systemd, чтобы применить изменения:

sudo systemctl daemon-reload

Создание удостоверяющего центра

Начните с создания центра сертификации (CA) для вашей конфигурации TLS.

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

Используйте OpenSSL для генерации закрытого и открытого ключей CA на машине, на которой расположен ваш сервер Docker:

# Сгенерируйте закрытый ключ
openssl genrsa -aes256 -out ca-private.pem 4096

# Cгенерируйте открытый ключ из закрытого ключа
openssl req -new -x509 -days 365 -key ca-private.pem -sha256 -out ca-public.pem

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

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

Генерация ключа сервера и запроса на подписание сертификата

Далее создайте ключ сервера и запрос на подписание сертификата:

# Генерируем серверный ключ

# Сгенерируйте ключ сервера
openssl genrsa -out server-key.pem 4096

# Сгенерируйте запрос на подписание сертификата
openssl req -subj "/CN=itsecforu.ru" -sha256 -new -key server-key.pm -out request.csr

Запрос на подписание сертификата (CSR) содержит всю информацию, необходимую для создания подписанного сертификата.

Важно проверить правильность общего имени в CSR для вашего сервера.

Оно указано в поле CN как itsecforu.ru выше; вы должны установить его на полное доменное имя (FQDN) для вашего сервера.

Настройка расширений сертификата

Использование этого CSR разрешает подключение к серверу через его FQDN.

Вам необходимо указать расширения сертификата, если вы хотите добавить другой домен или использовать IP-адрес.

Для этого создайте файл расширений с полями subjectAltName и extendedKeyUsage:

echo subjectAltName = DNS:sub.itsecforu.ru;IP=192.168.0.1 >> extfile.cnf
echo extendedKeyUsage = serverAuth >> extFile.cnf

Этот пример дополнительно разрешает соединения через sub.itsecforu.ru и 192.168.0.1.

Генерация подписанного сертификата

Теперь вы готовы объединить все компоненты и сгенерировать подписанный сертификат:

openssl x509 -req -days 365 -sha256 \
    -in request.csr \
    -CA ca-public.pem \
    -CAkey ca-private.pem \
    -CAcreateserial \
    -extfile extfile.cnf \
    -out certificate.pem

Система принимает запрос на подписание сертификата, добавляет ваш файл расширения и использует ключи вашего УЦ для создания подписанного сертификата OpenSSL.

Для завершения процесса вам потребуется ввести парольную фразу УЦ.

Срок действия этого сертификата истекает через год.

Вы можете изменить флаг -days.

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

Генерация клиентского сертификата

Затем вы должны сгенерировать еще один сертификат для использования вашими клиентами Docker.

Он должен быть подписан тем же УЦ, что и сертификат сервера.

Используйте файл расширений с extendedKeyUsage = clientAuth, чтобы подготовить этот сертификат для использования в клиентском сценарии.

# Сгенерировать клиентский ключ
openssl genrsa -out client-key.pem 4096

# Создание запроса на подпись сертификата
openssl req -subj '/CN=client' -new -key client-key.pem -out client-request.csr

# Завершить подписание
echo extendedKeyUsage = clientAuth >> extfile-client.cnf
openssl x509 -req -days 365 -sha256 \
     -in client-request.csr \ 
     -CA ca-public.pem \
     -CAkey ca-private.pem \
     -CAcreateserial \
     -extfile extfile-client.cnf \
     -out client-certificate.pem

Подготовка к настройке Docker

Скопируйте файлы ca-public.pem, certificate.pem и server-key.pem в новый каталог, готовый к использованию в конфигурации Docker.

После этого скопируйте файлы ca-public.pem, client-certificate.pem и client-key.pem на машину, с которой вы будете подключаться.

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

Будьте осторожны, чтобы не потерять свои закрытые ключи, так как они не подлежат восстановлению.

Без них вы не сможете проверять сертификаты или генерировать обновления.

Настройка демона Docker

Теперь вы можете запустить демон Docker с флагами TLS, ссылающимися на сгенерированные вами сертификат и ключи.

Параметры –tlscacert, –tlscert и –tlskey указывают пути к соответствующим ресурсам OpenSSL, сгенерированным выше.

/usr/bin/dockerd \
    -H unix:///var/run/docker.sock \
    -H tcp://0.0.0.0:2376 \
    --tlsverify \
    --tlscacert=ca-public.pem \
    --tlscert=certificate.pem \
    --tlskey=server-key.pem

Добавление флага –tlsverify обеспечивает проверку TLS-соединений.

Клиенты без соответствующего сертификата будут заблокированы от доступа к TCP-сокету Docker.

Настройка клиента Docker

Активируйте TLS на клиенте, указав флаги TLS при использовании команды docker.

Вы также должны добавить флаг -H, чтобы указать адрес удаленного сокета Docker для подключения.

С точки зрения клиента, –tlsverify означает, что команда будет подключаться только к серверам с TLS-сертификатом, подписанным тем же УЦ, что и ее собственный.

docker \
    -H tcp://0.0.0.0:2376 \
    --tlsverify \
    --tlscacert=ca-public.pem \
    --tlscert=client-certificate.pem \
    --tlskey=client-key.pem \
    ps

Установка этих флагов при каждом использовании CLI быстро надоедает.

Если вы в основном будете работать с одним и тем же хостом, защищенным TLS, установите переменные окружения DOCKER_HOST и DOCKER_TLS_VERIFY в профиле оболочки.

Скопируйте файлы сертификатов в ca, cert и key внутри каталога ~/.docker.

Они соответствуют флагам Docker –tls и определяют сертификат по умолчанию для клиента.

export DOCKER_HOST=tcp://0.0.0.0:2376
export DOCKER_TLS_VERIFY=1

Вы можете упростить работу с несколькими хостами, использующими смесь локальных, удаленных, незащищенных и TLS-соединений, настроив контексты Docker.

Эта функция позволяет переключаться между целями с помощью команд Docker CLI.

Клиент Docker также поддерживает альтернативные режимы проверки.

Использование смеси флагов tls, tlscacert, tlscert, tlskey и tlsverify активирует различные уровни применения TLS.

Если установлен только tls, Docker будет аутентифицировать сервер, используя пул CA по умолчанию.

Добавление флагов tlscacert и tlsverify без клиентского ключа обеспечит использование сервером данного УЦ без каких-либо других проверок.

Если опустить tlscacert и tlsverify, но включить остальные три ключа, то сертификат клиента будет проверен без проверки подлинности сервера CA.

Заключение

Защита TCP-сокета Docker с помощью сертификатов TLS позволяет вам более безопасно использовать API, предотвращая подключения от неавторизованных клиентов.

Злоумышленники, сканирующие порты вашей сети, не смогут подключиться к Docker, что обеспечит вам уровень защиты, который предотвратит взлом вашей машины с привилегиями root-уровня.

см. также:

 

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