Я пытаюсь настроить рой докеров.
Мне нужны мои узлы для связи через TLS.
Я создал сертификат для узла менеджера с расширеннымKeyUsage = serverAuth
Я настроил узел диспетчера со следующим daemon.json:
{
"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2376"],
"tlscacert": "/var/docker/ca.pem",
"tlscert": "/var/docker/server-cert.pem",
"tlskey": "/var/docker/server-key.pem",
"tlsverify": true
}
Чтобы проверить это, я создал сертификат клиента, который использовал его для подключения к docker api с моего ноутбука, и я могу успешно подключиться.
Теперь мне нужно добавить в рой один рабочий узел.
Я настроил его так же, как и узел менеджера; с аналогичным daemon.json. Я использовал SSL-ключ с extendedKeyUsage = serverAuth и доказал клиентское соединение так же, как и на управляющем узле.
Затем в диспетчере запустил docker swarm init
Чтобы присоединить рабочий узел к рою, я использую следующую команду: docker swarm join --token XXX dockman.myhost.com:2376
Но получаю ошибку:
Error response from daemon: rpc error: code = Unavailable desc = all SubConns are in TransientFailure, latest connection error: connection error: desc = "transport: authentication handshake failed: remote error: tls: bad certificate"
Я подумал, что могу проверить это дальше, попытавшись подключиться к API-интерфейсу докеров на управляющем узле из рабочего узла:
sudo docker --tlsverify --tlscacert=/var/docker/ca.pem --tlscert=./server-cert.pem --tlskey=./server-key.pem -H=127.0.0.1:2376 version
Результат:
Client: Docker Engine - Community
Version: 19.03.5
API version: 1.40
Go version: go1.12.12
Git commit: 633a0ea838
Built: Wed Nov 13 07:29:52 2019
OS/Arch: linux/amd64
Experimental: false
The server probably has client authentication (--tlsverify) enabled. Please check your TLS client certification settings: Get https://127.0.0.1:2376/v1.40/version: remote error: tls: bad certificate
Этот второй тест дал мне гораздо больше поводов для размышлений. Конечно, это не удастся, потому что я пытаюсь подключиться с помощью сертификата сервера, а не сертификата клиента, но разве это не то, что пытается сделать docker swarm join? Мне не имеет смысла помещать сертификат клиента в daemon.json. Я googledd сделал один сертификат как для сервера, так и для клиента, и это возможно, но кажется плохой практикой. Я бы подумал, что это было бы рассмотрено в руководстве, если бы это было необходимо.
На этом я застрял. Я не могу понять, какой сертификат требуется.
Я слежу https://github.com/docker/docker.github.io/blob/master/swarm/configure-tls.md Это описывает создание сертификатов, но не упоминает аутентификацию клиента или сервера вообще.
Я нашел документ, в котором говорится, что сертификаты должны быть клиентскими и серверными.
https://hub.docker.com/_/swarm/
Поэтому я переделал сертификат узла, чтобы он был и клиентским, и серверным. Теперь команда docker version работает при запуске с узла, но не при соединении с роем.
Вы путаете режим Swarm (docker swarm
и аналогичные интерфейсы командной строки) с классическим Swarm на основе контейнера (размещенным как контейнер на концентраторе докеров). Это два разных инструмента.
Для двух комплектов документации см:
Нет необходимости выполнять ручную настройку TLS в Swarm Mode, все это встроено, а порты для Swarm Mode отличаются от портов для сокета Docker API. Вы не хотите выставлять docker API в сети без уважительной причины (это частый источник взломов), и Swarm Mode не является причиной.
Следовательно, вам следует удалить -H
вариант для dockerd
вместе с любыми параметрами TLS. Тогда беги docker swarm init
на первом диспетчере, который сгенерирует учетные данные TLS и предоставит токен, содержащий хэш самоподписанных сертификатов. Затем другие менеджеры и рабочие проводят docker swarm join
чтобы сгенерировать клиентские сертификаты, подключитесь к менеджеру, проверьте хэш сертификатов менеджера из токена и аутентифицируйте себя для менеджера с секретной частью токена соединения.
Вышеупомянутое зашифрует плоскость управления между менеджерами и рабочими. Чтобы зашифровать данные, передаваемые по оверлейным сетям между рабочими, вам необходимо включить IPSec в оверлейных сетях, которые вы создаете:
docker network create --opt encrypted --driver overlay app-overlay-net
Документация по этой функции находится по адресу: https://docs.docker.com/v17.09/engine/userguide/networking/overlay-security-model/
Я был прав в том, что для работы все сертификаты должны быть сертификатами как клиента, так и сервера.
Затем я столкнулся с другими проблемами, главная из которых заключалась в том, что виртуальные машины на хосте, который я использую, запрещают использование порта 4789, поскольку он используется VMWare. Это порт пути данных по умолчанию, используемый для оверлейной сети.
Мне пришлось полностью удалить все узлы и менеджеры из роя (эффективно удалив его) и повторно подключить его, используя параметр data-path-port:
docker swarm init --data-path-port=7777
(Я также указал адрес рекламы в качестве ip для каждого узла, но я не думаю, что это было необходимо)
Конечно, все мои секреты докеров, конфигурация докеров и некоторые из моих сетей докеров были потеряны в этом процессе, и их пришлось воссоздавать.
Как только я закончил это и изменил брандмауэр, чтобы разрешить UDP-связь между узлами с использованием порта данных, все снова заработало.
Поскольку сеть роя зашифрована, я думаю, что все должно работать.