Verifica l'identità della VM

Prima che un'applicazione invii informazioni sensibili a un'istanza di una macchina virtuale (VM), l'applicazione può verificare l'identità dell'istanza utilizzando i token di identità dell'istanza firmati da Google. Ogni istanza ha un token JWT (JSON Web Token) univoco che include i dettagli dell'istanza e la firma RS256 di Google. Le tue applicazioni possono verificare la firma a fronte dei certificati Oauth2 pubblici di Google per confermare l'identità dell'istanza con cui hanno stabilito una connessione.

Compute Engine genera token di istanza firmati solo quando un'istanza li richiede dai metadati dell'istanza. Le istanze possono accedere solo al proprio token univoco e non ai token di altre istanze.

Ti consigliamo di verificare le identità delle tue istanze nei seguenti scenari:

  • Quando avvii un'istanza per la prima volta, le applicazioni potrebbero dover garantire che l'istanza a cui si sono connesse abbia un'identità valida prima di trasmettere informazioni sensibili all'istanza.
  • Quando i tuoi criteri richiedono di archiviare le credenziali all'esterno dell'ambiente Compute Engine e invii regolarmente queste credenziali alle tue istanze per un uso temporaneo. Le tue applicazioni possono confermare l'identità delle istanze ogni volta che devono trasmettere le credenziali.

I metodi di autenticazione delle istanze di Google offrono i seguenti vantaggi:

  • Compute Engine crea un token univoco ogni volta che viene richiesto da un'istanza e ogni token scade entro un'ora. Puoi configurare le applicazioni in modo che accettino il token di identità di un'istanza una sola volta, riducendo così il rischio che il token possa essere riutilizzato da un sistema non autorizzato.
  • I token di metadati firmati utilizzano lo standard di settore aperto RFC 7519 e il livello di identità OpenID Connect 1.0, pertanto gli strumenti e le librerie esistenti funzioneranno senza problemi con i token di identità.

Prima di iniziare

  • Scopri come recuperare i valori dei metadati dell'istanza.
  • Scopri le nozioni di base sui token web JSON per sapere come utilizzarli nelle tue applicazioni.
  • Scopri come creare e abilitare gli account di servizio nelle tue istanze. Alle istanze deve essere associato un account di servizio in modo che possano recuperare i token di identità. L'account di servizio non richiede alcuna autorizzazione IAM per recuperare questi token di identità.
  • Se non l'hai ancora fatto, configura l'autenticazione. L'autenticazione è il processo mediante il quale viene verificata l'identità per l'accesso ai servizi e alle API Google Cloud. Per eseguire codice o esempi da un ambiente di sviluppo locale, puoi autenticarti in Compute Engine nel seguente modo.

    Per utilizzare gli esempi Python in questa pagina da un ambiente di sviluppo locale, installa e inizializza gcloud CLI, quindi configura Credenziali predefinite dell'applicazione con le tue credenziali utente.

    1. Installa Google Cloud CLI.
    2. Per initialize gcloud CLI, esegui questo comando:

      gcloud init
    3. Crea credenziali di autenticazione locali per il tuo Account Google:

      gcloud auth application-default login

    Per ulteriori informazioni, consulta Configura l'autenticazione per un ambiente di sviluppo locale.

Verifica dell'identità di un'istanza

