Integrazione di IAP con Cloud Service Mesh

Questa guida descrive come integrare Identity-Aware Proxy (IAP) con Cloud Service Mesh. L'integrazione di IAP con Cloud Service Mesh ti consente di accedere in sicurezza ai servizi in base ai principi BeyondCorp di Google. IAP verifica l'identità dell'utente e il contesto della richiesta per determinare se un utente può essere autorizzato ad accedere a un'applicazione o a una risorsa. L'integrazione di IAP con Cloud Service Mesh offre i seguenti vantaggi:

  • Controllo completo dell'accesso sensibile al contesto ai workload in esecuzione su Cloud Service Mesh. Puoi impostare criteri di accesso granulari in base agli attributi della richiesta di origine, come l'identità utente, l'indirizzo IP e il tipo di dispositivo. Puoi combinare i criteri di accesso con le limitazioni in base al nome host e al percorso di un URL richiesta.

  • Attiva il supporto dei claim sensibili al contesto nell'autorizzazione di Cloud Service Mesh.

  • Accesso scalabile, sicuro e ad alta disponibilità alla tua applicazione tramite un bilanciatore del carico Google Cloud. Il bilanciamento del carico ad alte prestazioni offre protezione integrata contro gli attacchi DDoS (distributed denial of service) e il supporto per l'indirizzamento IP anycast globale.

Prerequisiti

Segui i passaggi descritti in Installare gli strumenti dipendenti e convalidare il cluster per:

Inoltre, questa guida presuppone che tu abbia:

Configurazione di un cluster con Anthos Service Mesh

Questa sezione spiega come eseguire la configurazione per l'integrazione di IAP sia per le nuove installazioni di Cloud Service Mesh sia per gli upgrade.

Nuove installazioni

  1. Attiva iap.googleapis.com. Nel comando seguente, sostituisci PROJECT_ID con il progetto in cui installerai Cloud Service Mesh:

    gcloud services enable \
      --project=PROJECT_ID \
      iap.googleapis.com
    
  2. Il cluster da aggiornare deve avere l'opzione --addons=HttpLoadBalancing impostata. Il componente aggiuntivo HttpLoadBalancing attiva un controller di bilanciamento del carico HTTP (L7) per il cluster. Esegui il comando seguente per aggiornare il cluster con le opzioni richieste da Cloud Service Mesh. A meno che non abbia impostato una zona o una regione predefinita, devi fornire la regione (--region=REGION) o la zona (--zone=ZONE) nel comando.

    gcloud container clusters update CLUSTER_NAME \
      --project=PROJECT_ID \
      --update-addons=HttpLoadBalancing=ENABLED
    
  3. Per impostazione predefinita, nel file iap-operator.yaml la porta 31223 è impostata come porta di stato e la porta 31224 come porta HTTP. Se la porta 31223 è già in uso nel cluster, esegui quanto segue per impostare un'altra porta di stato:

    kpt cfg set asm gcloud.container.cluster.ingress.statusPort STATUS_PORT
    

    Se la porta 31224 è già in uso nel cluster, esegui quanto segue per impostare un'altra porta HTTP:

    kpt cfg set asm gcloud.container.cluster.ingress.httpPort HTTP_PORT
    
  4. Segui i passaggi descritti in Installare le funzionalità predefinite e la CA Mesh per utilizzare uno script fornito da Google per installare Cloud Service Mesh. Quando esegui lo script, includi la seguente opzione:

    --option iap-operator
    

    Ad esempio:

    ./asmcli install \
      --project_id "PROJECT_ID" \
      --cluster_name "CLUSTER_NAME" \
      --cluster_location "CLUSTER_LOCATION" \
      --fleet_id FLEET_PROJECT_ID \
      --output_dir DIR_PATH \
      --enable_all \
      --option iap-operator
    

    Quando installi Cloud Service Mesh, il file iap-operator.yaml imposta il campo type del servizio istio-ingressgateway su NodePort, che configura il gateway in modo da aprire una porta specifica sul mesh di servizi. In questo modo puoi configurare un bilanciatore del carico che indirizzi il traffico inviato al tuo nome di dominio a questa porta.

  5. Se stai installando Cloud Service Mesh gestito, completa anche i seguenti passaggi:

    1. Aggiungi l'etichetta di revisione allo spazio dei nomi istio-system.

    2. Scarica la specifica del servizio gateway di ingresso Istio per IAP e assegnale il nome iap_operator.yaml.

    3. Installa l'ingress come servizio NodePort. Per maggiori informazioni, consulta la pagina Eseguire la migrazione da IstioOperator.

      asmcli experimental mcp-migrate-check -f iap_operator.yaml
      
      istioctl install -f /asm-generated-configs/gateways-istiooperator/"GATEWAY_NAME".yaml
      

