Kubeadm: utilizar certificados de servicio de kubelet firmados

Creado en 9 nov. 2018  ·  38Comentarios  ·  Fuente: kubernetes/kubeadm

¿Es este un INFORME DE ERROR o una SOLICITUD DE FUNCIÓN?

/ tipo error

Abriendo el lado kubeadm para este problema en el servidor de métricas

Versiones

$ 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"}

Medio ambiente :

  • Versión de Kubernetes (use 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"}
  • Proveedor de nube o configuración de hardware :
    Alguna
  • SO (por ejemplo, de / etc / os-release):
    Alguna
  • Kernel (por ejemplo, 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
  • Otros :

¿Qué sucedió?

kubeadm crea certificados por debajo de /var/lib/kubelet/pki/kubelet.* firmados con una CA diferente de la que está debajo de /etc/kubernetes/pki/ca.pem

¿Qué esperabas que sucediera?

Como resultado, algunas aplicaciones como el servidor de métricas no pueden recopilar estadísticas de un kubelet seguro porque el kubelet tiene certificados firmados por un ca diferente al maestro (s) de K8.

Muestra de error:

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]

¿Cómo reproducirlo (de la forma más mínima y precisa posible)?

Instale el servidor de métricas en ejecución:

$ kubectl -n registros del sistema kube

¿Algo más que necesitemos saber?

Algo más de antecedentes aquí

También hay pasos allí que seguí para solucionar el problema.


editar: neolit123

el problema aquí es que el certificado de servicio está autofirmado de forma predeterminada:
consulte https://github.com/kubernetes/website/pull/27071 para obtener información actualizada sobre la documentación.

aresecurity help wanted kinbug kinfeature lifecyclfrozen prioritimportant-longterm

Comentario más útil

resumamos el problema:

como lo describe @anitgandhi :
https://github.com/kubernetes/kubeadm/issues/1223#issuecomment -454572577

el problema con kubeadm aquí es que no estamos pasando un par de banderas al kubelet:

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

sin estos indicadores, kubelet adopta de forma predeterminada el certificado de servicio autofirmado cuando se ejecuta por primera vez, que se puede verificar con:

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

con un certificado autofirmado en lugar de un certificado firmado por la CA del clúster ( /etc/kubernetes/ca.crt ), las implementaciones como el servidor de métricas no pueden eliminar el kubelet, porque el certificado SAN autofirmado solo incluirá DNS:hostname .

soluciones posibles:
A) implemente el canto de un nuevo par kubelet.crt/key , idealmente por debajo de /var/lib/kubelet/pki y establezca las banderas kubelet adicionales --tls-cert-file , --tls-private-key-file .

B) documento significa habilitar esto bajo demanda de manera similar a cómo lo hizo https://stackoverflow.com/questions/53212149/x509-certificate-signed-by-unknown-authority-kubeadm/53218524#53218524
excepto posiblemente utilizando los comandos Kubernetes CSR / kubeadm.

C) como lo comentó @alexbrand

Si es posible, creo que deberíamos usar las funciones de arranque de TLS integradas en kubelet para solicitar / rotar certificados de servicio.

D) ?

@ kubernetes / sig-cluster-lifecycle
para mí esto parece en el espacio entre error / característica.

ver también:
https://github.com/kubernetes/community/pull/602/files

Todos 38 comentarios

@ raravena80 No tengo conocimiento de ningún certificado creado por kubeadm bajo /var/lib/kubelet/pki/ .. ¿podría proporcionarnos más información? por ejemplo, archivos de configuración de kubeadm, pasos para crear el clúster

@fabriziopandini No estoy del todo seguro de si los certificados son creados por kubeadm, pero el procedimiento general se describe aquí .

Así es como se ve el contenido del directorio:

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#

¿Son archivos kubelet.crt y kubelet.key creados por el kubelet la primera vez que se carga?

@ raravena80 gracias por la aclaración
Probablemente no tengo el contexto completo aquí, así que dejo espacio para que otros respondan.

