Kubeadm: использовать подписанные сертификаты обслуживания kubelet

Созданный на 9 нояб. 2018  ·  38Комментарии  ·  Источник: kubernetes/kubeadm

Это ОТЧЕТ ОБ ОШИБКЕ или ЗАПРОС О ФУНКЦИОНИРОВАНИИ?

/ добрый баг

Открытие стороны kubeadm для этой проблемы на сервере метрик

Версии

$ kubeadm version
kubeadm version: &version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.1", GitCommit:"4ed3216f3ec431b140b1d899130a69fc671678f4", GitTreeState:"clean", BuildDate:"2018-10-05T16:43:08Z", GoVersion:"go1.10.4", Compiler:"gc", Platform:"linux/amd64"}

Окружающая среда :

  • Версия Kubernetes (используйте kubectl version ):
$ kubectl version
Client Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.1", GitCommit:"4ed3216f3ec431b140b1d899130a69fc671678f4", GitTreeState:"clean", BuildDate:"2018-10-05T16:46:06Z", GoVersion:"go1.10.4", Compiler:"gc", Platform:"linux/amd64"}
Server Version: version.Info{Major:"1", Minor:"12", GitVersion:"v1.12.1", GitCommit:"4ed3216f3ec431b140b1d899130a69fc671678f4", GitTreeState:"clean", BuildDate:"2018-10-05T16:36:14Z", GoVersion:"go1.10.4", Compiler:"gc", Platform:"linux/amd64"}
  • Облачный провайдер или конфигурация оборудования :
    Любой
  • ОС (например, из / etc / os-release):
    Любой
  • Ядро (например, uname -a ):
$ uname -a
Linux ip-172-31-1-118 4.15.0-1023-aws #23-Ubuntu SMP Mon Sep 24 16:31:06 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux
  • Другие :

Что случилось?

kubeadm создает сертификаты под /var/lib/kubelet/pki/kubelet.* подписанные другим CA, отличным от того, который находится под /etc/kubernetes/pki/ca.pem

Чего вы ожидали?

В результате некоторые приложения, такие как сервер метрик, не могут собирать статистику с защищенного кублета, потому что у кублета есть сертификаты, подписанные другим CA, отличным от мастера (ов) K8s.

Пример ошибки:

E1108 23:49:32.090084       1 manager.go:102] unable to fully collect metrics: [unable to fully scrape metrics from source kubelet_summary:ip-x-x-x-x: unable to fetch metrics from Kubelet ip-x-x-x-x (ip-x-x-x-x): Get https://ip-x-x-x-x:10250/stats/summary/: x509: certificate signed by unknown authority, unable to fully scrape metrics from source kubelet_summary:ip-x-x-x-x: unable to fetch metrics from Kubelet ip-x-x-x-x (ip-x-x-x-x): Get https://ip-x-x-x-x:10250/stats/summary/: x509: certificate is valid for x.x.x.x not ip-x-x-x-x]

Как это воспроизвести (максимально минимально и точно)?

Установите сервер метрик при запуске:

$ kubectl -n журналы системы kube

Что еще нам нужно знать?

Еще немного фона здесь

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


редактировать: neolit123

проблема здесь в том, что обслуживающий сертификат по умолчанию самозаверяющий:
см. https://github.com/kubernetes/website/pull/27071 для обновления документации.

aresecurity help wanted kinbug kinfeature lifecyclfrozen prioritimportant-longterm

Самый полезный комментарий

Подведем итоги проблемы:

как указано @anitgandhi :
https://github.com/kubernetes/kubeadm/issues/1223#issuecomment -454572577

проблема с kubeadm здесь в том, что мы не передаем kubelet пару флагов:

--tls-cert-file=<some-path>/kubelet.crt
--tls-private-key-file=<some-path>/kubelet.key

без этих флагов kubelet по умолчанию использует самозаверяющий сертификат при первом запуске, что можно проверить с помощью:

sudo openssl verify -verbose -CAfile /var/lib/kubelet/pki/kubelet.crt /var/lib/kubelet/pki/kubelet.crt

с самозаверяющим сертификатом вместо сертификата, подписанного центром сертификации кластера ( /etc/kubernetes/ca.crt ), развертывания, подобные серверу метрик, не могут очистить кубелет, поскольку самозаверяющий сертификат SAN будет включать только DNS:hostname .

возможные решения:
А) реализовать пение новой пары kubelet.crt/key , в идеале под /var/lib/kubelet/pki и установить дополнительные флаги кублета --tls-cert-file , --tls-private-key-file .

