Panoramica delle policy di autorizzazione

A differenza di un'applicazione monolitica che potrebbe essere eseguita in un'unica posizione, le app di microservizi distribuite a livello globale effettuano chiamate oltre i confini della rete. Ciò significa più punti di accesso alle applicazioni e più opportunità per attacchi dannosi. Poiché i pod Kubernetes hanno IP temporanei, le regole firewall tradizionali basate su IP non sono adeguate per proteggere l'accesso tra i workload. In un'architettura di microservizi, è necessario un nuovo approccio alla sicurezza. Basandosi su funzionalità di sicurezza come i service account Kubernetes e le policy di sicurezza Istio, Cloud Service Mesh offre ancora più funzionalità per proteggere le applicazioni.

Questa pagina fornisce agli operatori delle applicazioni una panoramica della risorsa personalizzata AuthorizationPolicy. Le policy di autorizzazione consentono di abilitare il controllo dell'accesso sui workload nei livelli di applicazione (L7) e trasporto (L3/4). Devi configurare le policy di autorizzazione per specificare le autorizzazioni, ovvero cosa può fare un servizio o utente.

Policy di autorizzazione

Le richieste tra i servizi nel mesh (e tra gli utenti finali e i servizi) sono consentite per impostazione predefinita. Utilizza la risorsa personalizzata AuthorizationPolicy per definire policy granulari per i tuoi workload. Dopo aver applicato le policy di autorizzazione, Cloud Service Mesh le distribuisce ai proxy sidecar. Quando le richieste arrivano a un workload, il proxy sidecar controlla le policy di autorizzazione per determinare se la richiesta deve essere consentita o negata.

Per informazioni dettagliate sui campi della risorsa personalizzata AuthorizationPolicy supportati dalla piattaforma, consulta Funzionalità supportate.

Ambito delle policy

Puoi applicare una policy all'intero mesh di servizi, a uno spazio dei nomi o a un singolo workload.

  • Per applicare una policy a livello di mesh, specifica lo spazio dei nomi radice (istio-system) nel campo metadata:namespace:

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "mesh-wide"
      namespace: istio-system
    spec:
    ...
    
  • Per applicare una policy a uno spazio dei nomi, specificalo nel campo metadata:namespace:

    apiVersion: "security.istio.io/v1beta1"
    kind: "AuthorizationPolicy"
    metadata:
      name: "currencyservice"
      namespace: currencyservice
    spec:
    ...
    
  • Per limitare una policy a un workload specifico, includi un campo selector.

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

Struttura di base

Una policy di autorizzazione include l'ambito della policy, una risorsa action e un elenco di rules:

  • Come descritto nella sezione precedente, l'ambito della policy può essere l'intero mesh, uno spazio dei nomi o un workload specifico. Se lo includi, il campo selector specifica il target della policy.

  • Il campo action specifica se consentire (ALLOW) o negare (DENY) la richiesta. Se non specifichi un'azione, il campo viene preimpostato su ALLOW. Per chiarezza, consigliamo di specificare sempre l'azione. Le policy di autorizzazione supportano anche le azioni AUDIT e CUSTOM. L'azione AUDIT è supportata solo su alcune piattaforme. Per ulteriori dettagli, vedi Funzionalità supportate.

  • rules specifica quando attivare l'azione.

    • Il campo from in rules specifica le origini della richiesta.

    • Il campo to in rules specifica le operazioni della richiesta.

    • Il campo when specifica le condizioni aggiuntive necessarie per applicare la regola.

Nel seguente esempio:

  • La policy viene applicata alle richieste inviate al servizio frontend nello spazio dei nomi demo.

  • Le richieste sono consentite quando "hello:world" è nell'intestazione della richiesta; in caso contrario, le richieste vengono rifiutate.

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"]

Controllo dell'accesso all'operazione di richiesta

Puoi controllare l'accesso a operazioni di richiesta come metodi HTTP o porte TCP aggiungendo una sezione to in rules. Nell'esempio seguente, solo i metodi HTTP GET e POST sono consentiti per currencyservice nello spazio dei nomi 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"]

Controllo dell'accesso all'identità autenticata

Negli esempi precedenti, le policy consentono le richieste da workload non autenticati. Se hai abilitato mutual TLS (mTLS) in modalità STRICT, puoi limitare l'accesso in base all'identità del workload o dello spazio dei nomi da cui proviene la richiesta nella sezione source.

  • Utilizza il campo principals o notPrincipal per controllare l'accesso a livello di workload.

  • Utilizza il campo namespaces o notNamespaces per controllare l'accesso a livello di spazio dei nomi.

Tutti i campi precedenti richiedono l'abilitazione di mTLS STRICT. Se non riesci a impostare mTLS STRICT, consulta Rifiuta le richieste in testo non crittografato per una soluzione alternativa.

Workload identificato

Nell'esempio seguente, le richieste a currencyservice sono consentite solo dal servizio frontend. Le richieste a currencyservice provenienti da altri workload vengono rifiutate.

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"]

Per specificare un service account, principals deve essere nel seguente formato:

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

Se utilizzi Cloud Service Mesh in-cluster con Citadel CA, allora cluster.local è il dominio attendibile. In tutti gli altri casi, PROJECT_ID.svc.id.googè il dominio attendibile per il mesh.

Spazio dei nomi identificato

L'esempio seguente mostra una policy che nega le richieste se l'origine non è lo spazio dei nomi 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"]

Corrispondenza dei valori