Solo una nota al margen (podría ser que pueda ayudar)
Kubeadm ya crea un certificado llamado apiserver-kubelet-client para permitir que el servidor api hable de forma segura con los kubelets; está firmado por ca y sujeto a las reglas RBAC necesarias.

/ asignar @liztio

Creo que esto es para generar previamente los certificados de servidor de kubelet. Traté de intentar usar las banderas de Kubelet para el arranque del servidor TLS y rotar los certificados del servidor, desafortunadamente no pude hacer que Kubelet solicitara un certificado de servidor para sí mismo usando el token de arranque. Kubelet termina recurriendo a su comportamiento predeterminado para los certificados de servidor, que es generar uno autofirmado.

Hasta donde yo sé, en este momento la única forma de evitarlo es generar certificados de servidor de Kubelet fuera de banda y colocarlos en una ruta determinista y kubelet (configurado por kubeadm) lo recogerá y establecerá algunos indicadores de kubelet en consecuencia. ; referencia: https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#client -and-serve -ificates

El apiserver-kubelet-client es el certificado de cliente que el servidor API presentará a un kubelet, pero kubelet está configurado para confiar en los clientes que están firmados por la CA 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

Es la identidad de kubelet como servidor que se presenta lo que debe estar firmado por la CA de k8s, lo que llega a la pregunta original.

También hay una discusión relevante al final de este hilo: https://github.com/kubernetes/kubeadm/issues/118

Creo que es posible que kubeadm tenga que agregar un aprobador de CSR para las solicitudes de certificados del servidor con un token de arranque válido, tal como lo hace para las solicitudes de certificados del cliente.

¿Qué hay de hacer que el kubelet cargue su ca autofirmado en un mapa de configuración en algún lugar? el complemento nodeadmission podría restringirlo a solo su propio mapa de configuración. metrics-server puede usarlo para contactar al nodo.

¿Alguna idea sobre eso?

Si es posible, creo que deberíamos usar las funciones de arranque de TLS integradas en kubelet para solicitar / rotar certificados de servicio.

@alexbrand estoy de acuerdo en eso

El bootstrapping de kubelet TLS solo genera certificados de cliente por cualquier motivo:
--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.

Y kubeadm ya lo hace. ¿Quizás esta es una solicitud de función de kubelet?

resumamos el problema:

como lo describe @anitgandhi :
https://github.com/kubernetes/kubeadm/issues/1223#issuecomment -454572577

el problema con kubeadm aquí es que no estamos pasando un par de banderas al kubelet:

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

sin estos indicadores, kubelet adopta de forma predeterminada el certificado de servicio autofirmado cuando se ejecuta por primera vez, que se puede verificar con:

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

con un certificado autofirmado en lugar de un certificado firmado por la CA del clúster ( /etc/kubernetes/ca.crt ), las implementaciones como el servidor de métricas no pueden eliminar el kubelet, porque el certificado SAN autofirmado solo incluirá DNS:hostname .

soluciones posibles:
A) implemente el canto de un nuevo par kubelet.crt/key , idealmente por debajo de /var/lib/kubelet/pki y establezca las banderas kubelet adicionales --tls-cert-file , --tls-private-key-file .

B) documento significa habilitar esto bajo demanda de manera similar a cómo lo hizo https://stackoverflow.com/questions/53212149/x509-certificate-signed-by-unknown-authority-kubeadm/53218524#53218524
excepto posiblemente utilizando los comandos Kubernetes CSR / kubeadm.

C) como lo comentó @alexbrand

Si es posible, creo que deberíamos usar las funciones de arranque de TLS integradas en kubelet para solicitar / rotar certificados de servicio.

D) ?

@ kubernetes / sig-cluster-lifecycle
para mí esto parece en el espacio entre error / característica.

ver también:
https://github.com/kubernetes/community/pull/602/files

Creo que se debe hacer algo entre las opciones B + C, ya que gran parte del certificado de cliente de token de arranque / lógica de CSR kubelet + kubeadm tendría una lógica común para esto.

resumamos el problema:

como lo describe @anitgandhi :
# 1223 (comentario)

