Descripción general de la política de autorización

A diferencia de una aplicación monolítica que podría ejecutarse en un solo lugar, las apps de microservicios distribuidas en todo el mundo realizan llamadas a través de los límites de red. Esto significa que habrá más puntos de entrada a tus aplicaciones y más oportunidades de ataques maliciosos. Debido a que los Pods de Kubernetes tienen IP transitorias, las reglas de firewall tradicionales basadas en IP no son adecuadas para proteger el acceso entre las cargas de trabajo. En una arquitectura de microservicios, se necesita un nuevo enfoque para la seguridad. Basándose en funciones de seguridad como las cuentas de servicio de Kubernetes y las políticas de seguridad de Istio, Cloud Service Mesh proporciona aún más capacidades que te ayudarán a proteger tus aplicaciones.

En esta página, se proporciona a los operadores de aplicaciones una descripción general del recurso personalizado (CR) de AuthorizationPolicy. Las políticas de autorización te permiten habilitar el control de acceso en las cargas de trabajo en las capas de la aplicación (L7) y de transporte (L3/4). Configura políticas de autorización para especificar permisos: ¿qué puede hacer este servicio o usuario?

Políticas de autorización

Las solicitudes entre servicios de tu malla (y entre usuarios finales y servicios) se permiten de forma predeterminada. Usa el CR AuthorizationPolicy a fin de definir políticas detalladas para tus cargas de trabajo. Después de aplicar las políticas de autorización, Cloud Service Mesh las distribuye a los proxies de sidecar. A medida que se ingresan las solicitudes, el proxy de sidecar verifica las políticas de autorización para determinar si se debe permitir o rechazar la solicitud.

Alcance de la política

Puedes aplicar una política a toda la malla de servicios, a un espacio de nombres o a una carga de trabajo individual.

  • Para aplicar una política en toda la malla, especifica el espacio de nombres raíz, istio-system, en el campo metadata:namespace:

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "mesh-wide"
      namespace: istio-system
    spec:
    ...
    
  • Para aplicar una política a un espacio de nombres, especifica el espacio de nombres en el campo metadata:namespace:

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "currencyservice"
      namespace: currencyservice
    spec:
    ...
    
  • Para restringir una política a una carga de trabajo específica, incluye un campo selector.

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "frontend"
      namespace: demo
    spec:
      selector:
        matchLabels:
          app: frontend
       ...
    

Estructura básica

Una política de autorización incluye el alcance de la política, un action y una lista de rules:

  • Como se describió en la sección anterior, el alcance de la política puede ser la malla completa, un espacio de nombres o una carga de trabajo específica. Si lo incluyes, el campo selector especifica el destino de la política.

  • El campo action especifica si se debe ALLOW o DENY la solicitud. Si no especificas una acción, la acción se establecerá de forma predeterminada en ALLOW. Para mayor claridad, te recomendamos que siempre especifiques la acción. (Las políticas de autorización también admiten acciones AUDIT y CUSTOM).

  • Las rules especifican cuándo activar la acción.

    • El campo from en rules especifica las fuentes de la solicitud.

    • El campo to en rules especifica las operaciones de la solicitud.

    • El campo when especifica condiciones adicionales necesarias para aplicar la regla.

En el siguiente ejemplo:

  • La política se aplica a las solicitudes al servicio frontend en el espacio de nombres demo.

  • Las solicitudes se permiten cuando “hello:world” está en el encabezado de la solicitud; de lo contrario, se rechazan las solicitudes.

apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
  name: "hello-world"
  namespace: demo
spec:
  selector:
    matchLabels:
      app: frontend
  action: ALLOW
  rules:
  - when:
    - key: request.headers[hello]
      values: ["world"]

Control de acceso a la operación de solicitud

Puedes controlar el acceso a operaciones de solicitud específicas, como métodos HTTP o puertos TCP, si agregas una sección to en rules. En el siguiente ejemplo, solo los métodos HTTP GET y POST se permiten a currencyservice en el espacio de nombres demo.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: currencyservice
 namespace: demo
spec:
 selector:
   matchLabels:
     app: currencyservice
 action: ALLOW
 rules:
 - to:
   - operation:
       methods: ["GET", "POST"]

Control de acceso en la identidad autenticada

