Kubeadm: usar certificados de serviço kubelet assinados

Criado em 9 nov. 2018  ·  38Comentários  ·  Fonte: kubernetes/kubeadm

Este é um RELATÓRIO DE BUGS ou PEDIDO DE RECURSO?

/ tipo bug

Abrindo o lado kubeadm para este problema no servidor de métricas

Versões

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

Meio Ambiente :

  • Versão do 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"}
  • Provedor de nuvem ou configuração de hardware :
    Algum
  • SO (por exemplo, de / etc / os-release):
    Algum
  • Kernel (por exemplo, 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
  • Outros :

O que aconteceu?

kubeadm cria certificados em /var/lib/kubelet/pki/kubelet.* assinados com um CA diferente daquele em /etc/kubernetes/pki/ca.pem

O que você esperava que acontecesse?

Como resultado, alguns aplicativos como o servidor de métricas não podem coletar estatísticas de um kubelet seguro porque o kubelet tem certificados assinados por um ca diferente do (s) mestre (s) K8s

Amostra de erro:

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]

Como reproduzi-lo (o mais mínimo e precisamente possível)?

Instale o metrics-server em execução:

registros do $ kubectl -n kube-system

Mais alguma coisa que precisamos saber?

Mais um pouco de fundo aqui

Também há etapas que segui para corrigir o problema.


editar: neolit123

o problema aqui é que o certificado de serviço é autoassinado por padrão:
consulte https://github.com/kubernetes/website/pull/27071 para atualização da documentação.

aresecurity help wanted kinbug kinfeature lifecyclfrozen prioritimportant-longterm

Comentários muito úteis

vamos resumir o problema:

conforme descrito por @anitgandhi :
https://github.com/kubernetes/kubeadm/issues/1223#issuecomment -454572577

o problema com o kubeadm aqui é que não estamos passando alguns sinalizadores para o kubelet:

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

sem esses sinalizadores, o padrão do kubelet é a autoassinatura do certificado de veiculação quando é executado pela primeira vez, o que pode ser verificado com:

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

com um certificado autoassinado em vez de certificado assinado pelo cluster CA ( /etc/kubernetes/ca.crt ), implantações como o servidor de métricas não podem eliminar o kubelet, porque o certificado SAN autoassinado incluirá apenas DNS:hostname .

soluções possíveis:
A) implementar o canto de um novo par kubelet.crt/key , de preferência sob /var/lib/kubelet/pki e definindo os sinalizadores de kubelet extras --tls-cert-file , --tls-private-key-file .

B) documento significa habilitar isso sob demanda de forma semelhante a como @ raravena80 fez aqui: https://stackoverflow.com/questions/53212149/x509-certificate-signed-by-unknown-authority-kubeadm/53218524#53218524
exceto, possivelmente, usando comandos Kubernetes CSRs / kubeadm.

C) conforme comentado por @alexbrand

Se possível, acho que devemos usar os recursos de inicialização TLS integrados ao kubelet para solicitar / rotacionar certificados de serviço.

D)?

@ kubernetes / sig-cluster-lifecycle
para mim, isso parece no espaço entre bug / recurso.

Veja também:
https://github.com/kubernetes/community/pull/602/files

Todos 38 comentários

@ raravena80 Não tenho conhecimento de nenhum certificado criado pelo kubeadm sob /var/lib/kubelet/pki/ .. você poderia gentilmente fornecer mais informações? por exemplo, arquivos de configuração kubeadm, etapas para criar o cluster

@fabriziopandini Não tenho certeza se os certificados são criados pelo kubeadm, mas o procedimento geral é descrito aqui .

Esta é a aparência do conteúdo do diretório:

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#

Eles são kubelet.crt e kubelet.key arquivos criados pelo kubelet na primeira vez que carrega?

@ raravena80 obrigado pelo esclarecimento
Provavelmente não tenho o contexto completo aqui, então deixo espaço para outras pessoas responderem.