Dopo aver installato Cloud Service Mesh, torna a questa guida e vai alla sezione successiva per configurare l'integrazione con IAP.

Upgrade

Questa sezione illustra i seguenti casi d'uso di upgrade:

  • Hai già configurato l'integrazione di IAP e stai eseguendo l'upgrade di Cloud Service Mesh. In questo caso, hai già attivato iap.googleapis.com nel tuo progetto e il componente aggiuntivo HttpLoadBalancing nel tuo cluster. Vai al passaggio 3 per scaricare il pacchetto asm e eseguire l'upgrade di Cloud Service Mesh.

  • Stai eseguendo l'upgrade di Cloud Service Mesh e vuoi configurare l'integrazione con IAP per la prima volta. In questo caso, devi completare tutti i passaggi che seguono, eseguire l'upgrade di Cloud Service Mesh e tornare a questa guida dopo l'upgrade per completare l'integrazione.

  1. Attiva iap.googleapis.com. Nel comando seguente, sostituisci PROJECT_ID con il progetto in cui installerai Cloud Service Mesh.

    gcloud services enable \
      --project=PROJECT_ID \
      iap.googleapis.com
    
  2. Il cluster da aggiornare deve avere l'opzione --addons=HttpLoadBalancing impostata. Il componente aggiuntivo HttpLoadBalancing attiva un controller di bilanciamento del carico HTTP (L7) per il cluster. Esegui il comando seguente per aggiornare il cluster con le opzioni richieste da Cloud Service Mesh. A meno che non abbia impostato una zona o una regione predefinita, devi fornire la regione (--region=REGION) o la zona (--zone=ZONE) nel comando.

    gcloud container clusters update CLUSTER_NAME \
      --project=PROJECT_ID
      --update-addons=HttpLoadBalancing=ENABLED
    
  3. Se stai aggiornando un bilanciatore del carico HTTP Cloud esistente e funzionante, esegui quanto segue per conservare le porte HTTP e di stato esistenti:

    kpt cfg set asm gcloud.container.cluster.ingress.httpPort $(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="http2")].nodePort}')
    
    kpt cfg set asm gcloud.container.cluster.ingress.statusPort $(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="status-port")].nodePort}')
    
  4. Segui i passaggi descritti in Eseguire l'upgrade di Cloud Service Mesh per utilizzare uno script fornito da Google per eseguire l'upgrade di Cloud Service Mesh.

    Quando esegui l'upgrade di Cloud Service Mesh, il file iap-operator.yaml imposta il campo type del servizio istio-ingressgateway su NodePort, che configura il gateway in modo da aprire una porta specifica nel mesh di servizi. In questo modo, puoi configurare un bilanciatore del carico che instrada il traffico inviato al tuo nome di dominio a questa porta.

    Per impostazione predefinita, nel file iap-operator.yaml la porta 31223 è impostata come porta di stato e la porta 31224 come porta HTTP.

    Quando esegui lo script, includi la seguente opzione:

    --option iap-operator
    

    Ad esempio:

    ./asmcli install \
      --project_id "PROJECT_ID" \
      --cluster_name "CLUSTER_NAME" \
      --cluster_location "CLUSTER_LOCATION" \
      --fleet_id FLEET_PROJECT_ID \
      --output_dir DIR_PATH \
      --enable_all \
      --option iap-operator
    
  5. Completa l'upgrade attivando l'iniezione automatica del proxy sidecar sui tuoi workload. Per maggiori dettagli, consulta Eseguire il deployment e il ricoinvolgimento dei carichi di lavoro.

    Una volta completato l'upgrade, torna a questa guida e vai alla sezione successiva per configurare l'integrazione con l'IAP.

Prenotazione di un indirizzo IP statico e configurazione del DNS

Per integrare Identity-Aware Proxy con Cloud Service Mesh, devi configurare un bilanciatore del carico HTTP(S) di Google Cloud, che richiede un nome di dominio che rimandi a un indirizzo IP statico. Puoi prenotare un indirizzo IP esterno statico, che assegna l'indirizzo al tuo progetto per un tempo indeterminato finché non lo rilasci esplicitamente.

  1. Prenota un indirizzo IP esterno statico:

    gcloud compute addresses create example-static-ip --global
    
  2. Ottieni l'indirizzo IP statico:

    gcloud compute addresses describe example-static-ip --global
    
  3. Nel tuo registrar di nomi di dominio, configura un nome di dominio completo (FQDN) con l'indirizzo IP statico. In genere, aggiungi un record A alle impostazioni DNS. I passaggi di configurazione e la terminologia per l'aggiunta di un A record per un FQDN variano a seconda del registrar del nome di dominio.

    La propagazione dell'impostazione DNS può richiedere da 24 a 48 ore. Puoi continuare a configurare tutto quanto indicato in questa guida, ma non potrai testare la configurazione finché le impostazioni DNS non saranno propagate.

Deployment di un'applicazione di esempio

Prima di attivare l'IAP, devi avere un'applicazione in esecuzione sul tuo cluster GKE per poter verificare che tutte le richieste abbiano un'identità. Questa guida utilizza l'esempio Bookinfo per dimostrare come configurare il bilanciatore del carico HTTP(S) e attivare l'IAP.

Segui i passaggi per eseguire il deployment di Bookinfo. Fino a quando non esegui il deployment del bilanciatore del carico, l'applicazione Bookinfo non è accessibile dall'esterno del cluster GKE (ad esempio da un browser).

Richieste esterne

La risorsa Gateway di Bookinfo (definita in samples/bookinfo/networking/bookinfo-gateway.yaml) utilizza la risorsa preconfigurata istio-ingressgateway. Ricorda che quando hai eseguito il deployment di Cloud Service Mesh, hai specificato NodePort per istio-ingressgateway, che apre una porta specifica nel mesh di servizi. Sebbene i nodi del cluster abbiano indirizzi IP esterni, le richieste provenienti dall'esterno del cluster vengono bloccate dalle regole del firewall di Google Cloud. Con IAP, il modo corretto per esporre le applicazioni alla rete internet pubblica è utilizzare un bilanciatore del carico. Non esporre gli indirizzi dei nodi utilizzando regole firewall, che aggirerebbero IAP.

Per inoltrare le richieste a Bookinfo, devi configurare un bilanciatore del carico HTTP(S) nel tuo progetto Google Cloud. Poiché il bilanciatore del carico si trova nel tuo progetto, si trova all'interno del firewall e può accedere ai nodi del cluster. Dopo aver configurato il bilanciatore del carico con l'indirizzo IP statico e il nome di dominio, puoi inviare richieste al nome di dominio, che il bilanciatore del carico inoltra ai nodi del cluster.

Attivazione di IAP