B) документ означает включение этого по запросу аналогично тому, как это сделал https://stackoverflow.com/questions/53212149/x509-certificate-signed-by-unknown-authority-kubeadm/53218524#53218524
кроме, возможно, использования команд Kubernetes CSRs / kubeadm.

C) как прокомментировал @alexbrand

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

D)?

@ kubernetes / sig-кластер-жизненный цикл
мне кажется, что это пространство между ошибкой / функцией.

также см:
https://github.com/kubernetes/community/pull/602/files

Все 38 Комментарий

@ raravena80 Я не знаю ни одного сертификата, созданного kubeadm под /var/lib/kubelet/pki/ .. не могли бы вы предоставить дополнительную информацию? например, файлы конфигурации kubeadm, шаги по созданию кластера

@fabriziopandini Я не совсем уверен, создаются ли сертификаты с помощью kubeadm, но общая процедура описана здесь .

Вот как выглядит содержимое каталога:

root@ip-172-31-1-118:/var/lib/kubelet/pki# pwd
/var/lib/kubelet/pki
root@ip-172-31-1-118:/var/lib/kubelet/pki# ls -al
total 24
drwxr-xr-x 2 root root 4096 Jul 23 21:10 .
drwxr-xr-x 7 root root 4096 Nov 12 04:52 ..
-rw------- 1 root root 2810 Jul 23 21:09 kubelet-client-2018-07-23-21-09-53.pem
-rw------- 1 root root 1159 Jul 23 21:10 kubelet-client-2018-07-23-21-10-43.pem
lrwxrwxrwx 1 root root   59 Jul 23 21:10 kubelet-client-current.pem -> /var/lib/kubelet/pki/kubelet-client-2018-07-23-21-10-43.pem
-rw-r--r-- 1 root root 1501 Nov  8 23:53 kubelet.crt
-rw------- 1 root root 1679 Nov  8 23:53 kubelet.key
root@ip-172-31-1-118:/var/lib/kubelet/pki#

Это файлы kubelet.crt и kubelet.key созданные kubelet при первой загрузке?

@ raravena80 спасибо за разъяснения
Вероятно, у меня нет полного контекста, поэтому я оставляю место для ответа другим.

Только одно примечание (может быть, это может помочь)
Kubeadm уже создает сертификат с именем apiserver-kubelet-client позволяющий серверу api безопасно взаимодействовать с кубелетами; он подписан CA и привязан к необходимым правилам RBAC.

/ назначить @liztio

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

Насколько мне известно, сейчас единственный способ обойти это - создать внеполосные серверные сертификаты Kubelet и разместить их по детерминированному пути, и kubelet (настроенный kubeadm) подберет его и установит соответствующие флаги kubelet. ; ссылка: https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#client -and-serve-Certificates

apiserver-kubelet-client - это сертификат клиента, который сервер API представит kubelet, но kubelet настроен на доверие клиентам, подписанным центром сертификации k8s:

# cat /var/lib/kubelet/config.yaml 
address: 0.0.0.0
apiVersion: kubelet.config.k8s.io/v1beta1
authentication:
  anonymous:
    enabled: false
  webhook:
    cacheTTL: 2m0s
    enabled: true
  x509:
    clientCAFile: /etc/kubernetes/pki/ca.crt