el problema con kubeadm aquí es que no estamos pasando un par de banderas al kubelet:

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

sin estos indicadores, kubelet adopta de forma predeterminada el certificado de servicio autofirmado cuando se ejecuta por primera vez, que se puede verificar con:

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

con un certificado autofirmado en lugar de un certificado firmado por la CA del clúster ( /etc/kubernetes/ca.crt ), las implementaciones como el servidor de métricas no pueden eliminar el kubelet, porque el certificado SAN autofirmado solo incluirá DNS:hostname .

soluciones posibles:
A) implemente el canto de un nuevo par kubelet.crt/key , idealmente por debajo de /var/lib/kubelet/pki y establezca las banderas kubelet adicionales --tls-cert-file , --tls-private-key-file .

B) documento significa habilitar esto bajo demanda de manera similar a cómo lo hizo https://stackoverflow.com/questions/53212149/x509-certificate-signed-by-unknown-authority-kubeadm/53218524#53218524
excepto posiblemente utilizando los comandos Kubernetes CSR / kubeadm.

C) como lo comentó @alexbrand

Si es posible, creo que deberíamos usar las funciones de arranque de TLS integradas en kubelet para solicitar / rotar certificados de servicio.

D) ?

@ kubernetes / sig-cluster-lifecycle
para mí esto parece en el espacio entre error / característica.

ver también:
https://github.com/kubernetes/community/pull/602/files

gran resumen @ neolit123 . ¿Sabe si esto se deslizará al próximo ciclo o al trabajo en progreso mientras hablamos? Preguntando principalmente por el servidor de métricas que, en mi opinión, cada implementación quiere tenerlo;)

@randomvariable mencionó que hay otra solución para eso.
De las discusiones hasta ahora, dudamos en firmar el certificado de servicio de kubelet con la CA del clúster. este tema necesita más discusión.

/ eliminar-ayuda

porque aún no se ha elegido la solución a implementar.

¿Algún movimiento sobre esto? Me estoy enfrentando a él para admitir funciones de ajuste de escala automático dentro de un clúster implementado de kubeadm.

La solución alternativa actual es desactivar la verificación de CA del certificado de kubelet.

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

no realmente, está bloqueado en las propuestas de diseño.
hay una serie de soluciones, pero el trabajo de documentar los estancados:
https://github.com/kubernetes/kubeadm/issues/1602

--kubelet-inseguro-tls

esto puede no ser ideal para todos los usuarios.

Los problemas se vuelven obsoletos después de 90 días de inactividad.
Marque el problema como nuevo con /remove-lifecycle stale .
Los problemas obsoletos se pudren después de 30 días adicionales de inactividad y finalmente se cierran.

Si es seguro cerrar este problema ahora, hágalo con /close .

Envíe sus comentarios a sig-testing, kubernetes / test-infra y / o fejta .
/ ciclo de vida obsoleto

/ ciclo de vida congelado

Me encontré con este problema exacto al crear un clúster v1.18.2 con kubeadm.

Al configurar el servidor de métricas, no funciona sin configurar su kubelet-insecure-tls flag O emitir certificados para kublet "fuera de banda", firmando con la CA de kubernetes.

Pensé en reutilizar el certificado de cliente de kubelet pero, por supuesto, se emite a CN = system:node:nodename y no a SAN. Y lo probé, lo que, por supuesto, cambia el error para indicar solo eso. ¿El mismo certificado podría usarse como servidor / cliente si tuviera el nombre de nodo como nombre alternativo del sujeto? Pero supongo que sería más apropiado usar certificados separados para servidor / cliente.

/ remove-lifecycle congelado

/ ciclo de vida congelado

está congelado para que los bots no cierren el problema.

¿El mismo certificado podría usarse como servidor / cliente si tuviera el nombre de nodo como nombre alternativo del sujeto?

en teoría ya menos que kubelet los valide, por ejemplo, "el certificado de cliente no debe tener SAN".

Pero supongo que sería más apropiado usar certificados separados para servidor / cliente.