I passaggi riportati di seguito descrivono come attivare IAP.

  1. Verifica se hai già un brand utilizzando il comando list. Puoi avere un solo brand per progetto.

    gcloud iap oauth-brands list

    Di seguito è riportato un esempio di risposta gcloud, se il brand esiste:

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_ID]
    applicationTitle: [APPLICATION_TITLE]
    supportEmail: [SUPPORT_EMAIL]
    orgInternalOnly: true
    
  2. Se non esiste alcun brand, utilizza il comando create:

    gcloud iap oauth-brands create --application_title=APPLICATION_TITLE --support_email=SUPPORT_EMAIL

    I campi sopra indicati sono obbligatori quando si chiama questa API:

    • supportEmail: l'indirizzo email dell'assistenza visualizzato nella schermata per il consenso OAuth. Questo indirizzo email può essere l'indirizzo di un utente o un alias di Google Gruppi. Sebbene gli account di servizio abbiano anche un indirizzo email, non sono indirizzi email validi e non possono essere utilizzati per creare un brand. Tuttavia, un account di servizio può essere il proprietario di un gruppo Google. Crea un nuovo gruppo Google o configura un gruppo esistente e imposta l'account del servizio desiderato come proprietario del gruppo.

    • applicationTitle: il nome dell'applicazione visualizzato nella schermata per il consenso OAuth.

    La risposta contiene i seguenti campi:

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_ID]
    applicationTitle: [APPLICATION_TITLE]
    supportEmail: [SUPPORT_EMAIL]
    orgInternalOnly: true
    

Creazione di un client OAuth IAP

  1. Utilizza il comando create per creare un cliente. Utilizza la marca name del passaggio precedente.

    gcloud iap oauth-clients create projects/PROJECT_NUMBER/brands/BRAND-ID --display_name=NAME

    La risposta contiene i seguenti campi:

    name: projects/[PROJECT_NUMBER]/brands/[BRAND_NAME]/identityAwareProxyClients/[CLIENT_ID]
    secret: [CLIENT_SECRET]
    displayName: [NAME]
    
  2. Utilizza l'ID client (CLIENT_ID nel passaggio precedente) e CLIENT_SECRET per attivare IAP. Crea un secret di Kubernetes con i materiali del tuo client OAuth:

    kubectl create secret generic -n istio-system my-secret --from-literal=client_id=CLIENT_ID \
    --from-literal=client_secret=CLIENT_SECRET

Implementazione del bilanciatore del carico

Puoi utilizzare una risorsa Ingress per creare un bilanciatore del carico HTTP(S) con certificati SSL configurati automaticamente. I certificati SSL gestiti vengono eseguiti in provisioning, rinnovati e gestiti per il tuo dominio.

  1. Crea una risorsa ManagedCertificate. Questa risorsa specifica il dominio per il certificato SSL. L'elenco spec.domains deve contenere un solo dominio. I domini con caratteri jolly non sono supportati. Nel seguente file YAML, sostituisci DOMAIN_NAME con il nome di dominio configurato per l'indirizzo IP statico esterno.

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.gke.io/v1
    kind: ManagedCertificate
    metadata:
      name: example-certificate
      namespace: istio-system
    spec:
      domains:
        - DOMAIN_NAME
    EOF
  2. Crea una risorsa BackendConfig. Questa risorsa indica a GCLB come eseguire controlli di integrità su Ingress Gateway e come configurare Identity-Aware Proxy. Innanzitutto, raccogli alcuni valori da Ingress Gateway relativi ai controlli di salute:

    • Porta di ingresso del controllo di integrità: questa è la porta di controllo di integrità di istio-ingress.

      export HC_INGRESS_PORT=$(kubectl -n istio-system get service istio-ingressgateway -o jsonpath='{.spec.ports[?(@.name=="status-port")].nodePort}')

    • Percorso di ingresso del controllo di integrità: questo è il percorso del controllo di integrità di istio-ingress.

      export HC_INGRESS_PATH=$(kubectl get pods -n istio-system -l app=istio-ingressgateway -o jsonpath='{.items[0].spec.containers[?(@.name=="istio-proxy")].readinessProbe.httpGet.path}')

    cat <<EOF | kubectl apply -n istio-system -f -
    apiVersion: cloud.google.com/v1
    kind: BackendConfig
    metadata:
      name: http-hc-config
    spec:
      healthCheck:
        checkIntervalSec: 2
        timeoutSec: 1
        healthyThreshold: 1
        unhealthyThreshold: 10
        port: ${HC_INGRESS_PORT}
        type: HTTP
        requestPath: ${HC_INGRESS_PATH}
      iap:
        enabled: true
        oauthclientCredentials:
          secretName: my-secret
    EOF
  3. Aggiungi un'annotazione al servizio di ingresso con BackendConfig.

        kubectl annotate -n istio-system service/istio-ingressgateway --overwrite \
          cloud.google.com/backend-config='{"default": "http-hc-config"}' \
          cloud.google.com/neg='{"ingress":false}'
    
  4. Crea il bilanciatore del carico definendo la risorsa Ingress.

    • Imposta l'annotazione networking.gke.io/managed-certificates sul nome del certificato creato nel passaggio precedente, example-certificate.

    • Imposta l'annotazione kubernetes.io/ingress.global-static-ip-name sul nome dell'indirizzo IP statico che hai prenotato, example-static-ip.

    • Imposta serviceName su istio-ingressgateway, che viene utilizzato nella risorsa Gateway per l'esempio Bookinfo.

    cat <<EOF | kubectl apply -f -
    apiVersion: networking.k8s.io/v1
    kind: Ingress
    metadata:
      name: example-ingress
      namespace: istio-system
      annotations:
        kubernetes.io/ingress.global-static-ip-name: example-static-ip
        networking.gke.io/managed-certificates: example-certificate
    spec:
      defaultBackend:
        service:
          name: istio-ingressgateway
          port:
            number: 80
    EOF
  5. Nella console Google Cloud, vai alla pagina Kubernetes Engine > Servizi & Ingress.

    Vai alla pagina Servizi e ingress

    Nella colonna Stato dovresti vedere il messaggio "Creazione di un ingresso". Attendi che GKE completi il provisioning di Ingress prima di continuare. Aggiorna la pagina ogni pochi minuti per ottenere lo stato più aggiornato dell'Ingress. Dopo il provisioning di Ingress, potresti visualizzare lo stato "Ok" o l'errore "Tutti i servizi di backend sono in stato NON VALIDO". Una delle risorse di cui GKE esegue il provisioning è un controllo di stato predefinito. Se viene visualizzato il messaggio di errore, significa che Ingress è stato provisionato e che è stato eseguito il controllo di integrità predefinito. Quando visualizzi lo stato "Ok" o l'errore, vai alla sezione successiva per configurare i controlli di salute per il bilanciatore del carico.