Apenas uma nota lateral (pode ser que possa ajudar)
O Kubeadm já cria um certificado denominado apiserver-kubelet-client para permitir que o servidor API se comunique com segurança com os kubelets; é assinado por ca e vinculado às regras RBAC necessárias.

/ assign @liztio

Acho que isso é para pré-gerar certificados de servidor do kubelet. Tentei usar os sinalizadores Kubelet para bootstrap do servidor TLS e rodar certificados de servidor, infelizmente não consegui fazer o Kubelet solicitar um certificado de servidor para si mesmo usando o token de bootstrap. O Kubelet acaba voltando ao seu comportamento padrão para certificados de servidor, que é gerar um certificado autoassinado.

Até onde sei, agora a única maneira de contornar isso é gerar certificados de servidor do Kubelet fora da banda e colocá-los em um caminho determinístico e o kubelet (configurado pelo kubeadm) irá pegá-lo e definir alguns sinalizadores de kubelet de acordo ; referência: https://kubernetes.io/docs/reference/command-line-tools-reference/kubelet-tls-bootstrapping/#client -and-serving-certificates

O apiserver-kubelet-client é o certificado do cliente que o servidor API apresentará a um kubelet, mas o kubelet está configurado para confiar em clientes assinados pela 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

É a identidade do kubelet como um servidor apresentado que precisa ser assinado pelo CA k8s, o que leva à questão original.

Há também algumas discussões relevantes no final deste tópico: https://github.com/kubernetes/kubeadm/issues/118

Acho que o kubeadm pode ter que adicionar um aprovador de CSR para solicitações de certificado de servidor com um token de inicialização válido, assim como faz para solicitações de certificado de cliente.

Que tal fazer com que o kubelet carregue seu ca autoassinado para um configmap em algum lugar? o plugin nodeadmission poderia restringi-lo apenas ao seu próprio configmap. metrics-server pode usá-lo para contatar o nó.

Alguma ideia sobre isso?

Se possível, acho que devemos usar os recursos de inicialização TLS integrados ao kubelet para solicitar / rotacionar certificados de serviço.

@alexbrand eu concordo com isso

A inicialização Kubelet TLS só gera certificados de cliente por qualquer 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.

E o kubeadm já faz isso. Talvez esta seja uma solicitação de recurso do kubelet?

vamos resumir o problema:

conforme descrito por @anitgandhi :
https://github.com/kubernetes/kubeadm/issues/1223#issuecomment -454572577

o problema com o kubeadm aqui é que não estamos passando alguns sinalizadores para o kubelet:

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

sem esses sinalizadores, o padrão do kubelet é a autoassinatura do certificado de veiculação quando é executado pela primeira vez, o que pode ser verificado com:

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

com um certificado autoassinado em vez de certificado assinado pelo cluster CA ( /etc/kubernetes/ca.crt ), implantações como o servidor de métricas não podem eliminar o kubelet, porque o certificado SAN autoassinado incluirá apenas DNS:hostname .

soluções possíveis:
A) implementar o canto de um novo par kubelet.crt/key , de preferência sob /var/lib/kubelet/pki e definindo os sinalizadores de kubelet extras --tls-cert-file , --tls-private-key-file .

B) documento significa habilitar isso sob demanda de forma semelhante a como @ raravena80 fez aqui: https://stackoverflow.com/questions/53212149/x509-certificate-signed-by-unknown-authority-kubeadm/53218524#53218524
exceto, possivelmente, usando comandos Kubernetes CSRs / kubeadm.

C) conforme comentado por @alexbrand

Se possível, acho que devemos usar os recursos de inicialização TLS integrados ao kubelet para solicitar / rotacionar certificados de serviço.

D)?

@ kubernetes / sig-cluster-lifecycle
para mim, isso parece no espaço entre bug / recurso.

Veja também:
https://github.com/kubernetes/community/pull/602/files

Acho que algo entre as opções B + C deve ser feito, uma vez que muitos dos certificados de cliente de token de inicialização / lógica CSR kubelet + kubeadm teriam uma lógica comum a isso.

