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
- AWS (Amazon Web Services):
-
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.