En los ejemplos anteriores, las políticas permiten solicitudes de cargas de trabajo no autenticadas. Si tienes habilitada la TLS mutua STRICT (mTLS), puedes restringir el acceso en función de la identidad de la carga de trabajo o el espacio de nombres al que pertenece la solicitud en la sección source.

  • Usa el campo principals o notPrincipal para controlar el acceso a nivel de la carga de trabajo.

  • Usa el campo namespaces o notNamespaces para controlar el acceso a nivel del espacio de nombres.

Todos los campos anteriores requieren que tengas habilitado mTLS STRICT. Si no puedes configurar STRICT mTLS, consulta Rechaza solicitudes de texto simple para obtener una solución alternativa.

Carga de trabajo identificada

En el siguiente ejemplo, las solicitudes a currencyservice solo se permiten desde el servicio frontend. Se rechazan las solicitudes a currencyservice desde otras cargas de trabajo.

apiVersion: "security.istio.io/v1beta1"
kind: "AuthorizationPolicy"
metadata:
  name: "currencyservice"
  namespace: demo
spec:
  selector:
    matchLabels:
      app: currencyservice
  action: ALLOW
  rules:
  - from:
    - source:
        principals: ["example-project-1234.svc.id.goog/ns/demo/sa/frontend-sa"]

Para especificar una cuenta de servicio, los principals de la autoridad certificadora de Cloud Service Mesh (CA de Mesh) y Certificate Authority Service (servicio de AC) deben tener el siguiente formato:

principals: ["PROJECT_ID.svc.id.goog/ns/NAMESPACE/sa/SERVICE_ACCOUNT_NAME"]

PROJECT_ID.svc.id.goog es el dominio de confianza para la CA de Mesh. Si usas la CA de Istio (antes conocida como Citadel), el dominio de confianza predeterminado es cluster.local.

Espacio de nombres identificado

En el siguiente ejemplo, se muestra una política que rechaza solicitudes si la fuente no es el espacio de nombres foo:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
 name: httpbin-deny
 namespace: foo
spec:
 selector:
   matchLabels:
     app: httpbin
     version: v1
 action: DENY
 rules:
 - from:
   - source:
       notNamespaces: ["foo"]

Coincidencia de valores

La mayoría de los campos de las políticas de autorización son compatibles con los siguientes esquemas de coincidencia:

  • Coincidencia exacta: coincidencia exacta de strings.
  • Coincidencia de comodines mediante el carácter comodín "*":
    • Coincidencia de prefijo: una string con un "*" final. Por ejemplo, "test.example.*" coincide con "test.example.com" o "test.example.com.cn".
    • Coincidencia de sufijo: una string con un "*" inicial. Por ejemplo, "*.example.com" coincide con "eng.example.com" o "test.eng.example.com".
  • Coincidencia de presencia: para especificar que un campo debe estar presente y no vacío, usa el formato fieldname: ["*"]. Esto es diferente a dejar un campo sin especificar, lo que significa que coincide con todo, incluido el vacío.

Existen algunas excepciones. Por ejemplo, los siguientes campos solo admiten coincidencia exacta:

  • El campo key en la sección when
  • Los ipBlocks en la sección source
  • El campo ports en la sección to

La siguiente política de ejemplo permite el acceso a las rutas de acceso con el prefijo /test/* o el sufijo */info:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: tester
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: ALLOW
  rules:
  - to:
    - operation:
        paths: ["/test/*", "*/info"]

Coincidencia de exclusión

Para hacer coincidir condiciones negativas como notValues en el campo when, notIpBlocks en el campo source, notPorts en el campo to, Cloud Service Mesh admite la coincidencia de exclusión. En el siguiente ejemplo, se requiere una solicitud válida principals, que se deriva de la autenticación JWT, si la ruta de la solicitud no es /healthz. Por lo tanto, la política excluye las solicitudes a la ruta de acceso /healthz de la autenticación de JWT:

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: disable-jwt-for-healthz
  namespace: default
spec:
  selector:
    matchLabels:
      app: products
  action: ALLOW
  rules:
  - to:
    - operation:
        notPaths: ["/healthz"]
    from:
    - source:
        requestPrincipals: ["*"]

Rechazo de solicitudes de texto sin formato

