Может ли самозаверяющий сертификат защитить несколько CN / FQDN?

Это немного глупая установка, но вот что я сейчас вижу:

  • Я изучаю Kubernetes
  • Я хочу отправить собственный код в свой кластер Kubernetes, это означает, что код должен быть доступен в виде образа Docker, доступного из некоторого репозитория Docker (по умолчанию - Docker Hub)
  • Хотя я готов заплатить за Docker Hub, если мне нужно (хотя я бы предпочел этого избежать), у меня есть опасения по поводу размещения моего пользовательского кода в сторонней службе. Неожиданные ограничения скорости , нарушения безопасности, внезапные изменения ToS и т. д.
  • Для этого я использую собственный реестр Docker в кластере Kubernetes.
  • Я не хочу настраивать клиенты Docker, работающие на узлах Kubernetes, на доверие небезопасным (HTTP) реестрам Docker. Если я решу извлечь какие-либо изображения из внешнего реестра (например, общедоступные образы, такие как nginx, я могу извлечь из Docker Hub вместо локального размещения), тогда я не хочу быть уязвимым для атак MITM, заменяя образ
  • В конечном итоге у меня будет инструмент сборки в кластере (Jenkins или другой), который вытащит мой код из git, создаст образ и отправит его во внутренний реестр. Тогда все узлы, извлеченные из реестра, будут жить в кластере. Поскольку реестру никогда не нужно получать изображения из источников за пределами кластера или доставлять их в источники за пределами кластера, реестр не нуждается в службе NodePort, но вместо этого может быть службой ClusterIP .... в конечном итоге
  • Пока у меня не будет готовой окончательной настройки, я создаю образы на своем локальном компьютере и хочу отправить их в реестр (из Интернета).
  • Поскольку я не планирую делать реестр доступным из внешнего мира (в конечном итоге), я не могу использовать Let's Encrypt для создания для него действительных сертификатов (даже если бы я делал свой реестр Docker доступным для внешнего мира, Я все равно не могу использовать Let's Encrypt, не написав дополнительный код для использования certbot или что-то)

Я планирую следовать примеру из этот пост в StackOverflow: сгенерируйте самозаверяющий сертификат, а затем запустите реестр Docker, используя этот сертификат. Затем используйте DaemonSet, чтобы сделать этот сертификат доверенным на всех узлах кластера.

Теперь, когда у вас есть настройка, вот суть моей проблемы: в моем кластере к моему реестру Docker можно получить доступ через простое имя хоста (например, docker-registry), но за пределами моего кластера мне нужно либо получить доступ к нему через IP-адрес узла адрес или доменное имя, указывающее на узел или балансировщик нагрузки.

При создании моего самозаверяющего сертификата меня попросили предоставить CN / FQDN для сертификата. Я ввожу docker-registry - внутреннее имя хоста, которое я планирую использовать. Затем я попытался получить доступ к своему реестру локально, чтобы отправить в него изображение:

> docker pull ubuntu
> docker tag ubuntu example.com:5000/my-ubuntu
> docker push example.com:5000/my-ubuntu
The push refers to repository [example.com:5000/my-ubuntu]
Get https://example.com:5000/v2/: x509: certificate is valid for docker-registry, not example.com

Я могу сгенерировать сертификат для example.com вместо docker-registry, однако я беспокоюсь, что у меня возникнут проблемы с настройкой службы или подключением к моему реестру из моего кластера, если я предоставлю свой внешний домен, подобный этому, вместо внутреннего имени хоста.

Вот почему мне интересно, могу ли я просто сказать, что мой самозаверяющий сертификат применяется к обоим example.com и docker-registry. Если нет, то два других приемлемых решения:

  • Могу ли я сказать клиенту Docker не проверять имя хоста и просто неявно доверять сертификату?
  • Могу ли я указать реестру Docker доставить один из двух разных сертификатов в зависимости от имени хоста, используемого для доступа к нему?

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


person stevendesu    schedule 01.11.2020    source источник


Ответы (1)


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

Например, вы можете настроить что-то вроде

{
    "insecure-registries" : [ "10.10.10.10:5000" ]
}

и единственный IP-адрес, к которому ваши демоны Docker будут обращаться без TLS, - это адрес этого хоста и номер порта.

Если вы не хотите этого делать, вам необходимо получить доверенный сертификат TLS. Проблема, о которой вы упомянули о наличии нескольких имен на сертификат, обычно решается с помощью поля Альтернативное имя субъекта в сертификат. (действительно, Kubernetes довольно часто использует эту функцию).

person Rory McCune    schedule 01.11.2020
comment
Знание того, что я могу указать хосты, которым доверять, успокаивает мои опасения по поводу небезопасного реестра, а альтернативное имя субъекта звучит так, как будто оно фактически предоставит исходное решение, которое я искал. Я могу немного поиграть с полем SAN только в образовательных целях, но в конечном итоге я рассмотрю возможность изменения своего DaemonSet, чтобы разрешить небезопасные реестры вместо того, чтобы доверять самозаверяющему сертификату - person stevendesu; 02.11.2020
comment
У меня возникли проблемы с тем, чтобы параметр небезопасных реестров работал нормально с автоматическим масштабированием Kubernetes (у меня нет хорошего способа разместить этот daemon.json файл на вновь созданных узлах). Однако с помощью SAN мне удалось запустить реестр и отправить в него образ. Так что это лучший вариант. Однако теперь у меня возникла новая проблема с именами хостов служб. К сервису ClusterIP нельзя получить доступ по имени на этапе ImagePull, поскольку Kubernetes выполняет извлечение изображения, а не под. - person stevendesu; 03.11.2020