vamos resumir o problema:

conforme descrito por @anitgandhi :
# 1223 (comentário)

o problema com o kubeadm aqui é que não estamos passando alguns sinalizadores para o kubelet:

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

sem esses sinalizadores, o padrão do kubelet é a autoassinatura do certificado de veiculação quando é executado pela primeira vez, o que pode ser verificado com:

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

com um certificado autoassinado em vez de certificado assinado pelo cluster CA ( /etc/kubernetes/ca.crt ), implantações como o servidor de métricas não podem eliminar o kubelet, porque o certificado SAN autoassinado incluirá apenas DNS:hostname .

soluções possíveis:
A) implementar o canto de um novo par kubelet.crt/key , de preferência sob /var/lib/kubelet/pki e definindo os sinalizadores de kubelet extras --tls-cert-file , --tls-private-key-file .

B) documento significa habilitar isso sob demanda de forma semelhante a como @ raravena80 fez aqui: https://stackoverflow.com/questions/53212149/x509-certificate-signed-by-unknown-authority-kubeadm/53218524#53218524
exceto, possivelmente, usando comandos Kubernetes CSRs / kubeadm.

C) conforme comentado por @alexbrand

Se possível, acho que devemos usar os recursos de inicialização TLS integrados ao kubelet para solicitar / rotacionar certificados de serviço.

D)?

@ kubernetes / sig-cluster-lifecycle
para mim, isso parece no espaço entre bug / recurso.

Veja também:
https://github.com/kubernetes/community/pull/602/files

ótimo resumo @ neolit123 . Você sabe se isso vai escorregar para o próximo ciclo ou trabalho em andamento neste momento? Perguntar principalmente por causa do servidor de métricas que, em caso de implantação, deseja tê-lo;)

@randomvariable mencionou que há outra solução alternativa para isso.
pelas discussões até agora, estamos hesitantes em assinar o certificado de serviço de kubelet com o cluster CA. este tópico precisa de uma discussão mais aprofundada.

/ remove-help

porque a solução a implementar ainda não foi escolhida.

Qualquer movimento sobre isso? Estou correndo contra ele para oferecer suporte a recursos de escalonamento automático em um cluster implantado kubeadm.

A solução alternativa atual é desligar a verificação de CA do certificado kubelet.

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

não realmente, é bloqueado em propostas de design.
há uma série de soluções alternativas, mas o trabalho de documentá-las está paralisado:
https://github.com/kubernetes/kubeadm/issues/1602

--kubelet-insecure-tls

isso pode não ser ideal para todos os usuários.

Os problemas ficam obsoletos após 90 dias de inatividade.
Marque o problema como novo com /remove-lifecycle stale .
Problemas obsoletos apodrecem após 30 dias adicionais de inatividade e, eventualmente, fecham.

Se for seguro encerrar este problema agora, faça-o com /close .

Envie feedback para sig-testing, kubernetes / test-infra e / ou fejta .
/ lifecycle stale

/ ciclo de vida congelado

Encontrando esse problema exato ao criar o cluster v1.18.2 com kubeadm.

Ao configurar o metrics-server, ele não funciona sem definir o sinalizador kubelet-insecure-tls OU emitir certificados para kublet "fora da banda", assinando-o com o CA do kubernetes.

Pensei em reutilizar o certificado de cliente kubelet, mas é claro que ele é emitido para CN = system:node:nodename e não há SANs. E eu testei, o que, claro, muda o erro para indicar exatamente isso. O mesmo certificado poderia ser usado como servidor / cliente se tivesse o nome do nó como nome alternativo do sujeito? Mas estou supondo que seria mais adequado usar certificados separados para servidor / cliente?

/ remove-lifecycle congelado

/ ciclo de vida congelado

ele está congelado para que os bots não fechem o problema.

O mesmo certificado poderia ser usado como servidor / cliente se tivesse o nome do nó como nome alternativo do sujeito?