En Cloud Service Mesh, la mTLS automática está habilitada de forma predeterminada. Con la mTLS automática, un proxy de sidecar de cliente detecta automáticamente si el servidor tiene un sidecar. El sidecar del cliente envía mTLS a las cargas de trabajo con sidecars y envía texto sin formato a las cargas de trabajo sin sidecars. Para obtener la mejor seguridad, te recomendamos que habilites STRICT de mTLS.

Si no puedes habilitar mTLS con el modo STRICT para una carga de trabajo o un espacio de nombres, puedes hacer lo siguiente:

  • crear una política de autorización a fin de permitir el tráfico de forma explícita con namespaces o principals no vacíos, o
  • rechazar el tráfico con namespaces o principals vacíos.

Debido a que namespaces y principals solo se pueden extraer con una solicitud mTLS, estas políticas rechazan de manera efectiva el tráfico de texto simple.

La siguiente política rechaza la solicitud si el principal de la solicitud está vacío (como es el caso de las solicitudes de texto simple). La política permite las solicitudes si la principal no está vacía. El ["*"] significa una coincidencia no vacía y el uso con notPrincipals significa la coincidencia con el principal vacío.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: require-mtls
  namespace: NAMESPACE
spec:
  action: DENY
  rules:
  - from:
    - source:
        notPrincipals: ["*"]

Prioridad de la política de autorización

Puedes configurar políticas de autorización de ALLOW y DENY independientes, pero debes comprender la prioridad de la política y el comportamiento predeterminado para asegurarte de que las políticas hagan lo que deseas. En el siguiente diagrama, se describe la prioridad de la política.

prioridad de la política de autorización

En las políticas de ejemplo de las siguientes secciones, se ilustran algunos de los comportamientos predeterminados y las situaciones en las que pueden resultarte útiles.

No permitir nada

En el siguiente ejemplo, se muestra una política ALLOW que no coincide con nada. De forma predeterminada, si no hay otras políticas ALLOW, las solicitudes siempre se deniegan.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-nothing
spec:
  action: ALLOW

Se recomienda comenzar con la política No permitir nada y, luego, agregar más políticas ALLOW a fin de abrir más acceso a una carga de trabajo.

Rechaza todo el acceso

En el siguiente ejemplo, se muestra una política DENY que coincide con todo. Debido a que las políticas DENY se evalúan antes que las políticas ALLOW, todas las solicitudes se rechazan, incluso si hay una política ALLOW que coincida con la solicitud.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: deny-all
spec:
  action: DENY
  rules:
  - {}

Una política de rechazo total es útil si deseas inhabilitar de forma temporal todo el acceso a una carga de trabajo.

Permite todo el acceso

En el siguiente ejemplo, se muestra una política ALLOW que coincide con todo y permite el acceso completo a una carga de trabajo. La política Permitir todo hace que las otras políticas ALLOW no sean útiles porque siempre permite la solicitud.

apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
  name: allow-all
spec:
  action: ALLOW
  rules:
  - {}

Una política de permiso completo es útil si deseas exponer de forma temporal el acceso completo a una carga de trabajo. Si hay políticas de DENY, las solicitudes se podrían rechazar, ya que las políticas de DENY se evalúan antes que las políticas de ALLOW.

Prácticas recomendadas

  1. Crea una cuenta de servicio de Kubernetes para cada servicio y especifica la cuenta de servicio en el Deployment. Por ejemplo:

    apiVersion: v1
    kind: ServiceAccount
    metadata:
      name: frontend-sa
      namespace: demo
    ---
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: frontend
      namespace:demo
    spec:
      selector:
        matchLabels:
          app: frontend
      template:
        metadata:
          labels:
            app: frontend
        spec:
          serviceAccountName: frontend-sa
        ...
    
  2. Comienza con una política No permitir nada y agrega de forma incremental más políticas ALLOW a fin de obtener más acceso a las cargas de trabajo.

  3. Si usas JWT para tu servicio, haz lo siguiente:

    1. Crea una política DENY para bloquear las solicitudes no autenticadas, por ejemplo:

      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: requireJWT
        namespace: admin
      spec:
        action: DENY
        rules:
        -  from:
          - source:
              notRequestPrincipals: ["*"]
      
    2. Aplica una política No permitir nada.

    3. Define las políticas ALLOW para cada carga de trabajo. Para ver ejemplos, consulta Token JWT.

¿Qué sigue?

Obtén más información sobre las funciones de seguridad de Cloud Service Mesh:

Obtén más información sobre las políticas de autorización en la documentación de Istio: