Volver a los microservicios junto con Istio. Parte 3

Volver a los microservicios junto con Istio. Parte 3

Nota de traducción.: Primera parte Este ciclo estuvo dedicado a familiarizarnos con las capacidades de Istio y su demostración en acción, la segunda — la enrutación altamente configurable y la gestión del tráfico de red. Ahora, hablaremos sobre seguridad: para demostrar las funciones básicas relacionadas, el autor utiliza el servicio de identidad Auth0, aunque de manera similar se pueden configurar otros proveedores.

Hemos configurado un clúster de Kubernetes en el que desplegamos Istio y un ejemplo de aplicación de microservicios de Análisis de Sentimientos, demostrando así las capacidades de Istio.

Con Istio, pudimos mantener un tamaño reducido de los servicios, ya que no necesitan implementar capas como reintentos (Retries), tiempos de espera (Timeouts), disyuntores automáticos (Circuit Breakers), trazado (Tracing), y monitoreo (Monitoring). Además, utilizamos técnicas avanzadas de prueba y despliegue: pruebas A/B, espejeo y despliegues canarios.

Volver a los microservicios junto con Istio. Parte 3

En este nuevo material, nos adentraremos en las capas finales en el camino hacia el valor de negocio: autenticación y autorización, ¡y en Istio es un placer completo!

Autenticación y autorización en Istio

Nunca hubiera creído que me inspiraría en autenticación y autorización. ¿Qué puede ofrecer Istio desde una perspectiva tecnológica para hacer de estos temas algo emocionante e incluso inspirador para ustedes?

La respuesta es sencilla: Istio transfiere la responsabilidad de estas funciones de sus servicios al proxy Envoy. Para cuando las solicitudes alcanzan los servicios, ya están autenticadas y autorizadas, por lo que solo queda escribir código útil para el negocio.

¿Suena bien? ¡Echemos un vistazo dentro!

Autenticación con Auth0

Usaremos Auth0 como servidor para la gestión de identidades y accesos, que tiene una versión de prueba, es intuitivo de usar y simplemente me gusta. Sin embargo, los mismos principios se pueden aplicar a cualquier otra implementación de OpenID Connect: KeyCloak, IdentityServer y muchos otros.

Para comenzar, vaya a Auth0 Portal con su cuenta, cree un inquilino (inquilino — una unidad lógica de aislamiento, vea más en la documentación — nota del traductor) ) y acceda a Aplicaciones > Aplicación por defecto, seleccionando Dominio, como se muestra en la captura de pantalla a continuación:

Volver a los microservicios junto con Istio. Parte 3

Especifique este dominio en el archivo resource-manifests/istio/security/auth-policy.yaml (fuente):

apiVersion: authentication.istio.io/v1alpha1
kind: Policy
metadata:
  name: auth-policy
spec:
  targets:
  - name: sa-web-app
  - name: sa-feedback
  origins:
  - jwt:
      issuer: "https://{YOUR_DOMAIN}/"
      jwksUri: "https://{YOUR_DOMAIN}/.well-known/jwks.json"
  principalBinding: USE_ORIGIN

Con un recurso así, Pilot (uno de los tres componentes básicos del Control Plane en Istio — nota del traductor) configura Envoy para autenticar las solicitudes antes de redirigirlas a los servicios: sa-web-app y sa-feedback. Al mismo tiempo, la configuración no se aplica a los Envoys del servicio sa-frontend, lo que nos permite dejar el frontend no autenticado. Para aplicar la política (Policy), ejecute el comando:

$ kubectl apply -f resource-manifests/istio/security/auth-policy.yaml
policy.authentication.istio.io "auth-policy" created

Regrese a la página y realice una solicitud — verá que finaliza con el estado 401 Unauthorized. Ahora redirigiremos a los usuarios del frontend a la autenticación con Auth0.

Autenticación de solicitudes con Auth0

