Некоторые команды kubectl не работают, когда кластер K8S инициализируется самогенерированным сертификатом apiserver-kubelet-client.crt

Мне нужно сгенерировать собственные SSL-сертификаты для компонентов кластера Kubernetes (apiserver, apiserver-kubelet-client, apiserver-etcd-client, front-proxy-client и т. Д.). Причина этого в том, что срок действия для этих сертификатов по умолчанию установлен на 1 год, и мне нужно, чтобы срок действия был более одного года по причинам моего бизнеса. Когда я сгенерировал свой собственный набор сертификатов и инициализировал кластер, все заработало отлично - запускались POD в пространствах имен kube-system, работало соединение с apiserver. Но я воспользовался тем, что некоторые команды, такие как kubectl logs, kubectl port-forward или kubectl exec, перестали работать и начали выдавать следующие ошибки:

kubectl logs <kube-apiserver-pod> -n kube-system
error: You must be logged in to the server (the server has asked for the client to provide credentials ( pods/log <kube-apiserver-pod>))

or

kubectl exec -it <kube-apiserver-pod> -n kube-system sh
error: unable to upgrade connection: Unauthorized`

однако команда docker exec для входа в контейнер k8s_apiserver работает правильно.

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

Ниже показан процесс, который я использовал для создания и использования моей собственной пары сертификат / ключ для apiserver-kubelet-client.

  1. Я инициализировал кластер Kubernetes для установки собственных сертификатов в папку /etc/kubernetes/pki, запустив kubeadm init ...

  2. Сделайте резервную копию папки /etc/kubernetes/pki в /tmp/pki_k8s

  3. Откройте apiserver-kubelet-client.crt с помощью openssl, чтобы проверить все установленные расширения, CN, O и т. Д.

    openssl x509 -noout -text -in /tmp/pki_k8s/apiserver-kubelet-client.crt

  4. Чтобы гарантировать, что такие же расширения и параметры CN, O будут отображаться в сертификате, созданном мной, я создал файл .conf для расширений и файл .csr для CN и O

    cd /tmp/pki_k8s/ cat <<-EOF_api_kubelet_client-ext > apiserver_kubelet_client-ext.conf [ v3_ca ] keyUsage = critical, digitalSignature, keyEncipherment extendedKeyUsage = clientAuth EOF_api_kubelet_client-ext

    openssl req -new -key apiserver-kubelet-client.key -out apiserver-kubelet-client.csr -subj "/O=system:masters,CN=kube-apiserver-kubelet-client"

  5. Наконец, я создал свой собственный apiserver-kubelet-client.crt. Для его генерации я повторно использовал существующие apiserver-kubelet-client.key и ca.crt / ca.key, сгенерированные при инициализации K8S.

    openssl x509 -req -in apiserver-kubelet-client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -sha256 -out apiserver-kubelet-client.crt -extensions v3_ca -extfile apiserver_kubelet_client-ext.conf -days 3650

  6. Как только я сгенерировал свой собственный apiserver-kubelet-client.crt, который перекрывает предыдущий, созданный самим сценарием инициализации k8s, я сбрасываю кластер kubernetes, нажимая kubeadm reset. Эта очищенная папка / etc / kubernetes

  7. скопируйте все сертификаты в /etc/kubernetes/pki из /tmp/pki_k8s

  8. и повторно инициализировать кластер K8S kubeadm init ...

Во время этого я увидел, что кластер K8S использовал для настройки уже существующие сертификаты, хранящиеся в /etc/kubernetes/pki.

[kubelet] Writing kubelet environment file with flags to file "/var/lib/kubelet/kubeadm-flags.env"
[kubelet] Writing kubelet configuration to file "/var/lib/kubelet/config.yaml"
[preflight] Activating the kubelet service
[certificates] Using the existing ca certificate and key.
[certificates] Using the existing apiserver certificate and key.
[certificates] Using the existing apiserver-kubelet-client certificate and key.
[certificates] Using the existing sa key.
[certificates] Using the existing front-proxy-ca certificate and key.
[certificates] Using the existing front-proxy-client certificate and key.
[certificates] Using the existing etcd/ca certificate and key.
[certificates] Using the existing etcd/server certificate and key.
[certificates] Using the existing etcd/peer certificate and key.
[certificates] Using the existing etcd/healthcheck-client certificate and key.
[certificates] Using the existing apiserver-etcd-client certificate and key.
[certificates] valid certificates and keys now exist in "/etc/kubernetes/pki"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/admin.conf"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/kubelet.conf"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/controller-manager.conf"
[kubeconfig] Wrote KubeConfig file to disk: "/etc/kubernetes/scheduler.conf"
[controlplane] wrote Static Pod manifest for component kube-apiserver to "/etc/kubernetes/manifests/kube-apiserver.yaml"
[controlplane] wrote Static Pod manifest for component kube-controller-manager to "/etc/kubernetes/manifests/kube-controller-manager.yaml"
[controlplane] wrote Static Pod manifest for component kube-scheduler to "/etc/kubernetes/manifests/kube-scheduler.yaml"
[etcd] Wrote Static Pod manifest for a local etcd instance to "/etc/kubernetes/manifests/etcd.yaml"
[init] waiting for the kubelet to boot up the control plane as Static Pods from directory "/etc/kubernetes/manifests"
[init] this might take a minute or longer if the control plane images have to be pulled

После этого кластер K8S находится в рабочем состоянии, я могу перечислить модули, перечислить описание, выполнить развертывание и т. Д., Но не смог проверить журналы, выполнить команду exec, как описано выше.

 kubectl get pods -n kube-system
NAME                                           READY     STATUS    RESTARTS   AGE
coredns-78fcdf6894-kjkp9                       1/1       Running   0          2m
coredns-78fcdf6894-q88lx                       1/1       Running   0          2m
...

kubectl  logs <apiserver_pod> -n kube-system -v 7
I0818 08:51:12.435494   12811 loader.go:359] Config loaded from file /root/.kube/config
I0818 08:51:12.436355   12811 loader.go:359] Config loaded from file /root/.kube/config
I0818 08:51:12.438413   12811 loader.go:359] Config loaded from file /root/.kube/config
I0818 08:51:12.447751   12811 loader.go:359] Config loaded from file /root/.kube/config
I0818 08:51:12.448109   12811 round_trippers.go:383] GET https://<HOST_IP>:6443/api/v1/namespaces/kube-system/pods/<apiserver_pod>
I0818 08:51:12.448126   12811 round_trippers.go:390] Request Headers:
I0818 08:51:12.448135   12811 round_trippers.go:393]     Accept: application/json, */*
I0818 08:51:12.448144   12811 round_trippers.go:393]     User-Agent: kubectl/v1.11.0 (linux/amd64) kubernetes/91e7b4f
I0818 08:51:12.462931   12811 round_trippers.go:408] Response Status: 200 OK in 14 milliseconds
I0818 08:51:12.471316   12811 loader.go:359] Config loaded from file /root/.kube/config
I0818 08:51:12.471949   12811 round_trippers.go:383] GET https://<HOST_IP>:6443/api/v1/namespaces/kube-system/pods/<apiserver_pod>/log
I0818 08:51:12.471968   12811 round_trippers.go:390] Request Headers:
I0818 08:51:12.471977   12811 round_trippers.go:393]     Accept: application/json, */*
I0818 08:51:12.471985   12811 round_trippers.go:393]     User-Agent: kubectl/v1.11.0 (linux/amd64) kubernetes/91e7b4f
I0818 08:51:12.475827   12811 round_trippers.go:408] Response Status: 401 Unauthorized in 3 milliseconds
I0818 08:51:12.476288   12811 helpers.go:201] server response object: [{
  "metadata": {},
  "status": "Failure",
  "message": "the server has asked for the client to provide credentials ( pods/log <apiserver_pod>)",
  "reason": "Unauthorized",
  "details": {
    "name": "<apiserver_pod>",
    "kind": "pods/log"
  },
  "code": 401
}]
F0818 08:51:12.476325   12811 helpers.go:119] error: You must be logged in to the server (the server has asked for the client to provide credentials ( pods/log <apiserver_pod>))

См. Служебный файл kubelet ниже:

[root@qa053 ~]# cat /etc/systemd/system/kubelet.service.d/10-kubeadm.conf

Note: This dropin only works with kubeadm and kubelet v1.11+
[Service]
Environment="KUBELET_KUBECONFIG_ARGS=--bootstrap-kubeconfig=/etc/kubernetes/bootstrap-kubelet.conf --kubeconfig=/etc/kubernetes/kubelet.conf"
Environment="KUBELET_CONFIG_ARGS=--config=/var/lib/kubelet/config.yaml"
Environment="CA_CLIENT_CERT=--client-ca-file=/etc/kubernetes/pki/ca.crt"
Environment="KUBELE=--rotate-certificates=true"
# This is a file that "kubeadm init" and "kubeadm join" generates at runtime, populating the KUBELET_KUBEADM_ARGS variable dynamically
EnvironmentFile=-/var/lib/kubelet/kubeadm-flags.env
# This is a file that the user can use for overrides of the kubelet args as a last resort. Preferably, the user should use
# the .NodeRegistration.KubeletExtraArgs object in the configuration files instead. KUBELET_EXTRA_ARGS should be sourced from this file.
EnvironmentFile=-/etc/sysconfig/kubelet
ExecStart=
ExecStart=/usr/bin/kubelet $KUBELET_KUBECONFIG_ARGS $KUBELET_CONFIG_ARGS $KUBELET_KUBEADM_ARGS $KUBELET_EXTRA_ARGS $KUBELET_CERTIFICATE_ARGS $CA_CLIENT_CERT

Есть ли у вас какие-либо идеи ? :) Спасибо

С наилучшими пожеланиями


person JaroVojtek    schedule 16.08.2018    source источник
comment
Какой результат kubectl --loglevel=9 logs <kube-apiserver-pod> -n kube-system   -  person Aleksandar    schedule 17.08.2018
comment
Привет @Aleksandar, --loglevel для kubectl - неизвестный флаг, но -v 7 woks, я отредактирую вышеуказанный вопрос, потому что вывод логгера превышает 600 символов   -  person JaroVojtek    schedule 18.08.2018
comment
Пожалуйста, поделитесь своим служебным файлом Kubelet.   -  person Akar    schedule 20.08.2018
comment
Привет, Акар, см. Конфигурационный файл сервиса kubelet в конце поста.   -  person JaroVojtek    schedule 21.08.2018
comment
Просто хочу добавить сюда один комментарий. Похоже, apiserver не может разговаривать с сервисом kubelet - для этого используется apiserver-kubelet-client.crt. Я следовал документации, описанной здесь: kubernetes.io/docs/setup/certificates. Я, как администратор, могу общаться с apiserver (kubectl get pods и т. Д.), Также служба kubelet может общаться с apiserver (POD настроены и работают). Но...   -  person JaroVojtek    schedule 21.08.2018
comment
когда вы выполняете, например, _1 _..., я считаю, что эта схема связи выглядит так: администратор делает запрос к apiserver, а apiserver отправляет запрос обратно на сервер, на котором запущены kubelet и docker. и он хочет выполнить docker exec -it..., и это общение каким-то образом запрещено   -  person JaroVojtek    schedule 21.08.2018


Ответы (1)


Я выяснил причину, по которой это не сработало.

При создании файла .csr я использовал это:

openssl req -new -key apiserver-kubelet-client.key -out apiserver-kubelet-client.csr -subj "/O=system:masters,CN=kube-apiserver-kubelet-client"

Но в -subj было неправильное форматирование, что вызывало проблемы с синтаксическим анализом правильного CN из сертификата. Вместо "/O=system:masters,CN=kube-apiserver-kubelet-client" нужно

openssl req -new -key apiserver-kubelet-client.key -out apiserver-kubelet-client.csr -subj "/O=system:masters/CN=kube-apiserver-kubelet-client"

Сертификаты, созданные обоими CSR-файлами, выглядят одинаково с точки зрения текстового представления. Но они действуют иначе.

person JaroVojtek    schedule 24.08.2018