Это идентичность kubelet как сервера, который должен быть подписан центром сертификации k8s, что возвращает нас к исходному вопросу.

Также в конце этой ветки есть соответствующее обсуждение: https://github.com/kubernetes/kubeadm/issues/118

Я думаю, что kubeadm, возможно, придется добавить утверждающего CSR для запросов сертификатов сервера с действующим токеном начальной загрузки, как это делается для запросов сертификатов клиентов?

Как насчет того, чтобы кубелет загружал свой самоподписанный CA куда-нибудь в конфигурационную карту? плагин nodeadmission может ограничить его только своей собственной конфигурационной картой. metrics-server может использовать его для связи с узлом.

Есть идеи по этому поводу?

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

@alexbrand Я согласен с этим

При начальной загрузке kubelet TLS сертификаты клиентов создаются только по любой причине:
--bootstrap-kubeconfig string
Path to a kubeconfig file that will be used to get client certificate for kubelet. If the file specified by --kubeconfig does not exist, the bootstrap kubeconfig is used to request a client certificate from the API server. On success, a kubeconfig file referencing the generated client certificate and key is written to the path specified by --kubeconfig. The client certificate and key file will be stored in the directory pointed by --cert-dir.

И кубеадм это уже делает. Возможно, это запрос функции кублета?

Подведем итоги проблемы:

как указано @anitgandhi :
https://github.com/kubernetes/kubeadm/issues/1223#issuecomment -454572577

проблема с kubeadm здесь в том, что мы не передаем kubelet пару флагов:

--tls-cert-file=<some-path>/kubelet.crt
--tls-private-key-file=<some-path>/kubelet.key

без этих флагов kubelet по умолчанию использует самозаверяющий сертификат при первом запуске, что можно проверить с помощью:

sudo openssl verify -verbose -CAfile /var/lib/kubelet/pki/kubelet.crt /var/lib/kubelet/pki/kubelet.crt

с самозаверяющим сертификатом вместо сертификата, подписанного центром сертификации кластера ( /etc/kubernetes/ca.crt ), развертывания, подобные серверу метрик, не могут очистить кубелет, поскольку самозаверяющий сертификат SAN будет включать только DNS:hostname .

возможные решения:
А) реализовать пение новой пары kubelet.crt/key , в идеале под /var/lib/kubelet/pki и установить дополнительные флаги кублета --tls-cert-file , --tls-private-key-file .

B) документ означает включение этого по запросу аналогично тому, как это сделал https://stackoverflow.com/questions/53212149/x509-certificate-signed-by-unknown-authority-kubeadm/53218524#53218524
кроме, возможно, использования команд Kubernetes CSRs / kubeadm.

C) как прокомментировал @alexbrand

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

D)?

@ kubernetes / sig-кластер-жизненный цикл
мне кажется, что это пространство между ошибкой / функцией.

также см:
https://github.com/kubernetes/community/pull/602/files

Я думаю, что что-то между вариантами B + C должно быть сделано, поскольку большая часть клиентского сертификата / CSR логики kubelet + kubeadm будет иметь общую логику для этого.

Подведем итоги проблемы:

как указано @anitgandhi :
# 1223 (комментарий)

проблема с kubeadm здесь в том, что мы не передаем kubelet пару флагов:

--tls-cert-file=<some-path>/kubelet.crt
--tls-private-key-file=<some-path>/kubelet.key

без этих флагов kubelet по умолчанию использует самозаверяющий сертификат при первом запуске, что можно проверить с помощью:

sudo openssl verify -verbose -CAfile /var/lib/kubelet/pki/kubelet.crt /var/lib/kubelet/pki/kubelet.crt

с самозаверяющим сертификатом вместо сертификата, подписанного центром сертификации кластера ( /etc/kubernetes/ca.crt ), развертывания, подобные серверу метрик, не могут очистить кубелет, поскольку самозаверяющий сертификат SAN будет включать только DNS:hostname .