Es una práctica común utilizarlos por separado incluso en los casos en que parece evitable. es poco probable que los mantenedores de kubelet / auth {z | n} cambien este detalle.

Oye. Hice un poco más de excavación. La opción de configuración de Kubelet serverTLSBootstrap: true puede crear una CSR para el certificado de servicio. Pero lo deja sin aprobar. ¿Cuál puede estar bien?

Establecer rotateCertificates: true y serverTLSBootsrap: true y luego aprobar la CSR para el certificado de publicación parece ser la forma más fácil de hacerlo. El certificado de publicación que se solicita / emite es por O = system:nodes, CN = system:node:<nodename> con nombres alternativos del sujeto por DNS: <nodename>, IP Address: <node IP address>

¿Debería kubeadm al habilitar la opción de configuración serverTLSBootstrap al menos para que Aprobar el certificado del servidor sea algo fácil de hacer? ¿O incluso kubeadm podría hacer la aprobación también?

Oye. Hice un poco más de excavación. La opción de configuración de Kubelet serverTLSBootstrap: true puede crear una CSR para el certificado de servicio. Pero lo deja sin aprobar. ¿Cuál puede estar bien?

Establecer rotateCertificates: true y serverTLSBootsrap: true y luego aprobar la CSR para el certificado de publicación parece ser la forma más fácil de hacerlo. El certificado de publicación que se solicita / emite es por O = system:nodes, CN = system:node:<nodename> con nombres alternativos del sujeto por DNS: <nodename>, IP Address: <node IP address>

¿Debería kubeadm al habilitar la opción de configuración serverTLSBootstrap al menos para que Aprobar el certificado del servidor sea algo fácil de hacer? ¿O incluso kubeadm podría hacer la aprobación también?

No estoy seguro de las implementaciones de seguridad, pero puede combinar serverTLSBootstrap con este operador para aprobar automáticamente las CSR https://github.com/kontena/kubelet-rubber-stamp

¿Debería kubeadm al habilitar la opción de configuración serverTLSBootstrap al menos para que Aprobar el certificado del servidor sea algo fácil de hacer? ¿O incluso kubeadm podría hacer la aprobación también?

kubeadm no puede realizar la aprobación porque kubeadm no es un demonio. tiene que implementar un controlador / operador que gestione eso para el usuario. quizás en el futuro.

la API de certificados debería pasar a GA pronto y, con suerte, tendremos una mejor manera de gestionar esto en k8s. por favor mira:
https://github.com/kubernetes/enhancements/issues/267
(pero no tengo claro con qué vamos a terminar ...)

también tenemos ideas alternativas. pero si todo esto está tratando de resolver el problema del servidor de métricas, también puede usar https://github.com/brancz/kube-rbac-proxy que puede realizar SAR en las solicitudes de MS al kubelet. lamentablemente esto aún no está documentado de nuestro lado:
https://github.com/kubernetes/kubeadm/issues/1602

@ neolit123 Al menos comencé a investigarlo cuando intentaba poner en marcha el servidor de métricas en kubeadm y los clústeres "de la manera difícil" para la experiencia de aprendizaje. Por supuesto, la forma más fácil era marcar MS con --kubelet-insecure-tls , pero tenía muchas ganas de ver cómo solucionarlo de forma segura y luego me interesé por el problema. 🙂

Por ahora, es bastante fácil para mí agregar la bandera serverTLSbootstrap a la configuración de kubelet y aprobar manualmente los certificados. Sin embargo, he notado una desventaja, que es que no puede interactuar completamente con los pods en el nodo hasta que apruebe el certificado. (kubectl exec no puede ejecutar el comando en los pods que se ejecutan en un nodo antes de la aprobación, por ejemplo)

También seguiré el tema de las mejoras. Gracias.

