Mejorando la seguridad de los microservicios con Istio

¡Hola! Mi nombre es Ilya, trabajo como ingeniero DevOps en el equipo de desarrollo. Utilizamos activamente un enfoque de microservicio y, debido a los detalles de nuestro trabajo, la seguridad de la comunicación entre servicios es importante para nosotros. En este artículo, quiero describir cómo funciona Istio y mostrarle cómo usar algunas de sus características de seguridad, por ejemplo. Espero que esto sea útil para resolver sus problemas. ¡Disfruta leyendo!







¿Por qué necesito una red de servicio?



La malla de servicios, en este caso Istio, es un enlace para todo lo que se requiere para administrar y configurar la comunicación entre servicios: enrutamiento, autenticación, autorización, rastreo, control de acceso y mucho más. Y aunque hay muchas bibliotecas de código abierto para implementar estas funciones directamente en el código de servicio, con Istio puede obtener todo lo mismo sin agregar nada al servicio en sí.



Componentes 



Artículo escrito para istio 1.6


Acerca de los cambios
Istio , . , , - , , . , , Istio 1.4   v1beta1 , Istio RBAC. 1.5 , Pilot, Galley Citadel istiod. - . .



Istio se divide lógicamente en un plano de datos y un plano de control.

El plano de datos es una colección de servidores proxy (Envoy) agregados al pod en forma de sidecars. Estos proxies proporcionan y controlan toda la comunicación de red entre microservicios y se configuran desde el plano de control.



El plano de gestión (istiod) proporciona descubrimiento de servicios, configuración y gestión de certificados. Convierte objetos Istio en configuraciones que Envoy comprende y los distribuye en el plano de datos.







Componentes de malla de servicio Istio



Puede agregar un enviado al pod de la aplicación, ya sea manualmente o configurando la adición automática utilizando el webhook Mutating Admission, que Istio agrega durante su instalación. Para hacer esto, coloque la etiqueta istio-injection = enabled en el espacio de nombres requerido.



Además del proxy sidecar con enviado, Istio agregará un contenedor init especial al pod que redirigirá el tráfico de combate al contenedor con enviado. ¿Pero cómo se logra esto? En este caso, no hay magia, y esto se implementa instalando reglas adicionales de iptables en el espacio de nombres de red del pod.



Sobre el consumo de recursos
, 100 Istio ~2-3 , envoy 40 , CPU 5%-7% pod.



Echemos un vistazo práctico a cómo un sidecar captura el tráfico entrante y saliente de un contenedor. Para hacer esto, echemos un vistazo al espacio de red de algún pod con el sidecar agregado por Istio con más detalle. 



Soporte de demostración
Kubernetes Istio. 

Kubernetes minikube:



Linux:
curl -Lo minikube https://storage.googleapis.com/minikube/releases/latest/minikube-linux-amd64 && chmod +x minikube
sudo mkdir -p /usr/local/bin/
sudo install minikube /usr/local/bin/

minikube start --driver=<driver_name> // --driver=none        .




MacOS:
brew install minikube
minikube start --driver=<driver_name>






Istio demo :



curl -L https://istio.io/downloadIstio | sh -
cd istio-1.6.3
export PATH=$PWD/bin:$PATH
istioctl install --set profile=demo


: productpage details. Istio .



kubectl label namespace default istio-injection=enabled
kubectl apply -f samples/bookinfo/platform/kube/bookinfo.yaml








Veamos una lista de contenedores para la aplicación de página de producto:



kubectl -n default get pods productpage-v1-7df7cb7f86-ntwzz -o jsonpath="{.spec['containers','initContainers'][*].name}"
productpage 
istio-proxy 
istio-init


Además de la página del producto en sí, el sidecar istio-proxy (el mismo enviado) y el contenedor init istio-init funcionan en el pod.



Puede ver los nombres de pod de las reglas de iptables configuradas en el espacio utilizando la utilidad nsenter. Para hacer esto, necesitamos descubrir el pid del proceso del contenedor:



docker inspect k8s_productpage --format '{{ .State.Pid }}'
16286


Ahora podemos ver las reglas de iptables establecidas en este contenedor.







Se puede ver que casi todo el tráfico entrante y saliente ahora es interceptado y redirigido a los puertos en los que el enviado ya lo está esperando. 



Habilitar el cifrado de tráfico mutuo



Los objetos Policy y MeshPolicy se han eliminado de istio 1.6. En cambio, se sugiere usar el objeto PeerAuthentication


Istio le permite cifrar todo el tráfico entre contenedores, y las aplicaciones mismas ni siquiera sabrán que se están comunicando a través de tls. Esto lo hace el propio Istio fuera de la caja con solo un manifiesto, ya que los certificados de cliente ya están montados en servidores proxy de sidecar. 



