Начиная с 1 октября 2021 начал получать много сообщений от пользователей, которые получали ошибку «SSL certificate problem: certificate has expired» при попытке обновить компонент через админку.
Ниже попытаюсь вкратце объяснить, из-за чего возникла проблема и как ее решить.
Причина ошибки
30 сентября 2021 14:01:15 GMT закончился срок действия корневого сертификата IdenTrust DST Root CA X3.
Из-за этого стала невозможна проверка сертификатов, выпущенным центром сертификации Let’s Encrypt.
Эта проверка осуществляется при отправке запросов с вашего сервера на другой сервер через домен, который имеет SSL-сертификат Let’s Encrypt.
Потому все такие запросы, отправленные через cURL будут выдавать ошибку «SSL certificate problem: certificate has expired»
Исправление
Если вы получаете эту ошибку при попытке обновить компонент через админку Joomla, то Вам необходимо удалить просроченный сертификат из цепочки сертификатов, которые использует Joomla.
Откройте файл и найдите строку, содержащую «DST Root CA X3». удалите ее и все последующий блок (это и есть просроченный сертификат):
Сохраните файл на сервер.
Если же в Вашем файле сертификаты не подписаны, то найдите нужный по последним 5 буквам — CNTUQ.
Если же Вы столкнулись с ошибкой «SSL certificate problem: certificate has expired» в другом месте, то напишите в тех. поддержку своего хостинга обращение следующего содержания:
«При попытке отправки запросов через cURL получаю ошибку SSL certificate problem: certificate has expired. Удалите, пожалуйста, просроченный сертификат DST Root CA X3 из цепочки сертификатов, которую использует OpenSSL»
Что делать, если протухли сертификаты и кластер превратился в тыкву?
Время на прочтение
Если в ответ на команду kubectl get pod вы получаете:
Unable to connect to the server: x509: certificate has expired or is not yet valid
то, скорее всего, прошел год, у сертификатов вашего kubernetes закончился срок действия, компоненты кластера перестали их использовать, взаимодействие между ними прекратилось и ваш кластер превратился в тыкву.
Что же делать и как восстановить кластер?
Для начала нам надо понимать, где находятся сертификаты, которые необходимо обновить.
Посмотреть на срок действия, кому выписан и кем подписан сертификат, можно с помощью вот этого небольшого скрипта shcert
Еще есть сертификаты, которые используют kubelet на рабочих узлах для аутентификации в API. Если для добавления узлов в кластер вы использовали kubeadm join, то, скорее всего, узел был подключен по процедуре TLS bootstrapping и в таком случае kubelet умеет обновлять свой сертификат автоматически, если ему задана опция —rotate-certificates. В последних версиях kubernetes эта опция уже включена по умолчанию.
Проверить, что узел подключен по процедуре TLS bootstrap достаточно просто — в этом случае в файле /etc/kubernetes/kubelet.conf в поле client-certificate обычно указан файл /var/lib/kubelet/pki/kubelet-client-current.pem, который является симлинком на текущий сертификат.
Посмотреть сроки действия этого сертификата можно так же, с помощью скрипта shcert
Возвращаемся к проблеме обновления сертификатов.
Если вы ставили кластер с помощью kubeadm, то у меня для вас хорошие новости. Начиная с версии 1.15 kubeadm умеет обновлять почти все сертификаты control plane одной командой
kubeadm alpha certs renew all
Эта команда обновит все сертификаты в каталоге /etc/kubernetes, даже если они уже закончились и все сломалось.
Не будет обновлен только сертификат kubelet — это тот, который лежит в файле /etc/kubernetes/kubelet.conf!
Update: kubeadm, начиная с версии 1.17, включает на всех узлах (даже на первом мастере, где делался kubeadm init) автообновление сертификата кублета. Проверить очень просто — в /etc/kubernetes/kubelet.conf в поле клиентского сертификата будет указан путь к файлу /var/lib/kubelet/pki/kubelet-client-current.pem
И конечно же, после обновления сертификатов надо перезапустить все компоненты control plane, перезагрузив узел целиком или остановив контейнеры с etcd, api, controller-manager и scheduler командой docker stop, и затем отрестартить kubelet systemctl restart kubelet.
Если ваш кластер старой версии: например 1.13 или меньше. То просто обновить kubeadm до версии 1.15, командой типа yum install kubeadm-1.15.0, не получится, так как он тянет за собой по зависимостями kubelet и kubernetes-cni, что может вызывать проблемы, так как работоспособность компонентов кластера, различающихся по версиям более чем на одну ступень, не гарантируется. Самый простой выход из данной ситуации — это установить kubeadm на какой-нибудь другой машине, взять бинарный файл /usr/bin/kubeadm, скопировать на мастер-узлы умершего кластера и использовать его только для обновления сертификатов. А уже после оживления кластера обновить его пошагово штатными способами, устанавливая каждый раз kubeadm на одну версию новее.
curl -L -o /tmp/kubeadm https://dl.k8s.io/release/v1.17.4/bin/linux/amd64/kubeadm
И наконец, с версии 1.16 kubeadm научился-таки продлевать все-все сертификаты при обновлении кластера командой kubeadm upgrade. Так что если вы регулярно обновляете свой кластер, не реже одного раза в год, ваши сертификаты всегда будут действительны.
А вот если кластер установлен не с помощью kubeadm, то тогда придется взять в руки openssl и обновлять все сертификаты в индивидуальном порядке.
Проблем добавляет то, что в сертификатах содержатся расширенные поля, и разные инструменты установки кластера могут добавлять свой набор полей. Причем названия этих полей в конфигурации openssl и в выводе содержимого сертификата коррелируют, но слабо. Надо гуглить и подбирать.
Я приведу пример конфигурации для openssl, в отдельных секциях которого описываются расширенные атрибуты, свои для каждого типа сертификата. На соответствующую секцию будем ссылаться при создании и подписывании csr. Эта конфигурация использовалась для оживления кластера, установленного год назад ранчером.
Актуальные атрибуты и дополнительные имена в сертификате можно посмотреть с помощью команды
openssl x509 -in cert.crt -text
При продлении сертификата для API сервера у меня возникала проблема: обновленный сертификат не работал. Решением стала выписка сертификата, который был действителен на 1 год в прошлом.
В openssl нельзя простой командой выпустить сертификат, действительный в прошлом, в коде жестко указано, что сертификат действует только с текущего момента. Но можно локально переместиться в прошлое с помощью библиотеки libfaketime
Выпускаем продленные сертификаты по следующему алгоритму:
Создаем CSR по существующему сертификату, указываем нужный раздел со списком расширенных аттрибутов в файле конфигурации:
openssl x509 -x509toreq -in «node.cert» -out «node.csr» -signkey «node.key» -extfile «openssl.cnf» -extensions client
Подписываем его соответствующим корневым сертификатом, смещая время на 1 год назад и указывая нужный раздел со списком расширенных аттрибутов в файле конфигурации
LD_PRELOAD=/usr/lib64/faketime/libfaketime.so.1 FAKETIME=»-365d» openssl x509 -req -days 36500 -in «node.csr» -CA «kube-ca.pem» -CAkey «kube-ca-key.pem» -CAcreateserial -out «node.new.cert» -extfile «openssl.cnf» -extensions client
Проверяем атрибуты и перезапускаем компоненты control plane.
Сергей Бондарев,
преподаватель Слёрма
slurm.io