Para autenticar las solicitudes del usuario final, es necesario crear una API en Auth0 que representará los servicios autenticados (reviews, details y ratings). Para crear la API, vaya a Auth0 Portal > APIs > Create API y complete el formulario:

Volver a los microservicios junto con Istio. Parte 3

La información importante aquí es Identifier, que más tarde utilizaremos en el script. Anótelo así:

  • Audience: {YOUR_AUDIENCE}

Los demás detalles necesarios se encuentran en el Auth0 Portal en la sección Applications — seleccione Test Application (creado automáticamente junto con la API).

Aquí anotaremos:

  • Dominio: {YOUR_DOMAIN}
  • Client Id: {YOUR_CLIENT_ID}

Desplácese hasta el campo de texto Test Application Allowed Callback URLs (URLs permitidos para el callback), en el que especificaremos la URL a la que debe enviarse la llamada después de que la autenticación haya concluido. En nuestro caso, es: http://{EXTERNAL_IP}/callback

Y para

Allowed Logout URLs (URLs permitidos para logout) agregue: http://{EXTERNAL_IP}/logout

Pasemos al frontend.

Actualización del frontend

Cambie a la rama

auth0 del repositorio [istio-mastery] . En esta rama, el código del frontend se ha modificado para redirigir a los usuarios a Auth0 para la autenticación y utilizar el token JWT en las solicitudes a los demás servicios. Esto se implementa de la siguiente manera (analyzeSentence() { fetch('/sentiment', { method: 'POST', headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${auth.getAccessToken()}` // Access Token }, body: JSON.stringify({ sentence: this.textField.getValue() }) }) .then(response => response.json()) .then(data => this.setState(data)); }App.js):

analyzeSentence() {
    fetch('\/sentiment', {
        method: 'POST',
        headers: {
            'Content-Type': 'application\/json',
            'Authorization': `Bearer ${auth.getAccessToken()}` \/\/ Token de Acceso
        },
        body: JSON.stringify({ sentence: this.textField.getValue() })
    })
        .then(response => response.json())
        .then(data => this.setState(data));
}

Para transferir el frontend a utilizar los datos del tenant en Auth0, abra sa-frontend/src/services/Auth.js y reemplace en él los valores que hemos anotado arriba (Auth.js):

const Config = {
    clientID: '{YOUR_CLIENT_ID}',
    domain:'{YOUR_DOMAIN}',
    audience: '{YOUR_AUDIENCE}',
    ingressIP: '{EXTERNAL_IP}' // Usado para redirigir después de la autenticación
}

La aplicación está lista. Introduzca su ID de Docker en los comandos a continuación al construir y desplegar los cambios realizados:

$ docker build -f sa-frontend/Dockerfile 
 -t $DOCKER_USER_ID/sentiment-analysis-frontend:istio-auth0 
 sa-frontend

$ docker push $DOCKER_USER_ID/sentiment-analysis-frontend:istio-auth0

$ kubectl set image deployment/sa-frontend 
 sa-frontend=$DOCKER_USER_ID/sentiment-analysis-frontend:istio-auth0

¡Pruebe la aplicación! Será redirigido a Auth0, donde necesitará iniciar sesión (o registrarse), después de lo cual será enviado de vuelta a la página desde donde se realizarán ya las solicitudes autenticadas. Si intenta ejecutar los comandos mencionados en las primeras partes del artículo con curl, obtendrá el código Código de estado 401, que indica que la solicitud no está autorizada.

Vamos a dar el siguiente paso: autorizar las solicitudes.

Autorización con Auth0

La autenticación nos permite entender quién es el usuario, pero para saber a qué tiene acceso, se requiere autorización. Istio también ofrece herramientas para esto.

Como ejemplo, crearemos dos grupos de usuarios (ver el esquema a continuación):

  • Usuarios (users) — con acceso solo a los servicios SA-WebApp y SA-Frontend;
  • Moderadores (moderators) — con acceso a los tres servicios.

Volver a los microservicios junto con Istio. Parte 3
Concepto de autorización

Para crear estos grupos, utilizaremos la extensión Auth0 Authorization y mediante Istio proporcionaremos diferentes niveles de acceso.

Instalación y configuración de Auth0 Authorization

En el portal de Auth0, vaya a extensiones (Extensions) e instale Auth0 Authorization. Después de la instalación, acceda a Authorization Extension, y allí a la configuración del tenant haciendo clic en la parte superior derecha y seleccionando la opción del menú adecuada (Configuration). Active los grupos (Groups) y haga clic en el botón para publicar la regla (Publish rule).

Volver a los microservicios junto con Istio. Parte 3

Creación de grupos

En Authorization Extension, vaya a Groups y cree un grupo Moderators. Como consideraremos a todos los usuarios autenticados como ordinarios, no hay necesidad de crear un grupo adicional para ellos.

Seleccione el grupo Moderators, haga clic en Add Members, agrega tu cuenta principal. Deja algunos usuarios sin ningún grupo para asegurarte de que su acceso esté prohibido. (Los nuevos usuarios se pueden crear manualmente a través de Auth0 Portal > Usuarios > Crear Usuario.)

Agrega Group Claim en el Access Token

Los usuarios han sido añadidos a grupos, sin embargo, esta información también debe reflejarse en los tokens de acceso. Para cumplir con OpenID Connect y al mismo tiempo devolver los grupos que necesitamos, el token requerirá agregar su custom claim. Se implementa a través de las reglas de Auth0.

Para crear una regla, ve al Portal de Auth0 a Reglas, haga clic en Crear Regla y selecciona una regla vacía de las plantillas.

Volver a los microservicios junto con Istio. Parte 3

Copia el código de abajo y guárdalo como una nueva regla Add Group Claim (namespacedGroup.js):

function (user, context, callback) {
    context.accessToken['https://sa.io/group'] = user.groups[0];
    return callback(null, user, context);
}

Nota: este código toma el primer grupo de usuario, definido en la Extensión de Autorización, y lo añade al access-token como custom claim (bajo su espacio de nombres, como requiere Auth0).

Regresa a la página Reglas y verifica que tienes dos reglas registradas en el siguiente orden:

  • auth0-authorization-extension
  • Add Group Claim

El orden es importante porque el campo de grupo recibe la regla de forma asíncrona auth0-authorization-extension y luego se añade como claim con la segunda regla. Como resultado, se obtiene el siguiente access-token:

{
 "https://sa.io/group": "Moderadores",
 "iss": "https://sentiment-analysis.eu.auth0.com/",
 "sub": "google-oauth2|196405271625531691872"
 // [recortado para claridad]
}

Ahora es necesario configurar el proxy Envoy para verificar el acceso del usuario, para lo cual el grupo será extraído del claim (https://sa.io/group) en el access-token devuelto. Este es el tema para la siguiente sección del artículo.

Configuración de autorización en Istio

Para que la autorización funcione, es necesario habilitar RBAC para Istio. Para esto, utilizaremos la siguiente configuración:

apiVersion: "rbac.istio.io/v1alpha1"
kind: RbacConfig
metadata:
  name: default
spec:
  mode: 'ON_WITH_INCLUSION'                     # 1
  inclusion:
    services:                                   # 2
    - "sa-frontend.default.svc.cluster.local"
    - "sa-web-app.default.svc.cluster.local"
    - "sa-feedback.default.svc.cluster.local" 

Explicaciones:

  • 1 — habilitamos RBAC solo para los servicios y namespaces enumerados en el campo Inclusion;
  • 2 — enumeramos la lista de nuestros servicios.

Aplicaremos la configuración con el siguiente comando:

$ kubectl apply -f resource-manifests/istio/security/enable-rbac.yaml
rbacconfig.rbac.istio.io/default creado

Ahora todos los servicios requieren control de acceso basado en roles (Role-Based Access Control). En otras palabras, el acceso a todos los servicios está prohibido y resultará en la respuesta RBAC: acceso denegado. Ahora permitimos el acceso a los usuarios autorizados.

Configuración de acceso para usuarios normales

Todos los usuarios deben tener acceso a los servicios SA-Frontend y SA-WebApp. Esto se implementa mediante los siguientes recursos de Istio:

  • ServiceRole — define los derechos que tiene el usuario;
  • ServiceRoleBinding — define a quién se aplica este ServiceRole.

Para los usuarios normales, permitimos el acceso a ciertos servicios (servicerole.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: regular-user
  namespace: default
spec:
  rules:
  - services: 
    - "sa-frontend.default.svc.cluster.local" 
    - "sa-web-app.default.svc.cluster.local"
    paths: ["*"]
    methods: ["*"]

Y a través de regular-user-binding aplicamos el ServiceRole a todos los visitantes de la página (regular-user-service-role-binding.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: regular-user-binding
  namespace: default
spec:
  subjects:
  - user: "*"
  roleRef:
    kind: ServiceRole
    name: "regular-user"

¿Significa "todos los usuarios" que los usuarios no autenticados también tendrán acceso al SA WebApp? No, la política verificará la validez del token JWT.

Aplicaremos las configuraciones:

$ kubectl apply -f resource-manifests/istio/security/user-role.yaml
servicerole.rbac.istio.io/regular-user creado
servicerolebinding.rbac.istio.io/regular-user-binding creado

Configuración de acceso para moderadores

Para los moderadores, queremos habilitar el acceso a todos los servicios (mod-service-role.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRole
metadata:
  name: mod-user
  namespace: default
spec:
  rules:
  - services: ["*"]
    paths: ["*"]
    methods: ["*"]

Pero queremos esos derechos solo para aquellos usuarios cuyos tokens de acceso contengan la afirmación https://sa.io/group con el valor Moderators (mod-service-role-binding.yaml):

apiVersion: "rbac.istio.io/v1alpha1"
kind: ServiceRoleBinding
metadata:
  name: mod-user-binding
  namespace: default
spec:
  subjects:
  - properties:
      request.auth.claims[https://sa.io/group]: "Moderators"
  roleRef:
    kind: ServiceRole
name: "mod-user" 

Aplicaremos las configuraciones:

$ kubectl apply -f resource-manifests/istio/security/mod-role.yaml
servicerole.rbac.istio.io/mod-user creado
servicerolebinding.rbac.istio.io/mod-user-binding creado

Debido al almacenamiento en caché en los envoy, puede tardar unos minutos en que las reglas de autorización surtan efecto. Después de eso, podrás verificar que los usuarios y moderadores tienen diferentes niveles de acceso.

Conclusión sobre esta parte

En serio: ¿alguna vez has visto un enfoque más sencillo, sin esfuerzo, escalable y seguro para la autenticación y autorización?

Solo se necesitaron tres recursos de Istio (RbacConfig, ServiceRole y ServiceRoleBinding) para lograr un control fino sobre la autenticación y la autorización del acceso de los usuarios finales a los servicios.

Además, hemos eliminado la preocupación sobre estos problemas de nuestros servicios en envoy, logrando:

  • reducción de la cantidad de código típico en el que pueden aparecer problemas de seguridad y errores;
  • disminución de las situaciones estúpidas en las que un endpoint quedó disponible externamente sin informar;
  • eliminación de la necesidad de actualizar todos los servicios cada vez que se añade un nuevo rol o permiso;
  • que los nuevos servicios se mantengan simples, seguros y rápidos.

Salida

Istio permite que los equipos enfoquen sus recursos en tareas importantes para el negocio, sin añadir sobrecargas a los servicios, volviéndolos a su estado de «micro».

El artículo (en tres partes) proporcionó conocimientos básicos y una guía práctica lista para comenzar a trabajar con Istio en proyectos reales.

P.D. del traductor

También puedes leer en nuestro blog:

Fuente: habr.com

Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS 🔥 Compra un hosting fiable para sitios web con protección contra DDoS, servidores VPS VDS | ProHoster