em teoria e a menos que o kubelet os valide - por exemplo, "o certificado do cliente não deve ter SANs".

Mas estou supondo que seria mais adequado usar certificados separados para servidor / cliente?

é prática comum usá-los separadamente, mesmo nos casos em que pareça evitável. é improvável que os mantenedores do kubelet / auth {z | n} mudem esse detalhe.

Ei. Diggin um pouco mais. A opção de configuração de Kubelet serverTLSBootstrap: true pode realmente criar um CSR para o certificado de serviço. Mas isso o deixa sem aprovação. O que pode estar ok?

Definir rotateCertificates: true e serverTLSBootsrap: true e, em seguida, aprovar o CSR para o certificado de serviço parece a maneira mais fácil de fazer aqui. O certificado de entrega que é solicitado / emitido é para O = system:nodes, CN = system:node:<nodename> com nomes alternativos de assunto para DNS: <nodename>, IP Address: <node IP address>

O kubeadm at deve habilitar a opção de configuração serverTLSBootstrap pelo menos para que a aprovação do certificado do servidor seja uma coisa fácil de fazer? Ou mesmo o kubeadm poderia fazer a aprovação também?

Ei. Diggin um pouco mais. A opção de configuração de Kubelet serverTLSBootstrap: true pode realmente criar um CSR para o certificado de serviço. Mas isso o deixa sem aprovação. O que pode estar ok?

Definir rotateCertificates: true e serverTLSBootsrap: true e, em seguida, aprovar o CSR para o certificado de serviço parece a maneira mais fácil de fazer aqui. O certificado de entrega que é solicitado / emitido é para O = system:nodes, CN = system:node:<nodename> com nomes alternativos de assunto para DNS: <nodename>, IP Address: <node IP address>

O kubeadm at deve habilitar a opção de configuração serverTLSBootstrap pelo menos para que a aprovação do certificado do servidor seja uma coisa fácil de fazer? Ou mesmo o kubeadm poderia fazer a aprovação também?

Não tenho certeza das implementações de segurança, mas você pode combinar serverTLSBootstrap com este operador para aprovar automaticamente os CSRs https://github.com/kontena/kubelet-rubber-stamp

O kubeadm at deve habilitar a opção de configuração serverTLSBootstrap pelo menos para que a aprovação do certificado do servidor seja uma coisa fácil de fazer? Ou mesmo o kubeadm poderia fazer a aprovação também?

kubeadm não pode fazer a aprovação porque kubeadm não é um daemon. ele tem que implantar um controlador / operador que gerencie isso para o usuário. talvez no futuro.

a API de certificados deve entrar em GA em breve e esperamos ter uma maneira melhor de gerenciar isso no k8s. por favor assista:
https://github.com/kubernetes/enhancements/issues/267
(ainda não está claro para mim com o que vamos acabar ...)

também temos ideias alternativas. mas se tudo isso está tentando resolver o problema do servidor métrico, você também pode usar https://github.com/brancz/kube-rbac-proxy que pode executar SAR nas solicitações MS para o kubelet. infelizmente, isso ainda não está documentado de nossa parte:
https://github.com/kubernetes/kubeadm/issues/1602

@ neolit123 Eu, pelo menos, comecei a olhar para isso ao tentar levantar o servidor de métricas no kubeadm e clusters "da maneira mais difícil" para experiência de aprendizagem. A maneira mais fácil, é claro, era sinalizar o MS com --kubelet-insecure-tls , mas eu realmente queria ver como consertar de forma segura e então fiquei interessado no problema. 🙂

Por enquanto, é fácil adicionar o sinalizador serverTLSbootstrap à configuração do kubelet e aprovar manualmente os certificados. No entanto, notei uma desvantagem disso, que é que você não pode interagir totalmente com os pods no nó até aprovar o certificado. (kubectl exec falha ao executar o comando em pods em execução em um nó antes da aprovação, por exemplo)

Vou acompanhar o problema de melhorias também. Obrigado.