El algoritmo es como sigue: 



  1. Los servidores proxy del lado del cliente y del lado del servidor se autentican entre sí antes de enviar solicitudes;

  2. Si la verificación es exitosa, el proxy del cliente cifra el tráfico y lo envía al proxy del servidor;

  3. El lado del servidor proxy descifra el tráfico y lo redirige localmente al servicio de destino real.



Puede habilitar mTLS en diferentes niveles:



  • A nivel de toda la red;

  • En el nivel del espacio de nombres;

  • A nivel de una cápsula específica. 



Modos de funcionamiento:



  • PERMISO: se permite el tráfico de texto cifrado y sin formato;

  • ESTRICTO: solo se permite TLS;

  • DESACTIVAR: solo se permite texto sin formato.



Veamos el servicio de detalles del pod de la página del producto usando curl sin TLS habilitado y veamos qué viene con los detalles usando tcpdump:



Solicitud:







Volcado de tráfico:







Todo el cuerpo y los encabezados son perfectamente legibles en texto plano.



Vamos a encender tls. Para hacer esto, cree un objeto de tipo PeerAuthentication en el espacio de nombres con nuestros pods.



apiVersion: security.istio.io/v1beta1
kind: PeerAuthentication
metadata:
  name: default
  namespace: default
spec:
  mtls:
    mode: STRICT


Vuelva a ejecutar la solicitud desde la página del producto para ver los detalles y ver qué obtenemos: el







tráfico está cifrado



Iniciar sesión



Los objetos ClusterRbacConfig, ServiceRole y ServiceRoleBinding se han eliminado junto con la implementación de la nueva política de autorización. Se sugiere utilizar el objeto AuthorizationPolicy en su lugar.


Mediante políticas de autorización, Istio puede configurar una aplicación para acceder a otra. Además, a diferencia de las políticas de red Kubernetes puras, esto funciona en el nivel L7. Por ejemplo, para el tráfico http, puede controlar con precisión los métodos y las rutas de la solicitud.



Como vimos en el ejemplo anterior, de forma predeterminada, el acceso está abierto a todos los pods en todo el clúster.



Ahora deshabilitaremos todas las actividades en el espacio de nombres predeterminado usando el siguiente archivo yaml:



apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
  namespace: default
spec:
  {}


E intente acceder al servicio de detalles:



curl details:9080
RBAC: access denied


Genial, ahora nuestra solicitud está fallando.



Y ahora configuremos el acceso para que solo se procese una solicitud GET y solo a lo largo de la ruta / detalles, y todas las demás solicitudes sean rechazadas. Hay varias opciones para esto:



  • Se puede configurar para pasar solicitudes con encabezados específicos;

  • Por la cuenta de servicio de la aplicación;

  • Por dirección IP saliente;

  • Por espacio de nombres saliente;

  • Por reclamos en el token JWT.



Lo más fácil de mantener es configurar el acceso a la cuenta de servicio de la aplicación, ya que no se requiere configuración previa porque la aplicación de demostración bookinfo ya viene con la cuenta de servicio creada y montada.



Para usar políticas de autorización basadas en cuentas de servicio, debe habilitar la autenticación mutua de TLS.


Configurar una nueva política de acceso:



apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
  name: "details-viewer"
  namespace: default
spec:
  selector:
    matchLabels:
      app: details
  rules:
  - from:
    - source:
        principals: ["cluster.local/ns/default/sa/bookinfo-productpage"]
    to:
    - operation:
        methods: ["GET"]
        paths: ["/details/*"]


Y tratamos de llegar de nuevo:



root@productpage-v1-6b64c44d7c-2fpkc:/# curl details:9080/details/0
{"id":0,"author":"William Shakespeare","year":1595,"type":"paperback","pages":200,"publisher":"PublisherA","language":"English","ISBN-10":"1234567890","ISBN-13":"123-1234567890"}


Todo esta funcionando. Probemos otros métodos y formas:



root@productpage-v1-6b64c44d7c-2fpkc:/# curl -XPOST details:9080/details/0
RBAC: access denied
root@productpage-v1-6b64c44d7c-2fpkc:/# 
root@productpage-v1-6b64c44d7c-2fpkc:/# curl -XGET details:9080/ping
RBAC: access denied


Conclusión



En conclusión, observo que las oportunidades consideradas son solo una fracción de lo que Istio puede hacer. Desde el primer momento, recibimos y configuramos la encriptación y autorización del tráfico entre servicios, aunque a costa de agregar componentes adicionales y, por lo tanto, de un consumo de recursos adicional. 



¡Gracias a todos!



All Articles