Es realmente triste que con kubeadm, que parece lo suficientemente maduro, el resultado listo para usar para kubeletet cert sea autofirmado y muchas personas eligen kubelet-insecure-tls para el servidor de métricas en lugar de hacer las cosas correctamente, etc. :(

es un problema complicado.

por favor, inténtalo:
https://github.com/kontena/kubelet-rubber-stamp
o
https://github.com/brancz/kube-rbac-proxy
como soluciones

es un problema complicado.

por favor, inténtalo:
https://github.com/kontena/kubelet-rubber-stamp
o
https://github.com/brancz/kube-rbac-proxy
como soluciones

En realidad, https://github.com/kontena/kubelet-rubber-stamp funciona bastante bien e imo parece ser una solución más correcta en lugar de proxy.

Paso 1:
Agregar
serverTLSBootstrap: true al final de cada /var/lib/kubelet/config.yaml para la reconfiguración de kubelets y no olvide aplicar la configuración (o simplemente reiniciarlos)

Paso 2:
Implementar sello de goma de kubelet

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

Paso 3:
Edite la implementación del servidor de métricas y elimine --kubelet-insecure-tls

Resultado:

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

Oye, solo para agregar a eso @vainkop
Durante su kubeadm init inicial para crear el clúster, también debería poder pasar un archivo de objeto de API de KubeletConfiguration para establecer el serverTLSBootstrap

`` `kubeadm-config.yaml
apiVersion: kubeadm.k8s.io/v1beta2
kind: ClusterConfiguration

...

apiVersion: kubelet.config.k8s.io/v1beta1
tipo: KubeletConfiguration
serverTLSBootstrap: verdadero

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

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

To get the CSRs

kubectl obtener csr
NOMBRE EDAD NOMBRE DEL SEÑOR CONDICIÓN DEL SOLICITANTE
csr-2qkdw 2m1s kubernetes.io/kube-apiserver-client-kubelet system: bootstrap : fcufbo Approved, Emitido
csr-9wvgt 114s sistema kubernetes.io/kubelet-serving
csr-lz97v 4m58s kubernetes.io/kubelet-serving system: node : master-1 Pendiente
csr-rsdsp 4m59s kubernetes.io/kube-apiserver-client-kubelet system: node : master-1 Approved, Emitido
csr-wgxqs 4m49s kubernetes.io/kubelet-serving system: node : master-1 Pendiente

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.

certificado kubectl aprobar csr-ab123 # O implementar sello de goma!

kubectl obtener csr
NOMBRE EDAD NOMBRE DEL SEÑOR CONDICIÓN DEL SOLICITANTE
csr-9wvgt 3m kubernetes.io/kubelet-serving system: node : worker-1 Approved, Emitido
...
''

Otra cosa extraña parece suceder aquí por cierto, y es que el nodo maestro parece crear su CSR dos veces. (Al menos las dos veces que probé esto)

Pero como dice @nijave en un comentario anterior, no estoy seguro de cuáles son las implicaciones de seguridad de usar el sello de goma.

@allir , @vainkop hasta donde puedo ver, el sello de goma de kubelet solo verifica si el nombre común de la CSR coincide con el nombre del solicitante, pero no verifica si los nombres de host adicionales y las direcciones IP solicitadas por el kubelet son válidos. Esto significa que un atacante que tiene acceso al certificado de cliente de kubelet puede crear certificados para básicamente cualquier nombre de dominio o dirección IP. Todos los clientes configurados para confiar en la CA raíz aceptarán este certificado.
Por supuesto, validar el nombre de host y las direcciones IP que son válidas para un kubelet dado es difícil, ya que actualmente no existe una autoridad que pueda confirmar lo que un kubelet puede solicitar. Por ejemplo, usar el objeto de nodo en el servidor API no es suficiente porque los kubelets pueden actualizar el objeto sin límites.

Oye, solo para agregar a eso @vainkop
Durante su kubeadm init inicial para crear el clúster, también debería poder pasar un archivo de objeto de API de KubeletConfiguration para establecer el serverTLSBootstrap
kubeadm init --config=kubeadm-config.yaml
Luego, todos los kubelet se configurarán automáticamente usando la bandera serverTLSBootstrap .

O para una configuración de K8 existente que usa Ansible, puede ser:

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

+ reiniciar kubelets

Vaya, estoy muy contento de haber encontrado este problema, y ​​no soy el único que quiere hacerlo de la manera correcta. :)

Ahora permítanme compartir mis pensamientos sobre este tema (corríjanme si me equivoco en algún lugar) :

Primero mi visión del problema original:
Actualmente, kubeadm habilita la autenticación de webhook para todos los kubelets de forma predeterminada, por lo que kubelet está validando los certificados de cliente para las conexiones entrantes sin problemas, incluso si se especifica la opción --kubelet-insecure-tls .
Por otro lado, el servidor de métricas no tiene la oportunidad de verificar el certificado específico de kubelet porque está autofirmado en el nodo.

Posibles riesgos de usar --kubelet-insecure-tls para metrics-server:
Si bien los datos de kubelet están algo seguros y nunca se proporcionarán al servidor de métricas sin una autenticación de webhook exitosa.
En teoría, alguien puede comprometer la IP del servidor o el nombre de host y proporcionar estadísticas incorrectas. Pero para establecer las conexiones, metricserver utiliza una dirección IP y nombres de host especificados para el nodo a través de kube-apiserver, por lo que el atacante debe piratear primero el servidor API, el DNS o la dirección IP del nodo.

Poca observación:
El servidor de métricas no es un servicio único que accede directamente a los kubelets. Kube-apiserver también hace esto para leer los registros del contenedor o ejecutar el shell en ellos. La buena pregunta es ¿cómo se asegura kube-apiserver de establecer una conexión con el kubelet específico mientras no tiene ninguna información sobre la CA que emitió su certificado?
¿No se comporta igual que el servidor de métricas con la opción --kubelet-insecure-tls en este caso?

Solución posible:
Hoy en día, los webhooks y la agregación de API son bastante populares en Kubernetes. Todos ellos se comportan de manera similar, generando su propia CA y su par crt / key. El hash de CA también se almacena en un recurso específico para proporcionar a kube-apiserver información sobre en qué certificado puede confiar.

Por ejemplo:

  • APIServices está almacenando el hash de CA relacionado en su recurso apiservices.apiregistration.k8s.io :

    spec:
    caBundle: <ca-hash>
    
  • Los webhooks almacenan hash de CA relacionados en sus recursos validatingwebhookconfigurations.admissionregistration.k8s.io y mutatingwebhookconfigurations.admissionregistration.k8s.io :

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

Para mí, es bastante obvio que cada recurso de nodo debe tener caBundle similares en su spec , donde los kubelets pueden registrar su propia CA para servir usando su certificado de cliente:

spec:
  caBundle: <ca-hash>

Tanto metris-server como kube-apiserver deben usar estos certificados para verificar y confiar en la conexión a los kubelets.

gracias a @ kfox1111 que expresó una idea similar anteriormente https://github.com/kubernetes/kubeadm/issues/1223#issuecomment -460854312

La buena pregunta es ¿cómo se asegura kube-apiserver de establecer una conexión con el kubelet específico mientras no tiene ninguna información sobre la CA que emitió su certificado?
¿No se comporta igual que el servidor de métricas con la opción --kubelet-insecure-tls en este caso?

Para responder a esta pregunta, puedo citar a @luxas aquí:

Correcto, no podemos hacer las conexiones desde el servidor api a los servidores de kubelet verificados, ya que cada kubelet tiene su propio certificado autofirmado. Podríamos considerar un flujo de aprobación manual wrt kubelet que sirva certificados en el futuro, pero eso no está asegurado de manera predeterminada en este momento.

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

espero que se pueda resolver algún día

[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

¿No tienes noticias de este número? También me interesaría tener una solución para esto.

estamos documentando soluciones alternativas aquí:
https://github.com/kubernetes/website/pull/27071
https://github.com/kubernetes/kubeadm/issues/1602

Podemos mantener este problema abierto, pero debido a la complejidad de requerir implementar un firmante con kubeadm de forma predeterminada, es poco probable que hagamos este cambio pronto.

¿Fue útil esta página
0 / 5 - 0 calificaciones