Pular para o conteúdo principal

Cloud Platform Node Metadata

Um servidor de metadata nas clouds é um serviço que fornece informações específicas sobre uma instância de máquina virtual (VM) ou um ambiente de execução. Ele é acessado a partir das VMs para obter dados que são úteis para a configuração e operação da própria instância.

  • Informações da Instância:

    • ID da Instância: Identificação única da VM na infraestrutura da cloud.
    • Tipo da Instância: Especificações da máquina, como a família de VM e o tamanho.
    • Zona de Disponibilidade: Informação sobre a localização geográfica ou zona onde a VM está rodando.
    • Hostname: Nome da máquina ou do host da instância.
  • Dados de Configuração:

    • Scripts de Inicialização: Scripts ou comandos que devem ser executados quando a instância inicia.
    • Chaves SSH: Chaves públicas usadas para acesso SSH à instância.
    • Tags e Labels: Tags e rótulos que podem ser usados para identificação ou classificação das VMs.
  • Credenciais Temporárias:

    • Access Keys Temporárias: Credenciais de acesso temporárias para a API da cloud, que permitem que a instância se autentique e acesse outros recursos.
    • Tokens de Identidade: Tokens para autenticação e autorização em serviços da cloud.
  • Dados de Rede:

    • Endereços IP: IP público e privado da instância.
    • Gateway de Rede: Endereço do gateway para saída da rede.
    • DNS: Servidores DNS configurados para a instância.
  • Customização Dinâmica:

    • Custom Data: Dados personalizados que podem ser passados à instância no momento da criação e usados pelo software ou scripts para personalização.
    • User Data: Similar ao custom data, pode conter scripts ou comandos que são executados durante o boot da instância.
  • Informações de Segurança:

    • Identidade da Instância: Informações sobre a identidade da instância para serviços como o AWS IAM, Google Cloud IAM ou Azure AD.
    • Certificados SSL/TLS: Certificados e chaves usados para comunicação segura.
  • Exemplos de Servidores de Metadata nas Clouds:

    • AWS (Amazon Web Services): http://169.254.169.254/latest/meta-data/
    • Google Cloud: http://169.254.169.254/computeMetadata/v1/
    • Azure: http://169.254.169.254/metadata/instance?api-version=2021-02-01
  • Utilidade:

    • Automação: Permite automatizar a configuração e o gerenciamento de VMs de forma dinâmica.
    • Segurança: Fornece credenciais temporárias e informações de identidade de forma segura.
    • Flexibilidade: Permite que as instâncias se ajustem dinamicamente às suas configurações e ambiente operacional.

Esses servidores de metadata são fundamentais para a operação eficiente e segura das VMs na nuvem, proporcionando uma maneira centralizada e padronizada de acessar dados críticos da instância.

Quando montamos um cluster Kubernetes a partir de VMs e não gerenciados pela cloud precisamos nos preocupar com essa segurança e evitar que pods que rodem dentro de uma VM consigam acesso a estes servidores.

Para mitigar isso devemos:

  • Garantir que a conta usada pelas instâncias somente tenham as permissões necessárias, mas isso está fora do escopo do Kubernetes.
  • Seguir o conjunto de recomendações de cada cloud provider que também está fora do escopo do Kubernetes, mas que é bom estar ciente.

O que podemos fazer é bloquear utilizando Network Policies. Podemos bloquear todos e somente permitir o que desejamos.

No nosso ambiente temos um master e um worker e como estamos usando o gcloud vamos tentar fazer o acesso gcloud server metadata direto do node e de dentro de um container de um pod que estamos rodando.

# Veja que conseguimos direto do node pegar a imagem que ele está usando
root@cks-master:~# curl "http://metadata.google.internal/computeMetadata/v1/instance/image" -H "Metadata-Flavor: Google"
projects/ubuntu-os-cloud/global/images/ubuntu-2004-focal-v20240808root@cks-master:~#

root@cks-master:~# k get pods
NAME READY STATUS RESTARTS AGE
app1 1/1 Running 0 6h58m
app2 1/1 Running 0 6h58m

# Executando o mesmo comando no container do pod app1 também conseguimos.
root@cks-master:~# k exec app1 -- curl "http://metadata.google.internal/computeMetadata/v1/instance/image" -H "Metadata-Flavor: Google"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
100 66 100 66 0 0 1946 0 --:--:--projects/ubuntu-os-cloud/global/images/ubuntu-2004-focal-v20240808 --:--:-- --:--:-- 2000

Podemos bloquear isso sabendo o ip e criando uma network policy para negar tudo.

root@cks-master:~# ping metadata.google.internal
PING metadata.google.internal (169.254.169.254) 56(84) bytes of data.
64 bytes from metadata.google.internal (169.254.169.254): icmp_seq=1 ttl=255 time=3.88 ms
64 bytes from metadata.google.internal (169.254.169.254): icmp_seq=2 ttl=255 time=3.72 ms
64 bytes from metadata.google.internal (169.254.169.254): icmp_seq=3 ttl=255 time=4.11 ms
64 bytes from metadata.google.internal (169.254.169.254): icmp_seq=4 ttl=255 time=4.21 ms
^C
--- metadata.google.internal ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3003ms
rtt min/avg/max/mdev = 3.718/3.978/4.208/0.192 ms
# Já temos o IP

Agora basta criar uma regra permitindo a saida para a internet, mas bloqueando o ip específico. Essa regra será aplicada em todos os pods do namespace.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: cloud-metadata-deny
namespace: default
spec:
podSelector: {}
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 0.0.0.0/0 # Liberando a saída para a Internet
except: # Menos esse IP
- 169.254.169.254/32
root@cks-master:~/default# kubectl apply -f np-deny-node-metadata.yaml
networkpolicy.networking.k8s.io/cloud-metadata-deny created

# E o pod não tem mais acesso
root@cks-master:~/default# k exec app1 -- curl "http://metadata.google.internal/computeMetadata/v1/instance/image" -H "Metadata-Flavor: Google"
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
0 0 0 0 0 0 0 0 --:--:-- 0:00:04 --:--:-- 0^C

# Mas o node ainda tem.
root@cks-master:~/default# curl "http://metadata.google.internal/computeMetadata/v1/instance/image" -H "Metadata-Flavor: Google"
projects/ubuntu-os-cloud/global/images/ubuntu-2004-focal-v20240808root@cks-master:~/default#

Se precisamos de um pod que tenha acesso ao cloud metadata server criamos uma regra específica para ele, dizendo o que ele pode acessar.

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: cloud-metadata-allow
namespace: default
spec:
podSelector:
matchLabels:
role: metadata-accessor # Liberar o pod com essa label
policyTypes:
- Egress
egress:
- to:
- ipBlock:
cidr: 169.254.169.254/32 # Estamos liberando esse IP

Observe que estamos aplicando duas regras ao mesmo pod. Uma para todos os pods incluindo o que queremos liberar e outra liberando somente este. Com a união entre essas regras, a regra que permite possui preferência.