La maggior parte dei campi nelle policy di autorizzazione supporta tutti i seguenti schemi di corrispondenza:

  • Corrispondenza esatta: corrispondenza esatta della stringa.
  • Corrispondenza con carattere jolly utilizzando il carattere jolly "*":
    • Corrispondenza del prefisso: una stringa che termina con "*". Ad esempio, "test.example.*" corrisponde a "test.example.com" o "test.example.com.cn".
    • Corrispondenza del suffisso: una stringa che inizia con "*". Ad esempio, "*.example.com" corrisponde a "eng.example.com" o "test.eng.example.com".
  • Corrispondenza di presenza: per specificare che un campo deve essere presente e non vuoto, utilizza il formato fieldname: ["*"]. Questa opzione è diversa rispetto a lasciare un campo non specificato, che significa che qualsiasi valore è corrisponde, inclusi quelli vuoti.

Esistono alcune eccezioni. Ad esempio, i seguenti campi supportano solo la corrispondenza esatta:

  • Il campo key nella sezione when
  • ipBlocks nella sezione source
  • Il campo ports nella sezione to

La seguente policy di esempio consente l'accesso ai percorsi con il prefisso /test/* o il suffisso */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"]

Corrispondenza delle esclusioni

Per trovare corrispondenze con condizioni negative come notValues nel campo when, notIpBlocks nel campo source, notPorts nel campo to, Cloud Service Mesh supporta la corrispondenza delle esclusioni. L'esempio seguente richiede una richiesta valida principals, derivata dall'autenticazione JWT, se il percorso della richiesta non è /healthz. Di conseguenza, la policy esclude le richieste al percorso /healthz dall'autenticazione 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: ["*"]

Rifiuta le richieste in testo non crittografato

In Cloud Service Mesh, auto mTLS è abilitato per impostazione predefinita. Con auto mTLS, un proxy sidecar lato client rileva automaticamente se il server ha un sidecar. Il sidecar client invia mTLS ai workload con sidecar e invia testo non crittografato ai workload senza sidecar. Per una maggiore sicurezza, ti consigliamo di abilitare mTLS STRICT.

Se non puoi abilitare mTLS in modalità STRICT per un workload o uno spazio dei nomi, puoi:

  • creare una policy di autorizzazione per consentire esplicitamente il traffico con namespaces non vuoto o principals non vuoto oppure
  • rifiutare il traffico con namespaces o principals vuoti.

Poiché namespaces e principals possono essere estratti solo con una richiesta mTLS, queste policy rifiutano effettivamente qualsiasi traffico in testo non crittografato.

La seguente policy nega la richiesta se l'entità nella richiesta è vuota (come nel caso delle richieste in testo non crittografato). La policy consente le richieste se l'entità non è vuota. ["*"] indica una corrispondenza non vuota e l'utilizzo con notPrincipals indica la corrispondenza con un'entità vuoto.

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

Precedenza delle policy di autorizzazione

Puoi configurare policy di autorizzazione ALLOW e DENY separate, ma devi comprendere la precedenza delle policy e il comportamento predefinito per assicurarti che le policy facciano ciò che vuoi. Il seguente diagramma descrive la precedenza delle policy.

precedenza delle policy di autorizzazione

Le policy di esempio nelle sezioni seguenti illustrano alcuni dei comportamenti predefiniti e le situazioni in cui potresti trovarle utili.

Non consentire nulla

L'esempio seguente mostra una policy ALLOW che non fa corrispondere nulla. Per impostazione predefinita, se non sono presenti altre policy ALLOW, le richieste vengono sempre rifiutate.

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

È una buona pratica di sicurezza iniziare con la policy che non consente nulla e aggiungere in modo incrementale altre policy ALLOW per aprire più accessi a un workload.

Nega ogni accesso

L'esempio seguente mostra una policy DENY che fa corrispondere tutto. Poiché le policy DENY vengono valutate prima delle policy ALLOW, tutte le richieste vengono rifiutate, anche se esiste una policy ALLOW che corrisponde alla richiesta.

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

Una policy per negare tutto è utile se vuoi disabilitare temporaneamente l'accesso a un workload.

Consenti tutti gli accessi

L'esempio seguente mostra una policy ALLOW che fa corrispondere tutto e consente l'accesso completo a un workload. La policy "allow-all" rende inutili le altre policy ALLOW perché consente sempre la richiesta.

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

Una policy di tipo "allow-all" è utile se vuoi esporre temporaneamente l'accesso completo a un workload. Se esistono policy DENY, le richieste potrebbero comunque essere rifiutate in quanto le policy DENY vengono valutate prima delle policy ALLOW.

Best practice

  1. Crea un service account Kubernetes per ogni servizio e specifica il service account nel deployment. Ad esempio:

    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. Inizia con una policy che non consente nulla e aggiungi in modo incrementale altre policy ALLOW per aprire un maggiore accesso ai workload.

  3. Se utilizzi JWT per il servizio:

    1. Crea una policy DENY per bloccare le richieste non autenticate, ad esempio:

      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: requireJWT
        namespace: admin
      spec:
        action: DENY
        rules:
        -  from:
          - source:
              notRequestPrincipals: ["*"]
      
    2. Applica una policy che non consente nulla.

    3. Definisci le policy ALLOW per ogni workload. Per gli esempi, vedi Token JWT.

Passaggi successivi

Scopri di più sulle funzionalità di sicurezza di Cloud Service Mesh:

Scopri di più sulle policy di autorizzazione nella documentazione di Istio: