Skip to main content

Cloud Platform Node Metadata

Un servidor de metadata en las clouds es un servicio que proporciona información específica sobre una instancia de máquina virtual (VM) o un entorno de ejecución. Se accede a él desde las VMs para obtener datos que son útiles para la configuración y operación de la propia instancia.

  • Información de la Instancia:

    • ID de la Instancia: Identificación única de la VM en la infraestructura de la cloud.
    • Tipo de la Instancia: Especificaciones de la máquina, como la familia de VM y el tamaño.
    • Zona de Disponibilidad: Información sobre la ubicación geográfica o zona donde la VM está ejecutándose.
    • Hostname: Nombre de la máquina o del host de la instancia.
  • Datos de Configuración:

    • Scripts de Inicialización: Scripts o comandos que deben ejecutarse cuando la instancia inicia.
    • Claves SSH: Claves públicas usadas para el acceso SSH a la instancia.
    • Tags y Labels: Tags y etiquetas que pueden usarse para identificación o clasificación de las VMs.
  • Credenciales Temporales:

    • Access Keys Temporales: Credenciales de acceso temporales para la API de la cloud, que permiten que la instancia se autentique y acceda a otros recursos.
    • Tokens de Identidad: Tokens para autenticación y autorización en servicios de la cloud.
  • Datos de Red:

    • Direcciones IP: IP pública y privada de la instancia.
    • Gateway de Red: Dirección del gateway para salida de la red.
    • DNS: Servidores DNS configurados para la instancia.
  • Personalización Dinámica:

    • Custom Data: Datos personalizados que pueden pasarse a la instancia en el momento de la creación y usados por el software o scripts para personalización.
    • User Data: Similar a custom data, puede contener scripts o comandos que se ejecutan durante el arranque de la instancia.
  • Información de Seguridad:

    • Identidad de la Instancia: Información sobre la identidad de la instancia para servicios como AWS IAM, Google Cloud IAM o Azure AD.
    • Certificados SSL/TLS: Certificados y claves usados para comunicación segura.
  • Ejemplos de Servidores de Metadata en las 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
  • Utilidad:

    • Automatización: Permite automatizar la configuración y gestión de VMs de forma dinámica.
    • Seguridad: Proporciona credenciales temporales e información de identidad de forma segura.
    • Flexibilidad: Permite que las instancias se ajusten dinámicamente a sus configuraciones y entorno operacional.

Estos servidores de metadata son fundamentales para la operación eficiente y segura de las VMs en la nube, proporcionando una forma centralizada y estandarizada de acceder a datos críticos de la instancia.

Cuando montamos un clúster Kubernetes a partir de VMs y no gestionados por la cloud, necesitamos preocuparnos por esta seguridad y evitar que pods que se ejecuten dentro de una VM consigan acceso a estos servidores.

Para mitigar esto debemos:

  • Garantizar que la cuenta usada por las instancias solo tenga los permisos necesarios, pero esto está fuera del alcance de Kubernetes.
  • Seguir el conjunto de recomendaciones de cada proveedor cloud, que también está fuera del alcance de Kubernetes, pero que es bueno conocer.

Lo que podemos hacer es bloquear utilizando Network Policies. Podemos bloquear todos y solo permitir lo que deseamos.

En nuestro entorno tenemos un master y un worker y como estamos usando gcloud vamos a intentar hacer el acceso al servidor metadata de gcloud directamente desde el nodo y desde dentro de un contenedor de un pod que estamos ejecutando.

# Vemos que conseguimos directamente del nodo obtener la imagen que 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

# Ejecutando el mismo comando en el contenedor del pod app1 también lo 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 esto sabiendo la IP y creando una network policy para denegar todo.

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
# Ya tenemos la IP

Ahora basta crear una regla permitiendo la salida a Internet, pero bloqueando la IP específica. Esta regla se aplicará a todos los pods del 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 la salida a Internet
except: # Menos esta 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

# Y el pod ya no tiene acceso
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

# Pero el nodo todavía lo tiene.
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#

Si necesitamos un pod que tenga acceso al servidor metadata de cloud creamos una regla específica para él, diciendo lo que puede acceder.

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

Observa que estamos aplicando dos reglas al mismo pod. Una para todos los pods incluyendo el que queremos liberar y otra liberando solo este. Con la unión entre estas reglas, la regla que permite tiene preferencia.