Configurare l'elenco di accesso IAP

Aggiungi un utente al criterio di accesso per IAP:

gcloud beta iap web add-iam-policy-binding \
    --member=user:EMAIL_ADDRESS \
    --role=roles/iap.httpsResourceAccessor

dove EMAIL_ADDRESS è l'indirizzo email completo dell'utente, ad esempio alice@example.com.

  1. Testa il bilanciatore del carico. Indirizza il browser a:

    http://DOMAIN_NAME/productpage

    dove DOMAIN_NAME è il nome di dominio configurato con l'indirizzo IP statico esterno.

    Dovresti vedere productpage dell'applicazione Bookinfo. Se aggiorni la pagina più volte, dovresti vedere diverse versioni delle recensioni, presentate in un ordine round robin: stelle rosse, stelle nere, nessuna stella.

    Dovresti anche testare l'accesso di https a Bookinfo.

Attivare il supporto di RCToken nel mesh di servizi

Per impostazione predefinita, IAP genera un token web JSON (JWT) che ha come ambito il client OAuth. Per Cloud Service Mesh, puoi configurare l'IAP in modo da generare un RequestContextToken (RCToken), che è un JWT, ma con un segmento di pubblico configurabile. RCToken ti consente di configurare il pubblico del JWT su una stringa arbitraria, che può essere utilizzata nei criteri di Cloud Service Mesh per l'autorizzazione granulare.