In alcuni scenari, le applicazioni devono verificare l'identità di un'istanza in esecuzione su Compute Engine prima di trasmettere dati sensibili all'istanza. In un esempio tipico, c'è un sistema in esecuzione al di fuori di Compute Engine chiamato "Host1" e un'istanza di Compute Engine denominata "VM1". VM1 può connettersi a Host1 e convalidare l'identità di quell'istanza con il seguente processo:

  1. VM1 stabilisce una connessione sicura a Host1 tramite un protocollo di connessione sicura a tua scelta, come HTTPS.

  2. VM1 richiede il proprio token di identità univoco al server di metadati e specifica il pubblico del token. In questo esempio, il valore del pubblico è l'URI di Host1. La richiesta al server di metadati include l'URI del pubblico in modo che Host1 possa controllare il valore in un secondo momento durante la fase di verifica del token.

  3. Google genera un nuovo token di identità dell'istanza univoco in formato JWT e lo fornisce a VM1. Il payload del token include diversi dettagli sull'istanza e l'URI di pubblico. Leggi la pagina Contenuti dei token per una descrizione completa dei contenuti dei token.

  4. VM1 invia il token di identità a Host1 tramite la connessione sicura esistente.

  5. Host1 decodifica il token di identità per ottenere i valori di intestazione e payload.

  6. Host1 verifica che il token sia firmato da Google controllando il valore del pubblico e verificando la firma del certificato sul certificato pubblico Google.

  7. Se il token è valido, Host1 procede con la trasmissione e chiude la connessione al termine. Host1 e tutti gli altri sistemi devono richiedere un nuovo token per le connessioni successive a VM1.

Ottenere il token di identità dell'istanza

Quando l'istanza della macchina virtuale riceve una richiesta per fornire il proprio token di identità, lo richiede al server metadati utilizzando il normale processo per recuperare i metadati dell'istanza. Ad esempio, potresti utilizzare uno dei seguenti metodi:

cURL

Crea una richiesta curl e includi un valore nel parametro audience. Facoltativamente, puoi includere il parametro format per specificare se vuoi includere o meno i dettagli del progetto e dell'istanza nel payload. Se utilizzi il formato full, puoi includere il parametro licenses per specificare se vuoi includere o meno i codici di licenza nel payload.

curl -H "Metadata-Flavor: Google" \
'http://metadata/computeMetadata/v1/instance/service-accounts/default/identity?audience=AUDIENCE&format=FORMAT&licenses=LICENSES'

Sostituisci quanto segue:

  • AUDIENCE: l'URI univoco concordato sia dall'istanza sia dal sistema che verifica l'identità dell'istanza. Ad esempio, il segmento di pubblico potrebbe essere un URL per la connessione tra i due sistemi.
  • FORMAT: il parametro facoltativo che specifica se i dettagli del progetto e dell'istanza sono inclusi nel payload. Specifica full per includere queste informazioni nel payload oppure standard per omettere le informazioni dal payload. Il valore predefinito è standard. Per saperne di più, consulta Formato del token di identità.
  • LICENSES: un parametro facoltativo che specifica se i codici di licenza per le immagini associate a questa istanza sono inclusi nel payload. Specifica TRUE per includere queste informazioni oppure FALSE per omettere queste informazioni dal payload. Il valore predefinito è FALSE. Non ha alcun effetto a meno che format non sia full

Il server dei metadati risponde a questa richiesta con un token web JSON firmato utilizzando l'algoritmo RS256. Il token include una firma Google e informazioni aggiuntive nel payload. Puoi inviare questo token ad altri sistemi e applicazioni in modo che possano verificare il token e confermare l'identità dell'istanza.

Python

Puoi inviare una semplice richiesta dalla tua istanza al server di metadati utilizzando i metodi nella libreria requests Python. L'esempio seguente richiede e poi stampa un token di identità dell'istanza. Il token è univoco per l'istanza che effettua la richiesta.

import requests

AUDIENCE_URL = "http://www.example.com"
METADATA_HEADERS = {"Metadata-Flavor": "Google"}
METADATA_VM_IDENTITY_URL = (
    "http://metadata.google.internal/computeMetadata/v1/"
    "instance/service-accounts/default/identity?"
    "audience={audience}&format={format}&licenses={licenses}"
)
FORMAT = "full"
LICENSES = "TRUE"