возможные решения:
А) реализовать пение новой пары kubelet.crt/key , в идеале под /var/lib/kubelet/pki и установить дополнительные флаги кублета --tls-cert-file , --tls-private-key-file .

B) документ означает включение этого по запросу аналогично тому, как это сделал https://stackoverflow.com/questions/53212149/x509-certificate-signed-by-unknown-authority-kubeadm/53218524#53218524
кроме, возможно, использования команд Kubernetes CSRs / kubeadm.

C) как прокомментировал @alexbrand

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

D)?

@ kubernetes / sig-кластер-жизненный цикл
мне кажется, что это пространство между ошибкой / функцией.

также см:
https://github.com/kubernetes/community/pull/602/files

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

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

/ remove-help

потому что решение для реализации еще не выбрано.

Есть какие-нибудь движения по этому поводу? Я сталкиваюсь с этим, чтобы поддерживать функции автомасштабирования в развернутом кластере kubeadm.

Текущий обходной путь - отключить проверку CA сертификата kubelet.

helm install --set 'args={--kubelet-insecure-tls}' --namespace kube-system metrics stable/metrics-serve

не совсем, это заблокировано предложениями по дизайну.
существует ряд обходных путей, но работа по их документированию застопорилась:
https://github.com/kubernetes/kubeadm/issues/1602

--kubelet-insecure-tls

это может быть не идеально для всех пользователей.

Проблемы устаревают после 90 дней бездействия.
Отметьте проблему как новую с помощью /remove-lifecycle stale .
Устаревшие выпуски гниют после дополнительных 30 дней бездействия и в конечном итоге закрываются.

Если сейчас можно безопасно закрыть эту проблему, сделайте это с помощью /close .

Отправьте отзыв в sig-testing, kubernetes / test-infra и / или fejta .
/ жизненный цикл устаревший

/ жизненный цикл заморожен

Возникла именно эта проблема при создании кластера v1.18.2 с помощью kubeadm.

При настройке сервера метрик он не работает без установки флага kubelet-insecure-tls ИЛИ выдачи сертификатов для кублета «вне диапазона», подписывая его с помощью кубернетского ЦС.

Я думал о повторном использовании клиентского сертификата kubelet, но он, конечно, выдается CN = system:node:nodename а не SAN. И я проверил это, хотя, конечно, меняет ошибку, чтобы указать именно на это. Один и тот же сертификат мог бы использоваться как сервер / клиент, если бы у него было имя узла в качестве альтернативного имени субъекта? Но я предполагаю, что было бы правильнее использовать отдельные сертификаты для сервера / клиента?

/ remove-lifecycle заморожен

/ жизненный цикл заморожен

он заморожен, чтобы боты не закрывали проблему.

Один и тот же сертификат мог бы использоваться как сервер / клиент, если бы у него было имя узла в качестве альтернативного имени субъекта?

теоретически, и если kubelet не проверяет их - например, «сертификат клиента не должен иметь SAN».

Но я предполагаю, что было бы правильнее использовать отдельные сертификаты для сервера / клиента?

это обычная практика использовать их отдельно, даже в тех случаях, когда кажется, что этого можно избежать. маловероятно, что разработчики kubelet / auth {z | n} изменили бы эту деталь.

Привет. Сделал еще немного копания. Параметр конфигурации Kubelet serverTLSBootstrap: true может фактически создать CSR для обслуживающего сертификата. Но это оставляет его без утверждения. Что может быть нормально?

Установка rotateCertificates: true и serverTLSBootsrap: true с последующим утверждением CSR для сертификата обслуживания кажется самым простым способом. Запрошенный / выпущенный сертификат обслуживания предназначен для O = system:nodes, CN = system:node:<nodename> с альтернативными именами субъектов для DNS: <nodename>, IP Address: <node IP address>

Должен ли kubeadm at включать параметр конфигурации serverTLSBootstrap, по крайней мере, для того, чтобы утверждение сертификата сервера было легким делом? Или даже kubeadm тоже может одобрить?