Per configurare l'RCToken:

  1. Crea una variabile di ambiente per il segmento di pubblico RCToken. Può essere qualsiasi stringa.

    export RCTOKEN_AUD="your-rctoken-aud"
    
  2. (Facoltativo) Il passaggio successivo richiede BACKEND_SERVICE_ID. Se devi conoscere il valore di BACKEND_SERVICE_ID, esegui il seguente comando:

    kubectl -n istio-system get Ingress example-ingress -o json | jq \
     '.metadata.annotations."ingress.kubernetes.io/backends"'
    

    L'output previsto è simile a "{\"BACKEND_SERVICE_ID\":\"HEALTHY\"}". Ad esempio, "ingress.kubernetes.io/backends": "{\"k8s-be-31224--51f3b55cd1457fb6\":\"HEALTHY\"}". Il valore BACKEND_SERVICE_ID in questo esempio è k8s-be-31224--51f3b55cd1457fb6.

  3. Recupera le impostazioni IAP esistenti.

    gcloud iap settings get --format json \
    --project=${PROJECT_ID} --resource-type=compute --service=BACKEND_SERVICE_ID > iapSettings.json
    
  4. Aggiorna IapSettings con il segmento di pubblico RCToken.

    cat iapSettings.json | jq --arg RCTOKEN_AUD_STR $RCTOKEN_AUD \
    '. + {applicationSettings: {csmSettings: {rctokenAud: $RCTOKEN_AUD_STR}}}' \
    > updatedIapSettings.json
    
    gcloud iap settings set updatedIapSettings.json --format json \
    --project=${PROJECT_ID} --resource-type=compute --service=BACKEND_SERVICE_ID
    
  5. Attiva l'autenticazione RCToken sul gateway in entrata Istio.

    cat <<EOF | kubectl apply -f -
    apiVersion: "security.istio.io/v1beta1"
    kind: "RequestAuthentication"
    metadata:
      name: "ingressgateway-jwt-policy"
      namespace: "istio-system"
    spec:
      selector:
        matchLabels:
          app: istio-ingressgateway
      jwtRules:
      - issuer: "https://cloud.google.com/iap"
        jwksUri: "https://www.gstatic.com/iap/verify/public_key-jwk"
        audiences:
        - $RCTOKEN_AUD
        fromHeaders:
        - name: ingress-authorization
          prefix: "Istio "
        outputPayloadToHeader: "verified-jwt"
        forwardOriginalToken: true
    EOF
    
  6. (Facoltativo) Assicurati che le richieste che non dispongono di JWT validi vengano rifiutate:

      cat <<EOF | kubectl apply -f -
      apiVersion: security.istio.io/v1beta1
      kind: AuthorizationPolicy
      metadata:
        name: iap-gateway-require-jwt
        namespace: istio-system
      spec:
        selector:
          matchLabels:
            app: istio-iap-ingressgateway
        action: DENY
        rules:
          - from:
              - source:
                  notRequestPrincipals: ["*"]
      EOF
      

  7. Assicurati che le richieste a Bookinfo productpage continuino a essere eseguite correttamente:

    http://DOMAIN_NAME/productpage

Per testare il criterio:

  1. Crea un oggetto richiesta IapSettings, ma imposta rctokenAud su una stringa diversa:

    cat iapSettings.json | jq --arg RCTOKEN_AUD_STR wrong-rctoken-aud \
    '. + {applicationSettings: {csmSettings: {rctokenAud: $RCTOKEN_AUD_STR}}}' \
    > wrongIapSettings.json
    
  2. Chiama l'API IapSettings per impostare il segmento di pubblico RCtoken.

    gcloud beta iap settings set wrongIapSettings.json --project=PROJECT_ID --resource-type=compute --service=BACKEND_SERVICE
  3. Fai una richiesta a Bookinfo productpage e dovrebbe non andare a buon fine:

    http://DOMAIN_NAME/productpage

Pulizia

Dopo aver completato questo tutorial, rimuovi le seguenti risorse per evitare addebiti indesiderati sul tuo account:

  1. Elimina il certificato gestito:

    kubectl delete managedcertificates example-certificate
  2. Elimina Ingress, che disalloca le risorse di bilanciamento del carico:

    kubectl -n istio-system delete ingress example-ingress

  3. Elimina l'indirizzo IP statico:

    gcloud compute addresses delete example-static-ip --global

    In questo caso, assicurati di eliminare l'indirizzo IP dal tuo registrar del dominio.

  4. Elimina il cluster, che elimina le risorse che lo compongono, ad esempio le istanze di calcolo, i dischi e le risorse di rete:

    gcloud container clusters delete CLUSTER_NAME