Exposing Services in Kubernetes

¡Apoya a HackTricks y obtén beneficios!

Existen diferentes formas de exponer servicios en Kubernetes para que tanto los puntos finales internos como los externos puedan acceder a ellos. Esta configuración de Kubernetes es bastante crítica ya que el administrador podría dar acceso a atacantes a servicios a los que no deberían poder acceder.

Enumeración automática

Antes de comenzar a enumerar las formas en que K8s ofrece para exponer servicios al público, sepa que si puede listar los espacios de nombres, los servicios y los ingresos, puede encontrar todo lo expuesto al público con:

kubectl get namespace -o custom-columns='NAME:.metadata.name' | grep -v NAME | while IFS='' read -r ns; do
    echo "Namespace: $ns"
    kubectl get service -n "$ns"
    kubectl get ingress -n "$ns"
    echo "=============================================="
    echo ""
    echo ""
done | grep -v "ClusterIP"
# Elimine el último '| grep -v "ClusterIP"' para ver también el tipo ClusterIP

ClusterIP

Un servicio ClusterIP es el servicio predeterminado de Kubernetes. Le proporciona un servicio interno en su clúster al que otras aplicaciones dentro de su clúster pueden acceder. No hay acceso externo.

Sin embargo, esto se puede acceder utilizando el proxy de Kubernetes:

kubectl proxy --port=8080

Ahora, puede navegar a través de la API de Kubernetes para acceder a los servicios utilizando este esquema:

http://localhost:8080/api/v1/proxy/namespaces/<NAMESPACE>/services/<SERVICE-NAME>:<PORT-NAME>/

Por ejemplo, podría usar la siguiente URL:

http://localhost:8080/api/v1/proxy/namespaces/default/services/my-internal-service:http/

para acceder a este servicio:

apiVersion: v1
kind: Service
metadata:  
  name: my-internal-service
spec:
  selector:    
    app: my-app
  type: ClusterIP
  ports:  
  - name: http
    port: 80
    targetPort: 80
    protocol: TCP

Este método requiere que ejecute kubectl como un usuario autenticado.

NodePort

NodePort abre un puerto específico en todos los nodos (las VM), y cualquier tráfico que se envíe a este puerto se reenvía al servicio. Esta es una opción realmente mala por lo general.

Un ejemplo de especificación de NodePort:

apiVersion: v1
kind: Service
metadata:  
  name: my-nodeport-service
spec:
  selector:    
    app: my-app
  type: NodePort
  ports:  
  - name: http
    port: 80
    targetPort: 80
    nodePort: 30036
    protocol: TCP

Si no especifica el nodePort en el yaml (es el puerto que se abrirá) se usará un puerto en el rango 30000-32767.

LoadBalancer

Expone el servicio externamente usando el balanceador de carga del proveedor de la nube. En GKE, esto iniciará un balanceador de carga de red que le dará una única dirección IP que reenviará todo el tráfico a su servicio.

Debe pagar un LoadBalancer por servicio expuesto, lo que puede resultar costoso.

ExternalName

Los servicios de tipo ExternalName mapean un servicio a un nombre DNS, no a un selector típico como my-service o cassandra. Especifica estos servicios con el parámetro spec.externalName.

Esta definición de servicio, por ejemplo, asigna el servicio my-service en el espacio de nombres prod a my.database.example.com:

apiVersion: v1
kind: Service
metadata:
  name: my-service
  namespace: prod
spec:
  type: ExternalName
  externalName: my.database.example.com

Al buscar el host my-service.prod.svc.cluster.local, el servicio DNS del clúster devuelve un registro CNAME con el valor my.database.example.com. Acceder a my-service funciona de la misma manera que otros servicios, pero con la diferencia crucial de que la redirección ocurre a nivel de DNS en lugar de a través de la intermediación o el reenvío.

IPs externas

El tráfico que ingresa al clúster con la IP externa (como IP de destino), en el puerto del servicio, se enrutará a uno de los puntos finales del servicio. externalIPs no son administrados por Kubernetes y son responsabilidad del administrador del clúster.

En la especificación del servicio, se pueden especificar externalIPs junto con cualquiera de los ServiceTypes. En el siguiente ejemplo, "my-service" se puede acceder por clientes en "80.11.12.10:80" (externalIP:port)

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  selector:
    app: MyApp
  ports:
    - name: http
      protocol: TCP
      port: 80
      targetPort: 9376
  externalIPs:
    - 80.11.12.10

Ingress

A diferencia de todos los ejemplos anteriores, Ingress NO es un tipo de servicio. En cambio, se encuentra en frente de múltiples servicios y actúa como un "enrutador inteligente" o punto de entrada en su clúster.

Puede hacer muchas cosas diferentes con un Ingress, y hay muchos tipos de controladores de Ingress que tienen diferentes capacidades.

El controlador de ingreso predeterminado de GKE iniciará un balanceador de carga HTTP(S) para usted. Esto le permitirá hacer enrutamiento basado en ruta y subdominio a servicios de backend. Por ejemplo, puede enviar todo en foo.yourdomain.com al servicio foo, y todo bajo la ruta yourdomain.com/bar/ al servicio bar.

El YAML para un objeto Ingress en GKE con un balanceador de carga HTTP L7 podría verse así:

apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: my-ingress
spec:
  backend:
    serviceName:

Última actualización