def acquire_token(
    audience: str = AUDIENCE_URL, format: str = "standard", licenses: bool = True
) -> str:
    """
    Requests identity information from the metadata server.

    Args:
        audience: the unique URI agreed upon by both the instance and the
            system verifying the instance's identity. For example, the audience
            could be a URL for the connection between the two systems.
        format: the optional parameter that specifies whether the project and
            instance details are included in the payload. Specify `full` to
            include this information in the payload or standard to omit the
            information from the payload. The default value is `standard`.
        licenses: an optional parameter that specifies whether license
            codes for images associated with this instance are included in the
            payload. Specify TRUE to include this information or FALSE to omit
            this information from the payload. The default value is FALSE.
            Has no effect unless format is `full`.

    Returns:
        A JSON Web Token signed using the RS256 algorithm. The token includes a
        Google signature and additional information in the payload. You can send
        this token to other systems and applications so that they can verify the
        token and confirm that the identity of your instance.
    """
    # Construct a URL with the audience and format.
    url = METADATA_VM_IDENTITY_URL.format(
        audience=audience, format=format, licenses=licenses
    )

    # Request a token from the metadata server.
    r = requests.get(url, headers=METADATA_HEADERS)
    # Extract and return the token from the response.
    r.raise_for_status()
    return r.text

Il server dei metadati risponde a questa richiesta con un token web JSON firmato utilizzando l'algoritmo RS256. Il token include una firma Google e informazioni aggiuntive nel payload. Puoi inviare questo token ad altri sistemi e applicazioni in modo che possano verificare il token e confermare l'identità dell'istanza.

Verifica del token

Dopo che l'applicazione riceve un token di identità dell'istanza da un'istanza di Compute Engine, può verificarlo utilizzando la procedura seguente.

  1. Ricevere il token dall'istanza della macchina virtuale, decodificarlo utilizzando un decodificatore JWT RS256 e leggere i contenuti dell'intestazione per ottenere il valore kid.

  2. Verifica che il token sia firmato confrontandolo con il certificato pubblico Google. Ogni certificato pubblico ha un valore kid che corrisponde al valore kid nell'intestazione del token.

  3. Se il token è valido, confronta i contenuti del payload con i valori previsti. Se il payload del token include dettagli sull'istanza e sul progetto, l'applicazione può controllare i valori instance_id, project_id e zone. Questi valori sono una tupla univoca a livello globale che conferma che l'applicazione comunica con l'istanza corretta nel progetto desiderato.

Puoi decodificare e verificare il token utilizzando qualsiasi strumento che preferisci, ma un metodo comune è utilizzare le librerie per il linguaggio che preferisci. Ad esempio, puoi utilizzare il metodo verify_token della libreria OAuth 2.0 di Google per Python. Il metodo verify_token associa il valore kid al certificato appropriato, verifica la firma, controlla l'attestazione del segmento di pubblico e restituisce i contenuti del payload dal token.

import google.auth.transport.requests
from google.oauth2 import id_token

def verify_token(token: str, audience: str) -> dict:
    """
    Verify token signature and return the token payload.

    Args:
        token: the JSON Web Token received from the metadata server to
            be verified.
        audience: the unique URI agreed upon by both the instance and the
            system verifying the instance's identity.

    Returns:
        Dictionary containing the token payload.
    """
    request = google.auth.transport.requests.Request()
    payload = id_token.verify_token(token, request=request, audience=audience)
    return payload

Dopo che l'applicazione avrà verificato il token e i relativi contenuti, potrà comunicare con l'istanza su una connessione sicura e chiudere la connessione al termine dell'operazione. Per le connessioni successive, richiedi un nuovo token all'istanza e verifica nuovamente l'identità dell'istanza.

Contenuti del token

Il token di identità dell'istanza contiene tre parti principali:

L'intestazione include il valore kid per identificare i certificati Oauth2 pubblici che devi utilizzare per verificare la firma. L'intestazione include anche il valore alg per confermare che la firma venga generata utilizzando l'algoritmo RS256.

{
  "alg": "RS256",
  "kid": "511a3e85d2452aee960ed557e2666a8c5cedd8ae",
}

Payload

Il payload contiene l'attestazione del pubblico aud. Se l'istanza ha specificato format=full quando ha richiesto il token, il payload include anche le attestazioni sull'istanza della macchina virtuale e sul relativo progetto. Quando richiedi un token di formato completo, se specifichi licenses=TRUE, verranno incluse anche le rivendicazioni sulle licenze associate all'istanza.

{
   "iss": "[TOKEN_ISSUER]",
   "iat": [ISSUED_TIME],
   "exp": [EXPIRED_TIME],
   "aud": "[AUDIENCE]",
   "sub": "[SUBJECT]",
   "azp": "[AUTHORIZED_PARTY]",
   "google": {
    "compute_engine": {
      "project_id": "[PROJECT_ID]",
      "project_number": [PROJECT_NUMBER],
      "zone": "[ZONE]",
      "instance_id": "[INSTANCE_ID]",
      "instance_name": "[INSTANCE_NAME]",
      "instance_creation_timestamp": [CREATION_TIMESTAMP],
      "instance_confidentiality": [INSTANCE_CONFIDENTIALITY],
      "license_id": [
        "[LICENSE_1]",
          ...
        "[LICENSE_N]"
      ]
    }
  }
}

Dove:

  • [TOKEN_ISSUER]: un URL che identifica chi ha emesso il token. Per Compute Engine, questo valore è https://accounts.google.com.
  • [ISSUED_TIME]: un timestamp Unix che indica quando è stato emesso il token. Questo valore viene aggiornato ogni volta che l'istanza richiede un token al server metadati.
  • [EXPIRED_TIME]: un timestamp Unix che indica la scadenza del token.
  • [AUDIENCE]: l'URI univoco concordato sia dall'istanza sia dal sistema che verifica l'identità dell'istanza. Ad esempio, un segmento di pubblico potrebbe essere un URL per la connessione tra i due sistemi.
  • [SUBJECT]: l'oggetto del token, ovvero l'ID univoco dell'account di servizio associato all'istanza.
  • [AUTHORIZED_PARTY]: la parte a cui è stato emesso il token ID, che è l'ID univoco dell'account di servizio associato all'istanza.
  • [PROJECT_ID]: l'ID del progetto in cui hai creato l'istanza.
  • [PROJECT_NUMBER]: il numero univoco del progetto in cui hai creato l'istanza.
  • [ZONE]: la zona in cui si trova l'istanza.
  • [INSTANCE_ID]: l'ID univoco dell'istanza a cui appartiene il token. Questo ID è univoco all'interno del progetto e della zona.
  • [INSTANCE_NAME]: il nome dell'istanza a cui appartiene il token. Se il progetto utilizza il DNS di zona, questo nome può essere riutilizzato in più zone, quindi utilizza una combinazione dei valori project_id, zone e instance_id per identificare un ID istanza univoco. I progetti con DNS globale abilitato hanno un nome istanza univoco in tutto il progetto.
  • [CREATION_TIMESTAMP]: un timestamp Unix che indica il momento in cui hai creato l'istanza.
  • [INSTANCE_CONFIDENTIALITY]: 1 se l'istanza è una VM riservata.
  • Da [LICENSE_1] a [LICENSE_N]: i codici di licenza per le immagini associate a questa istanza.

Il payload potrebbe essere simile al seguente esempio:

{
  "iss": "https://accounts.google.com",
  "iat": 1496953245,
  "exp": 1496956845,
  "aud": "https://www.example.com",
  "sub": "107517467455664443765",
  "azp": "107517467455664443765",
  "google": {
    "compute_engine": {
      "project_id": "my-project",
      "project_number": 739419398126,
      "zone": "us-west1-a",
      "instance_id": "152986662232938449",
      "instance_name": "example",
      "instance_creation_timestamp": 1496952205,
      "instance_confidentiality": 1,
      "license_id": [
        "1000204"
      ]
    }
  }
}

Firma

Google genera la firma codificando in base64url l'intestazione e il payload e concatena i due valori. Puoi controllare questo valore nei certificati Oauth2 pubblici per verificare il token.

Passaggi successivi