É realmente triste que com o kubeadm, que parece maduro o suficiente, o resultado pronto para o kubeletet cert é ser autoassinado e muitas pessoas escolhem kubelet-insecure-tls para o servidor de métricas em vez de fazer as coisas corretamente & etc :(

é um problema complicado.

tente por favor:
https://github.com/kontena/kubelet-rubber-stamp
ou
https://github.com/brancz/kube-rbac-proxy
como soluções alternativas

é um problema complicado.

tente por favor:
https://github.com/kontena/kubelet-rubber-stamp
ou
https://github.com/brancz/kube-rbac-proxy
como soluções alternativas

Na verdade, https://github.com/kontena/kubelet-rubber-stamp funciona muito bem e imo parece ser uma solução mais correta em vez de proxy.

Passo 1:
Adicionar
serverTLSBootstrap: true ao final de cada /var/lib/kubelet/config.yaml para reconfiguração de kubelets e não se esqueça de aplicar a configuração (ou apenas reiniciá-los)

Passo 2:
Implantar kubelet-rubber-stamp

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

Etapa 3:
Edite a implantação do metrics-server e remova --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

Ei, só para adicionar a isso @vainkop
Durante o kubeadm init para criar o cluster, você também deve ser capaz de passar um arquivo de objeto da API KubeletConfiguration para definir o serverTLSBootstrap

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

...

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

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

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

To get the CSRs

kubectl get csr
NOME IDADE SIGNERNAME REQUESTOR CONDITION
csr-2qkdw 2m1s kubernetes.io/kube-apiserver-client-kubelet system: bootstrap : fcufbo aprovado, emitido
csr-9wvgt 114s kubernetes.io/kubelet-serving system: node : worker-1 Pendente
csr-lz97v 4m58s kubernetes.io/kubelet-serving system: node : master-1 Pendente
csr-rsdsp 4m59s kubernetes.io/kube-apiserver-client-kubelet system: node : master-1 aprovado, emitido
csr-wgxqs 4m49s kubernetes.io/kubelet-serving system: node : master-1 Pendente

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.

Aprovação do certificado kubectl csr-ab123 # OU implantar o carimbo de borracha!

kubectl get csr
NOME IDADE SIGNERNAME REQUESTOR CONDITION
csr-9wvgt 3m kubernetes.io/kubelet-serving system: node : worker-1 aprovado, emitido
...
`` `

Outra coisa estranha parece acontecer aqui, aliás, que o nó mestre parece criar seu CSR duas vezes. (Pelo menos as duas vezes que tentei)

Mas, como @nijave disse em um comentário acima, não tenho certeza de quais são as implicações de segurança do uso do carimbo de borracha.

@allir , pelo que posso ver, o kubelet-rubber-stamp apenas verifica se o nome comum do CSR corresponde ao nome do solicitante, mas não verifica se os nomes de host e endereços IP adicionais solicitados pelo kubelet são válidos. Isso significa que um invasor que tem acesso ao certificado do cliente kubelet pode criar certificados para basicamente qualquer nome de domínio ou endereço IP. Todos os clientes configurados para confiar na CA raiz aceitarão este certificado.
É claro que validar o nome do host e os endereços IP válidos para um determinado kubelet é difícil, pois atualmente não há autoridade que possa confirmar o que um kubelet tem permissão para solicitar. Por exemplo, usar o objeto de nó no servidor de API não é suficiente porque os kubelets podem atualizar o objeto sem limites.

Ei, só para adicionar a isso @vainkop
Durante o kubeadm init para criar o cluster, você também deve ser capaz de passar um arquivo de objeto da API KubeletConfiguration para definir o serverTLSBootstrap
kubeadm init --config=kubeadm-config.yaml
Então, todos os kubelet's serão automaticamente configurados usando a sinalização serverTLSBootstrap .

Ou para uma configuração K8s existente usando Ansible, pode 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

Nossa, estou tão feliz por ter encontrado esse problema, e não sou a única que quer fazer desse jeito certo. :)

Agora, deixe-me compartilhar minhas idéias sobre este problema (corrija-me se eu estiver em algum lugar errado) :

Primeiro, minha visão do problema original:
Atualmente, o kubeadm habilita a autenticação de webhook para todos os kubelets por padrão, portanto, o kubelet está validando os certificados do cliente para conexões de entrada sem problemas, mesmo se a opção --kubelet-insecure-tls for especificada.
Do outro lado, o servidor de métricas não tem oportunidade de verificar o certificado kubelet específico porque ele é autoassinado no nó.

Possíveis riscos de usar --kubelet-insecure-tls para metrics-server:
Embora os dados do kubelet estejam um tanto protegidos e nunca serão fornecidos ao servidor de métricas sem a autenticação bem-sucedida do webhook.
Em teoria, alguém pode comprometer o IP do servidor ou o nome do host e fornecer estatísticas erradas. Mas, para estabelecer as conexões, o metricserver está usando um endereço IP e nomes de host especificados para o nó via kube-apiserver, então o invasor precisa hackear o servidor API, DNS ou o endereço IP do nó primeiro.

Pequena observação:
O metrics-server não é um serviço único que acessa os kubelets diretamente. O Kube-apiserver também faz isso para ler os logs do contêiner ou executar o shell neles. A boa pergunta é como o kube-apiserver garante que está estabelecendo conexão com o kubelet específico enquanto não tem nenhuma informação sobre a CA que emitiu seu certificado?
Ele não se comporta da mesma forma que o servidor de métricas com a opção --kubelet-insecure-tls neste caso?

Solução possível:
Hoje em dia, os webhooks e a agregação de API são bastante populares no Kubernetes. Todos eles se comportam de maneira semelhante, gerando seu próprio CA e par crt / chave. O hash CA também é armazenado em um recurso específico para fornecer ao kube-apiserver informações sobre em qual certificado ele pode confiar.

Por exemplo:

  • APIServices estão armazenando hash CA relacionado em seu recurso apiservices.apiregistration.k8s.io :

    spec:
    caBundle: <ca-hash>
    
  • Os webhooks estão armazenando o hash CA relacionado em seus recursos validatingwebhookconfigurations.admissionregistration.k8s.io e mutatingwebhookconfigurations.admissionregistration.k8s.io :

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

Para mim, é bastante óbvio que cada recurso de nó deve ter caBundle semelhantes em seus spec , onde kubelets podem registrar sua própria CA para servir usando seu certificado de cliente:

spec:
  caBundle: <ca-hash>

Metris-server e kube-apiserver devem usar esses certificados para verificar e confiar na conexão com os kubelets.

obrigado a @ kfox1111 que expressou uma ideia semelhante anteriormente https://github.com/kubernetes/kubeadm/issues/1223#issuecomment -460854312

A boa pergunta é como o kube-apiserver garante que está estabelecendo conexão com o kubelet específico enquanto não tem nenhuma informação sobre a CA que emitiu seu certificado?
Ele não se comporta da mesma forma que o servidor de métricas com a opção --kubelet-insecure-tls neste caso?

Para responder a essa pergunta, posso citar @luxas aqui:

Certo, não podemos fazer as conexões do servidor api aos servidores kubelet verificadas, pois cada kubelet tem seu próprio certificado autoassinado. Podemos considerar um fluxo de aprovação manual kubelet servindo certificados no futuro, mas isso não é protegido por padrão no momento.

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

espero que possa ser resolvido algum dia

[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

Nenhuma notícia deste problema? Eu também estaria interessado em ter uma solução para isso.

estamos documentando soluções alternativas aqui:
https://github.com/kubernetes/website/pull/27071
https://github.com/kubernetes/kubeadm/issues/1602

podemos manter esse problema aberto, mas devido às complexidades de exigir a implantação de um signatário com o kubeadm por padrão, é improvável que façamos essa mudança tão cedo.

Esta página foi útil?
0 / 5 - 0 avaliações