Introducción general sobre la política de autorización

A diferencia de las aplicaciones monolíticas, que pueden ejecutarse en un solo lugar, las aplicaciones de microservicios distribuidas a nivel mundial hacen llamadas a través de límites de red. Esto significa que habrá más puntos de entrada en tus aplicaciones y más oportunidades para que se produzcan ataques maliciosos. Además, como los pods de Kubernetes tienen IPs transitorias, las reglas de cortafuegos tradicionales basadas en IPs no son adecuadas para proteger el acceso entre cargas de trabajo. En una arquitectura de microservicios, se necesita un nuevo enfoque de seguridad. Cloud Service Mesh se basa en funciones de seguridad como las cuentas de servicio de Kubernetes y las políticas de seguridad de Istio, y proporciona aún más funciones para ayudarte a proteger tus aplicaciones.

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

Políticas de autorización

Las solicitudes entre los servicios de tu malla (y entre los usuarios finales y los servicios) se permiten de forma predeterminada. Utiliza el AuthorizationPolicy CR para definir políticas granulares para tus cargas de trabajo. Después de aplicar las políticas de autorización, Cloud Service Mesh las distribuye a los proxies sidecar. Cuando las solicitudes llegan a una carga de trabajo, el proxy sidecar comprueba las políticas de autorización para determinar si se deben permitir o denegar.

Ámbito 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 concreta.

  • 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 el 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 ámbito de la política, un action y una lista de rules:

  • Como se ha descrito en la sección anterior, el ámbito de la política puede ser toda la malla, un espacio de nombres o una carga de trabajo específica. Si lo incluye, el campo selector especifica el objetivo de la política.

  • El campo action especifica si se debe ALLOW o DENY la solicitud. Si no especifica ninguna acción, se asignará el valor ALLOW de forma predeterminada. Para que no haya dudas, te recomendamos que especifiques siempre la acción. Las políticas de autorización también admiten las acciones AUDIT y CUSTOM.

  • El elemento rules especifica cuándo se debe activar la acción.

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

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

    • El campo when especifica las condiciones adicionales que se deben cumplir 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 deniegan.

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 en la operación de solicitud

Puedes controlar el acceso a operaciones de solicitudes específicas, como métodos HTTP o puertos TCP, añadiendo una sección to en rules. En el siguiente ejemplo, solo se permiten los métodos HTTP GET y POST en el currencyservice del 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 identidades autenticadas

En los ejemplos anteriores, las políticas permiten solicitudes de cargas de trabajo no autenticadas. Si tienes habilitado el STRICTTLS mutuo (mTLS), puedes restringir el acceso en función de la identidad de la carga de trabajo o del espacio de nombres desde el que se envía la solicitud en la sección source.

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

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

Para rellenar todos los campos anteriores, debes tener habilitado STRICT mTLS. Si no puedes configurar STRICT mTLS, consulta Rechazar solicitudes de texto sin formato para ver una solución alternativa.

Carga de trabajo identificada

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

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, el principals de la autoridad de certificación de Cloud Service Mesh (AC de Mesh) y el servicio de autoridad de certificación (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 de la Mesh CA. 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 deniega las 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 valor

La mayoría de los campos de las políticas de autorización admiten todos los esquemas de coincidencia siguientes:

  • Concordancia exacta: coincidencia exacta de la cadena.
  • Coincidencia con comodín mediante el carácter comodín "*":
    • Coincidencia de prefijo: una cadena que termina en "*". Por ejemplo, "test.example.*" coincide con "test.example.com" o "test.example.com.cn".
    • Coincidencia de sufijo: una cadena que empieza por "*". Por ejemplo, "*.example.com" coincide con "eng.example.com" o "test.eng.example.com".
  • Concordancia de presencia: para especificar que un campo debe estar presente y no estar vacío, usa el formato fieldname: ["*"]. Esto es diferente de dejar un campo sin especificar, lo que significa que se buscará cualquier valor, incluido el valor vacío.

Hay algunas excepciones. Por ejemplo, los siguientes campos solo admiten coincidencias exactas:

  • El campo key de la sección when
  • La ipBlocks de la sección source
  • El campo ports de la sección to

La siguiente política de ejemplo permite el acceso a rutas 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 que coincidan las condiciones negativas, como notValues en el campo when, notIpBlocks en el campo source y 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 /healthz de la autenticación 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: ["*"]

Rechazar solicitudes de texto sin formato

En Cloud Service Mesh 1.5 y versiones posteriores, mTLS automático está habilitado de forma predeterminada. Con mTLS automático, un proxy sidecar del lado del 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 texto sin formato a las cargas de trabajo sin sidecars. Para disfrutar de la máxima seguridad, te recomendamos que habilites mTLS ESTRICTO.

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

  • crear una política de autorización para permitir explícitamente el tráfico con namespaces o principals no vacíos, o
  • Rechaza el tráfico con namespaces o principals vacíos.

Como namespaces y principals solo se pueden extraer con una solicitud mTLS, estas políticas rechazan cualquier tráfico sin cifrar.

La siguiente política deniega la solicitud si la entidad de seguridad de la solicitud está vacía (como ocurre con las solicitudes de texto sin formato). La política permite solicitudes si la entidad no está vacía. El símbolo ["*"] significa que la coincidencia no está vacía, y si se usa con notPrincipals, significa que la coincidencia se basa en un 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 las políticas de autorización

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

Prioridad de las políticas de autorización

Las políticas de ejemplo de las siguientes secciones ilustran algunos de los comportamientos predeterminados y las situaciones en las que pueden resultarle útiles.

No permitir nada

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

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

Es una buena práctica de seguridad empezar con la política de no permitir nada y añadir gradualmente más políticas ALLOW para abrir más acceso a una carga de trabajo.

Denegar todo el acceso

En el siguiente ejemplo se muestra una política DENY que coincide con todo. Como las políticas de DENY se evalúan antes que las de ALLOW, todas las solicitudes se deniegan, aunque haya una política de 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 denegación total es útil si quieres inhabilitar temporalmente todo el acceso a una carga de trabajo.

Permitir 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 que permite todo hace que otras políticas ALLOW sean inútiles, ya que siempre permite la solicitud.

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

Una política de permitir todo es útil si quieres exponer temporalmente el acceso completo a una carga de trabajo. Si hay políticas de DENY, las solicitudes se pueden denegar, ya que las políticas de DENY se evalúan antes que las 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. Empieza con una política de denegación total y añade de forma incremental más políticas ALLOW para abrir más acceso a las cargas de trabajo.

  3. Si usas JWTs en tu servicio:

    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 que no permita nada.

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

Siguientes pasos

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

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