Привет. Сделал еще немного копания. Параметр конфигурации Kubelet serverTLSBootstrap: true может фактически создать CSR для обслуживающего сертификата. Но это оставляет его без утверждения. Что может быть нормально?

Установка rotateCertificates: true и serverTLSBootsrap: true с последующим утверждением CSR для сертификата обслуживания кажется самым простым способом. Запрошенный / выпущенный сертификат обслуживания предназначен для O = system:nodes, CN = system:node:<nodename> с альтернативными именами субъектов для DNS: <nodename>, IP Address: <node IP address>

Должен ли kubeadm at включать параметр конфигурации serverTLSBootstrap, по крайней мере, для того, чтобы утверждение сертификата сервера было легким делом? Или даже kubeadm тоже может одобрить?

Не уверен в реализации безопасности, но вы можете объединить serverTLSBootstrap с этим оператором для автоматического утверждения CSR https://github.com/kontena/kubelet-rubber-stamp

Должен ли kubeadm at включать параметр конфигурации serverTLSBootstrap, по крайней мере, для того, чтобы утверждение сертификата сервера было легким делом? Или даже kubeadm тоже может одобрить?

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

API сертификатов должен скоро перейти на GA, и, надеюсь, у нас будет лучший способ справиться с этим в k8s. пожалуйста посмотри:
https://github.com/kubernetes/enhancements/issues/267
(пока мне непонятно, чем мы закончим ...)

у нас также есть альтернативные идеи. но если все это пытается решить проблему с метрическим сервером, вы можете просто использовать https://github.com/brancz/kube-rbac-proxy, который может выполнять SAR по запросам MS к kubelet. к сожалению, это еще не задокументировано с нашей стороны:
https://github.com/kubernetes/kubeadm/issues/1602

@ neolit123 Я, по крайней мере, начал --kubelet-insecure-tls , но я действительно хотел посмотреть, как исправить это безопасным способом, а затем просто заинтересовался этой проблемой. 🙂

На данный момент мне достаточно просто добавить флаг serverTLSbootstrap в конфигурацию kubelet и вручную утвердить сертификаты. Однако я заметил обратную сторону этого: вы не можете полностью взаимодействовать с модулями на узле, пока не утвердите сертификат. (kubectl exec не может запустить команду на подах, запущенных на узле, например, до утверждения)

Я также буду следить за улучшениями. Спасибо.

Это действительно печально, что с kubeadm, который кажется достаточно зрелым, готовый результат для сертификата kubeletet должен быть самоподписанным, и многие люди выбирают kubelet-insecure-tls для сервера метрик вместо того, чтобы делать что-то должным образом и т. Д. :(

это сложная проблема.

пожалуйста, попробуй:
https://github.com/kontena/kubelet-rubber-stamp
или же
https://github.com/brancz/kube-rbac-proxy
как обходные пути

это сложная проблема.

пожалуйста, попробуй:
https://github.com/kontena/kubelet-rubber-stamp
или же
https://github.com/brancz/kube-rbac-proxy
как обходные пути

На самом деле https://github.com/kontena/kubelet-rubber-stamp работает довольно хорошо, и imo кажется более правильным решением вместо прокси.

Шаг 1:
Добавлять
serverTLSBootstrap: true до конца каждого /var/lib/kubelet/config.yaml для реконфигурации кубелетов и не забудьте применить конфигурацию (или просто перезагрузить их)

Шаг 2:
Развернуть кубелет-штамп

service_account.yaml
role.yaml
role_binding.yaml
operator.yaml

Шаг 3:
Изменить развертывание сервера метрик и удалить --kubelet-insecure-tls

Результат:

kubectl get csr
NAME        AGE   SIGNERNAME                      REQUESTOR          CONDITION
csr-7dvsx   31m   kubernetes.io/kubelet-serving   system:node:u-02   Approved,Issued
csr-d6rvm   31m   kubernetes.io/kubelet-serving   system:node:u-03   Approved,Issued
csr-szblz   31m   kubernetes.io/kubelet-serving   system:node:u-01   Approved,Issued
csr-zjfgj   31m   kubernetes.io/kubelet-serving   system:node:u-04   Approved,Issued

Эй, просто чтобы добавить к этому @vainkop
Во время вашего начального kubeadm init для создания кластера вы также должны иметь возможность передать объектный файл KubeletConfiguration API, чтобы установить serverTLSBootstrap

`` kubeadm-config.yaml
apiВерсия: kubeadm.k8s.io/v1beta2
вид: ClusterConfiguration

...

apiVersion: kubelet.config.k8s.io/v1beta1
вид: KubeletConfiguration
serverTLSBootstrap: правда

`kubeadm init --config=kubeadm-config.yaml`

Then all kubelet's will automatically be set up using the `serverTLSBootstrap` flag.

To get the CSRs

kubectl получить csr
ИМЯ ВОЗРАСТ ПОДПИСЬ СОСТОЯНИЕ ЗАПРОСА
csr-2qkdw 2m1s kubernetes.io/kube-apiserver-client-kubelet system: bootstrap : fcufbo Approved, Issued
csr-9wvgt 114s kubernetes.io/kubelet-serving system: node : worker-1 Pending
csr-lz97v 4m58s kubernetes.io/kubelet-serving system: node : master-1 Pending
csr-rsdsp 4m59s kubernetes.io/kube-apiserver-client-kubelet system: node : master-1 Approved, Issued
csr-wgxqs 4m49s kubernetes.io/kubelet-serving system: node : master-1 Pending

Then either approve them manually or deploy https://github.com/kontena/kubelet-rubber-stamp which approves them automatically. I just tried it with kubelet-rubber-stamp and it works great.

Also I did not seem to need to restart the kubelet's this way, they picked up their certificates as soon as I approvde the CSR, but a caveat is that the kublet's have NO cert until the CSR is approved, it does not get a self signed certificate first.

Сертификат kubectl подтвердить csr-ab123 # ИЛИ развернуть штамп!

kubectl получить csr
ИМЯ ВОЗРАСТ ПОДПИСЬ СОСТОЯНИЕ ЗАПРОСА
csr-9wvgt 3m kubernetes.io/kubelet-serving system: node : worker-1 Approved, Issued
...
``

Кстати, здесь происходит еще одна странная вещь: главный узел, кажется, дважды создает свой CSR. (По крайней мере, два раза я пробовал это)

Но, как говорит @nijave в комментарии выше, я не уверен, каковы последствия для безопасности использования резинового штампа.

@allir , @vainkop насколько я вижу, kubelet-rubber-stamp только проверяет, совпадает ли общее имя CSR с именем запрашивающего, но не проверяет, действительны ли дополнительные имена хостов и IP-адреса, запрошенные kubelet. Это означает, что злоумышленник, имеющий доступ к сертификату клиента kubelet, может создавать сертификаты практически для любого доменного имени или IP-адреса. Все клиенты, настроенные на доверие корневому ЦС, будут принимать этот сертификат.
Конечно, проверка имени хоста и IP-адресов, действительных для данного кублета, является сложной задачей, поскольку в настоящее время нет органа, который мог бы подтвердить, что кубелету разрешено запрашивать. Например, использования объекта узла на сервере API недостаточно, поскольку кублеты могут обновлять объект без ограничений.

Эй, просто чтобы добавить к этому @vainkop
Во время вашего начального kubeadm init для создания кластера вы также должны иметь возможность передать объектный файл KubeletConfiguration API, чтобы установить serverTLSBootstrap
kubeadm init --config=kubeadm-config.yaml
Тогда все кубелеты будут автоматически настроены с использованием флага serverTLSBootstrap .

Или для существующей настройки K8s с использованием Ansible это может быть:

  tasks:
    - name: Insert a line at the end of /var/lib/kubelet/config.yaml
      lineinfile:
        path: /var/lib/kubelet/config.yaml
        line: 'serverTLSBootstrap: true'

+ перезапустить кубелец

Вау, я так рад, что нашел эту проблему, и не только я хочу, чтобы все было по-настоящему. :)

А теперь позвольте мне поделиться своими мыслями по этому поводу (поправьте меня, если я ошибаюсь) :

Сначала мое видение исходной проблемы:
В настоящее время kubeadm по умолчанию включает аутентификацию webhook для всех kubelet, поэтому kubelet без проблем проверяет сертификаты клиентов для входящих соединений, даже если указана опция --kubelet-insecure-tls .
С другой стороны, у метрик-сервера нет возможности проверить конкретный сертификат кублета, потому что он самоподписан на узле.

Возможные риски использования --kubelet-insecure-tls для metrics-server:
Хотя данные кубелета в некоторой степени защищены и никогда не будут предоставлены на сервер метрик без успешной аутентификации веб-перехватчика.
Теоретически кто-то может скомпрометировать IP-адрес сервера или имя хоста и предоставить неверную статистику. Но для установления соединений metricserver использует IP-адрес и имена хостов, указанные для узла через kube-apiserver, поэтому злоумышленнику необходимо сначала взломать API-сервер, DNS или IP-адрес узла.

Небольшое наблюдение:
Сервер метрик - это не единственная служба, которая напрямую обращается к кубелетам. Kube-apiserver также делает это для чтения логов контейнеров или выполнения на них оболочки. Хороший вопрос: как kube-apiserver гарантирует, что он устанавливает соединение с конкретным kubelet, когда у него нет никакой информации о CA, который выпустил его сертификат?
Разве в этом случае он не ведет себя так же, как сервер метрик с параметром --kubelet-insecure-tls ?

Возможное решение:
В настоящее время веб-перехватчики и агрегация API довольно популярны в Kubernetes. Все они ведут себя одинаково, генерируя собственный CA и пару crt / key. Хэш CA также хранится в определенном ресурсе, чтобы предоставить kube-apiserver информацию о том, какому сертификату он может доверять.

Например:

  • APIServices хранит связанный хэш CA в своем ресурсе apiservices.apiregistration.k8s.io :

    spec:
    caBundle: <ca-hash>
    
  • Webhooks хранят связанный хеш CA в своих ресурсах validatingwebhookconfigurations.admissionregistration.k8s.io и mutatingwebhookconfigurations.admissionregistration.k8s.io :

    webhooks:
    - clientConfig:
      caBundle: <ca-hash>
    

Для меня довольно очевидно, что каждый ресурс узла должен иметь аналогичный caBundle в своем spec , где кублеты могут зарегистрировать свой собственный CA для обслуживания, используя свой сертификат клиента:

spec:
  caBundle: <ca-hash>

И metris-server, и kube-apiserver должны использовать эти сертификаты для проверки и доверия соединения с kubelets.

спасибо @ kfox1111, который ранее высказал аналогичную идею https://github.com/kubernetes/kubeadm/issues/1223#issuecomment -460854312

Хороший вопрос: как kube-apiserver гарантирует, что он устанавливает соединение с конкретным kubelet, когда у него нет никакой информации о CA, который выпустил его сертификат?
Разве в этом случае он не ведет себя так же, как сервер метрик с опцией --kubelet-insecure-tls ?

Чтобы ответить на этот вопрос, я могу процитировать здесь @luxas :

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

с https://github.com/kubernetes/kubeadm/issues/118#issuecomment -407498529

надеюсь, что это может быть решено когда-нибудь

[root<strong i="6">@jenkins</strong> metrics-server]# kubectl -n kube-system logs -f metrics-server-6955d88db9-lftlz
I1120 08:23:09.094132       1 requestheader_controller.go:169] Starting RequestHeaderAuthRequestController
I1120 08:23:09.094234       1 shared_informer.go:240] Waiting for caches to sync for RequestHeaderAuthRequestController
I1120 08:23:09.094270       1 configmap_cafile_content.go:202] Starting client-ca::kube-system::extension-apiserver-authentication::client-ca-file
I1120 08:23:09.094279       1 shared_informer.go:240] Waiting for caches to sync for client-ca::kube-system::extension-apiserver-authentication::client-ca-file
I1120 08:23:09.094307       1 configmap_cafile_content.go:202] Starting client-ca::kube-system::extension-apiserver-authentication::requestheader-client-ca-file
I1120 08:23:09.094315       1 shared_informer.go:240] Waiting for caches to sync for client-ca::kube-system::extension-apiserver-authentication::requestheader-client-ca-file
I1120 08:23:09.095064       1 dynamic_serving_content.go:130] Starting serving-cert::/tmp/apiserver.crt::/tmp/apiserver.key
I1120 08:23:09.095207       1 secure_serving.go:197] Serving securely on [::]:4443
I1120 08:23:09.095259       1 tlsconfig.go:240] Starting DynamicServingCertificateController
I1120 08:23:09.194453       1 shared_informer.go:247] Caches are synced for client-ca::kube-system::extension-apiserver-authentication::requestheader-client-ca-file 
I1120 08:23:09.194660       1 shared_informer.go:247] Caches are synced for client-ca::kube-system::extension-apiserver-authentication::client-ca-file 
I1120 08:23:09.194455       1 shared_informer.go:247] Caches are synced for RequestHeaderAuthRequestController 
E1120 08:23:10.420643       1 server.go:132] unable to fully scrape metrics: [unable to fully scrape metrics from node k8s-master3: unable to fetch metrics from node k8s-master3: Get "https://10.39.140.250:10250/stats/summary?only_cpu_and_memory=true": x509: cannot validate certificate for 10.39.140.250 because it doesn't contain any IP SANs, unable to fully scrape metrics from node k8s-master1: unable to fetch metrics from node k8s-master1: Get "https://10.39.140.248:10250/stats/summary?only_cpu_and_memory=true": x509: cannot validate certificate for 10.39.140.248 because it doesn't contain any IP SANs, unable to fully scrape metrics from node k8s-master2: unable to fetch metrics from node k8s-master2: Get "https://10.39.140.249:10250/stats/summary?only_cpu_and_memory=true": x509: cannot validate certificate for 10.39.140.249 because it doesn't contain any IP SANs, unable to fully scrape metrics from node k8s-node1: unable to fetch metrics from node k8s-node1: Get "https://10.39.140.251:10250/stats/summary?only_cpu_and_memory=true": x509: cannot validate certificate for 10.39.140.251 because it doesn't contain any IP SANs]
I1120 08:23:33.874949       1 requestheader_controller.go:183] Shutting down RequestHeaderAuthRequestController
I1120 08:23:33.874978       1 configmap_cafile_content.go:223] Shutting down client-ca::kube-system::extension-apiserver-authentication::client-ca-file
I1120 08:23:33.874993       1 configmap_cafile_content.go:223] Shutting down client-ca::kube-system::extension-apiserver-authentication::requestheader-client-ca-file
I1120 08:23:33.875019       1 tlsconfig.go:255] Shutting down DynamicServingCertificateController
I1120 08:23:33.875026       1 dynamic_serving_content.go:145] Shutting down serving-cert::/tmp/apiserver.crt::/tmp/apiserver.key
I1120 08:23:33.875041       1 secure_serving.go:241] Stopped listening on [::]:4443

Нет новостей из этого номера? Мне было бы интересно найти решение для этого.

мы документируем обходные пути здесь:
https://github.com/kubernetes/website/pull/27071
https://github.com/kubernetes/kubeadm/issues/1602

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

Была ли эта страница полезной?
0 / 5 - 0 рейтинги