Résoudre les problèmes courants

Cette page présente les problèmes que vous pouvez rencontrer lors de la configuration de VPC Service Controls.

Comportement inattendu des règles de portée

Vous remarquerez peut-être des cas de non-respect inattendus de VPC Service Controls que votre règle de portée devrait autoriser. Il est connu que si vous ne disposez pas d'une stratégie d'accès au niveau de l'organisation, vous pouvez rencontrer des problèmes inattendus avec vos stratégies d'accès à portée.

Pour résoudre ce problème, créez une règle d'accès au niveau de l'organisation à l'aide de la commande suivante:

gcloud access-context-manager policies create --organization <var>ORGANIZATION_ID</var> --title <var>POLICY_TITLE</var>

Remplacez les éléments suivants :

  • ORGANIZATION_ID : ID de l'organisation.
  • POLICY_TITLE: titre lisible de votre stratégie d'accès.

Pour en savoir plus, consultez Créer une règle d'accès.

VPC partagé

Lorsque vous utilisez un VPC partagé, le périmètre de service incluant les projets appartenant à un réseau VPC partagé doit également inclure le projet qui héberge le réseau. Lorsque les projets appartenant à un réseau VPC partagé ne se trouvent pas dans le même périmètre que le projet hôte, les services peuvent ne pas fonctionner comme prévu ou être entièrement bloqués.

Vérifiez que l'hôte du réseau VPC partagé se trouve dans le même périmètre de service que les projets connectés au réseau.

Impossible d'ajouter un réseau VPC

L'erreur suivante peut se produire lorsque vous essayez d'ajouter un réseau VPC à un périmètre de service:

ERROR: (gcloud.access-context-manager.perimeters.update) PERMISSION_DENIED: Permission 'compute.networks.get' denied on resource '//compute.googleapis.com/projects/PROJECT_NAME/global/networks/VPC_NETWORK_NAME' (or it may not exist)

Cette erreur se produit pour l'une des raisons suivantes:

  • Le réseau VPC n'existe pas.
  • Le réseau VPC existe, mais ne comporte pas de sous-réseau.
  • L'appelant ne dispose pas de l'autorisation requise.

Pour résoudre ce problème, procédez comme suit :

  1. Vérifiez si le réseau VPC spécifié dans le message d'erreur existe en affichant les réseaux de votre projet.

    • Avant de vérifier le réseau VPC, assurez-vous que l'API Compute Engine est activée dans le projet associé à l'appel d'API en procédant comme suit:

      1. Dans la console Google Cloud, accédez à la page API et services.
        Accéder aux API et services

      2. Sur la page API et services, vérifiez si l'API Compute Engine est listée.

      3. Si l'API Compute Engine est manquante, activez-la.
        Activer l'API

  2. Vérifiez si au moins un sous-réseau existe dans le réseau VPC en affichant les sous-réseaux. Si aucun sous-réseau n'est défini, ajoutez-en un au réseau VPC.

  3. Vérifiez si l'appelant dispose de l'autorisation suivante sur le projet hôte du réseau VPC: compute.networks.get. Cette autorisation vous permet d'afficher les réseaux VPC d'un projet.

    • Demandez à l'administrateur de l'organisation propriétaire du projet hôte du réseau VPC d'accorder à l'appelant un rôle IAM avec l'autorisation compute.networks.get sur le projet hôte. Par exemple, le rôle de lecteur de réseau de Compute.

      Pour en savoir plus sur l'attribution de rôles, consultez la section Gérer les accès.

Veillez à lire les limites associées à l'utilisation de réseaux VPC dans des périmètres de service.

Requêtes entre périmètres

Normalement, des niveaux d'accès sont utilisés pour autoriser les requêtes provenant de l'extérieur d'un périmètre de service pour des ressources protégées à l'intérieur d'un périmètre.

Cependant, une requête provenant d'un projet situé dans un périmètre et portant sur une ressource protégée dans un autre périmètre est refusée, même si le niveau d'accès autorise normalement la requête.

Supposons que le projet A du périmètre 1 envoie une requête pour une ressource du projet B. La ressource du projet B est protégée par le périmètre 2. La requête est refusée car le projet A se trouve dans un périmètre distinct, même si un niveau d'accès pour le périmètre 2 autorise normalement la requête pour la ressource protégée.

Pour faciliter les requêtes entre les périmètres, utilisez l'une des approches suivantes:

  • Utilisez des règles de sortie et d'entrée. Pour autoriser les requêtes provenant d'un autre périmètre à des ressources protégées dans votre périmètre, l'autre périmètre doit utiliser une règle de sortie et vous devez définir une règle d'entrée dans votre périmètre.

  • Utiliser les liaisons de périmètre. Les liaisons permettent à au moins deux projets situés dans des périmètres différents d'envoyer des requêtes aux services de ces projets. Ces requêtes sont autorisées, même si les services sont protégés par les périmètres respectifs.

  • Assurez-vous que les périmètres ne protègent pas le service demandeur et la ressource cible. L'opération va alors réussir, car les services ne sont pas protégés.

L'adresse e-mail n'est pas valide ou n'existe pas

Lorsque vous mettez à jour un périmètre contenant un principal supprimé, le message d'erreur The email address is invalid or non-existent peut s'afficher.

Pour résoudre ce problème, vous pouvez effectuer l'une des opérations suivantes:

  • Supprimez l'adresse e-mail non valide du périmètre, y compris les niveaux d'accès et les règles d'entrée et de sortie.

    Vous pouvez utiliser la console Google Cloud ou Google Cloud CLI.

  • Effectuez une opération groupée (Google Cloud CLI uniquement) si l'adresse e-mail figure à la fois dans le test et dans le périmètre appliqué.

    1. Obtenez tous vos périmètres:
      gcloud access-context-manager perimeters list --format=list \
       --policy=<POLICY_NAME> > my-perimeters.yaml
    
    1. Supprimez l'adresse e-mail non valide du fichier my-perimeters.yaml, puis enregistrez-le sous le nom my-perimeters-updated.yaml.

    2. Remplacez tous vos périmètres:

      gcloud access-context-manager perimeters replace-all --format=list \
        --source-file=my-perimeters-updated.yaml \
        --policy=<POLICY_NAME>
    

Violations des règles d'entrée et de sortie

Le journal d'audit contient des informations sur les violations des règles d'entrée et de sortie qui vous aident à comprendre les violations de périmètre.

Violations des règles d'entrée

Une violation de règle d'entrée indique qu'un client API situé en dehors du périmètre a tenté d'accéder à une ressource située à l'intérieur du périmètre. Le périmètre de service rejette la requête, car il n'existe aucune règle d'entrée ni aucun niveau d'accès correspondant.

Une violation de règle d'entrée dans le journal d'audit contient les détails suivants :

  • Le nom du périmètre dans lequel la violation de la règle d'entrée s'est produite.
  • La ressource au sein du périmètre à laquelle le client API en dehors du périmètre a tenté d'accéder.

Dans l'exemple de violation de règle d'entrée suivant, un client API en dehors du périmètre tente d'accéder au bucket Cloud Storage prod-protected-storage-bucket situé au sein du périmètre prod-perimeter.

ingressViolations: [
  0: {
    targetResource: "projects/1234/buckets/prod-protected-storage-bucket"
    servicePerimeter: "accessPolicies/123456789/servicePerimeters/prod-perimeter"
  }
]

Pour résoudre ce problème, créez une règle d'entrée pour votre périmètre. Pour en savoir plus sur les règles d'entrée, consultez la documentation de référence sur les règles d'entrée.

Violation des règles de sortie

Une violation de règle de sortie dans le journal d'audit indique l'un des événements suivants :

  • Un client API au sein du périmètre a tenté d'accéder à une ressource située en dehors du périmètre.
  • Une requête API implique une ressource située à l'intérieur du périmètre et une ressource en dehors du périmètre. Par exemple, un client Cloud Storage appelle une commande de copie, où un bucket se trouve dans le périmètre et l'autre en dehors du périmètre.

Le périmètre de service rejette la requête, car il n'existe aucune règle de sortie correspondante. Une violation de règle de sortie dans le journal d'audit inclut les éléments suivants :

  • Le type de source, tel que le réseau ou la ressource.
  • La source, qui est une ressource ou un réseau, pour laquelle le périmètre a rencontré une violation de sortie.
  • Le périmètre qui a rencontré une violation de sortie.
  • La ressource cible située en dehors du périmètre auquel la requête a tenté d'accéder.

Dans l'exemple de violation de règle de sortie suivant, la requête API inclut une ressource de projets/5678, qui se trouve dans le périmètre prod-perimeter, et un objet du bucket Cloud Storage external-storage-bucket, qui se trouve en dehors du périmètre.

egressViolations: [
  0: {
    sourceType: "Resource"
    source: "projects/5678"
    targetResource: "projects/4321/buckets/external-storage-bucket/objects/corp-resources.json"
    servicePerimeter: "accessPolicies/123456789/servicePerimeters/prod-perimeter"
  }
]

Pour résoudre ce problème, créez une règle de sortie pour votre périmètre. Pour en savoir plus sur les règles de sortie, consultez la documentation de référence sur les règles de sortie.

Déboguer les requêtes bloquées par VPC Service Controls

Le journal d'audit de VPC Service Controls est le principal outil de débogage permettant d'identifier la raison pour laquelle une requête a été bloquée par VPC Service Controls.

Lorsque l'accès a été bloqué de manière inattendue, consultez les journaux d'audit du projet protégé par le périmètre de service. Ces journaux contiennent des données importantes sur les ressources demandées ainsi que la raison pour laquelle la requête a été refusée. Pour en savoir plus sur les journaux d'audit, consultez la section Diagnostiquer les problèmes à l'aide de l'outil de dépannage.

Les sections suivantes présentent les valeurs de violationReason que vous pouvez rencontrer lors de l'utilisation de VPC Service Controls.

NETWORK_NOT_IN_SAME_SERVICE_PERIMETER

Ce problème peut être dû à l'une des raisons suivantes:

  • Un client d'un réseau VPC dans un périmètre de service tente d'accéder à un projet qui ne se trouve pas dans le même périmètre. Cette requête entraîne une violation de sortie. Créez une règle de sortie pour résoudre ce problème.
  • Un client d'un réseau VPC situé en dehors d'un périmètre de service tente d'accéder à un projet protégé par ce périmètre. Cette requête entraîne une violation de l'accès. Créez une règle d'entrée pour résoudre ce problème.

Le client peut envoyer la requête à partir d'une VM Compute Engine ou Google Kubernetes Engine, ou d'un réseau sur site via Cloud Interconnect ou un VPN configuré à l'aide d'un réseau VPC.

Le diagramme suivant montre qu'une violation de sortie se produit lorsqu'un client d'un réseau VPC situé dans un périmètre de service tente d'accéder à un projet en dehors du périmètre:

Non-respect de la sortie en raison de NETWORK_NOT_IN_SAME_SERVICE_PERIMETER.

Voici un exemple de non-respect des règles d'egress:

egressViolations: [
{
  servicePerimeter: "accessPolicies/<POLICY_NAME>/servicePerimeters/<PERIMETER_NAME>"
  source: "projects/<NETWORK_PROJECT_NUMBER>"
  sourceType: "Network"
  targetResource: "projects/<RESOURCE_PROJECT_NUMBER>"
}
]

Où :

  • <POLICY_NAME> est le nom (au format numérique) de votre règle d'accès.
  • <PERIMETER_NAME> est le nom du périmètre de service.
  • <NETWORK_PROJECT_NUMBER> est le numéro du projet Google Cloud qui contient votre réseau VPC.
  • <RESOURCE_PROJECT_NUMBER> est le numéro du projet Google Cloud contenant la ressource.

Le diagramme suivant montre qu'une violation d'entrée se produit lorsqu'un client en dehors du périmètre tente d'accéder à un projet situé à l'intérieur du périmètre:

Non-respect des règles d&#39;entrée en raison de NETWORK_NOT_IN_SAME_SERVICE_PERIMETER.

Voici un exemple de non-respect des règles d'accès:

ingressViolations: [
{
          targetResource: "projects/<RESOURCE_PROJECT_NUMBER>",
      source: "projects/<NETWORK_PROJECT_NUMBER>"
          servicePerimeter: "accessPolicies/<POLICY_NAME>/servicePerimeters/<PERIMETER_NAME>"
}
]

Où :

  • <RESOURCE_PROJECT_NUMBER> est le numéro du projet Google Cloud contenant la ressource.
  • <NETWORK_PROJECT_NUMBER> est le numéro du projet Google Cloud qui contient votre réseau VPC.
  • <POLICY_NAME> est le nom (au format numérique) de votre règle d'accès.
  • <PERIMETER_NAME> est le nom du périmètre de service.

Solution

Pour résoudre cette erreur, créez une règle d'entrée ou de sortie pour votre périmètre.

RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER

Ce problème se produit lorsqu'une seule requête accède à plusieurs ressources, mais que ces ressources ne font pas partie du même périmètre de service. Ce problème se produit indépendamment de l'emplacement du client et de son accès aux ressources.

Le schéma suivant montre un client accédant aux ressources à partir d'un projet en dehors du périmètre et d'un projet dans le périmètre de service:

Non-respect d&#39;une règle de sortie en raison d&#39;un client qui accède aux ressources d&#39;un projet en dehors du périmètre.

Le schéma suivant montre un client accédant aux ressources de projets situés dans deux périmètres de service différents, mais qui ne communiquent pas entre eux:

Non-respect de la sortie en raison d&#39;un client qui accède aux ressources de projets situés dans deux périmètres de service différents.

Voici un exemple de non-respect des règles d'egress:

egressViolations: [
{
  servicePerimeter: "accessPolicies/<POLICY_NAME>/servicePerimeters/<PERIMETER_NAME>"
  source: "projects/<RESOURCE_PROJECT_INSIDE_THIS_PERIMETER>"
  sourceType: "Resource"
  targetResource: "projects/<RESOURCE_PROJECT_OUTSIDE_THIS-PERIMETER>"
}
]

Où :

  • <POLICY_NAME> est le nom (au format numérique) de votre règle d'accès.
  • <PERIMETER_NAME> est le nom du périmètre de service.
  • <RESOURCE_PROJECT_INSIDE_THIS_PERIMETER> est le numéro du projet Google Cloud situé dans le périmètre.
  • <RESOURCE_PROJECT_OUTSIDE_THIS_PERIMETER> est le numéro du projet Google Cloud situé en dehors du périmètre.

Solution

Pour résoudre ce problème, créez une règle de sortie pour votre périmètre.

NO_MATCHING_ACCESS_LEVEL

Ce problème survient lorsque l'adresse IP, les conditions requises par l'appareil ou l'identité de l'utilisateur ne correspondent à aucune règle d'entrée ni à aucun niveau d'accès attribué au périmètre. Cela signifie qu'un client qui ne fait pas partie du réseau Google Cloud tente d'accéder aux ressources réseau Google Cloud en dehors du périmètre. Par exemple, l'adresse IP correspondant au champ callerIp de l'enregistrement d'audit ne correspond à aucune plage CIDR définie dans les niveaux d'accès du périmètre de service.

Si l'adresse IP de l'appelant est manquante ou apparaît en tant qu'adresse IP interne, cette violation peut être due à un service Google Cloud qui n'est pas intégré à VPC Service Controls. Cela peut être dû au fait que le service Google Cloud tente d'accéder à un service protégé et échoue, comme prévu.

Pour résoudre ce problème, nous vous recommandons de créer une règle d'entrée plutôt qu'un niveau d'accès, car une règle d'entrée offre un contrôle d'accès précis.

Le schéma suivant montre un client qui tente d'accéder à des ressources en dehors du périmètre:

Non-respect de l&#39;accès en raison de l&#39;erreur NO_MATCHING_ACCESS_LEVEL.

Voici un exemple de non-respect des règles d'accès:

authenticationInfo: {
  principalEmail: "EMAIL"
}
requestMetadata: {
callerIp: "<PUBLIC_IP_ADDRESS>"
deviceState: "Cross Organization"
}
ingressViolations: [
        {
          targetResource: "projects/<RESOURCE_PROJECT_NUMBER>",
          servicePerimeter: "accessPolicies/<POLICY_NAME>/servicePerimeters/<PERIMETER-NAME>"
        }
  ]

Où :

  • <EMAIL> est l'adresse e-mail du compte de service ou de l'utilisateur authentifié.

    Si vous utilisez un service Google Cloud non compatible avec VPC Service Controls, les adresses e-mail appartenant au domaine google.com sont masquées et remplacées par google-internal. google-internal fait référence aux identités internes appartenant à Google.

  • <PUBLIC_IP_ADDRESS> est l'adresse IP de l'appelant. Pour un appelant depuis Internet, il s'agit de l'adresse IPv4 ou IPv6 publique.

  • <RESOURCE_PROJECT_NUMBER> est le numéro du projet Google Cloud contenant la ressource.

  • <POLICY_NAME> est le nom (au format numérique) de votre règle d'accès.

  • <PERIMETER_NAME> est le nom du périmètre de service.

Notez que dans ce cas, metadata.accessLevels peut toujours être présent, car ces niveaux d'accès peuvent ne pas être spécifiés dans le périmètre violé.

SERVICE_NOT_ALLOWED_FROM_VPC

Ce problème survient lorsqu'un client tente d'accéder aux ressources Google Cloud à partir d'un réseau VPC. Le client peut envoyer la requête à partir d'une VM Compute Engine ou Google Kubernetes Engine, ou d'un réseau sur site via Cloud Interconnect ou un VPN configuré à l'aide d'un réseau VPC.

Pour résoudre ce problème, assurez-vous que le service appelé est autorisé par la configuration des services accessibles par VPC du périmètre de service.

Exemples de cas de figure

Les exemples suivants couvrent des problèmes que vous pouvez rencontrer lors de l'utilisation de VPC Service Controls :

Accès à Cloud Storage à partir d'un environnement sur site

Dans cet exemple, VPC Service Controls bloque une requête provenant du poste de travail d'un employé (identifié par callerIp) vers un bucket Cloud Storage dans le projet corp-storage.

La requête génère l'enregistrement de journal d'audit suivant :

{
 insertId:  "222lvajc6f7"
 logName:  "projects/corp-storage/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "someone@google.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/_"
   ]
   violationReason:  "NO_MATCHING_ACCESS_LEVEL"
  }
  methodName:  "google.storage.NoBillingOk"
  requestMetadata: {
   callerIp:  "b1d5:d26d:5b17:43fe:d358:586b:db59:9617"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/690885588241"
  serviceName:  "storage.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-27T21:40:43.823209571Z"
 resource: {
  labels: {
   method:  "google.storage.NoBillingOk"
   project_id:  "corp-storage"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-27T21:40:42.973784140Z"
}

Le projet corp-storage est inclus dans un périmètre de service. Le poste de travail de l'employé n'appartient à aucun réseau de ce périmètre. Comme le poste de travail de l'employé existe en dehors du périmètre, la requête est bloquée.

Accès à BigQuery à partir d'une VM située en dehors du projet

Dans cet exemple, une VM appartenant au projet 458854174376 (data-collector) tente d'exécuter une requête BigQuery sur un ensemble de données du projet 798816221974 (corp-resources-protected) ; cette requête est refusée.

La VM utilise la requête suivante :

bq --project=corp-resources-protected query 'select count(*) from babynames.yob2000'

La requête renvoie le résultat suivant :

BigQuery error in query operation: VPC Service Controls: Request is
prohibited by organization's policy. Operation ID:
33643962-6a0f-4091-9283-bcdf7e9271f0

L'enregistrement de journal d'audit suivant est généré :

{
 insertId:  "1ei551d2pdq"
 logName:  "projects/corp-resources-protected/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "714877721106-compute@developer.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/1004338142803"
   ]
   violationReason:  "NETWORK_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "bigquery.googleapis.com/bigquery.jobs.create"
  requestMetadata: {
   callerIp:  "10.105.0.2"
   callerNetwork:  "//compute.googleapis.com/projects/ameet-dataflow/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/1004338142803"
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-28T23:06:13.579882505Z"
 resource: {
  labels: {
   method:  "bigquery.googleapis.com/bigquery.jobs.create"
   project_id:  "corp-resources-protected"
   service:  "bigquery.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-28T23:06:12.799656975Z"
}

Dans cet exemple, violationReason est NETWORK_NOT_IN_SAME_SERVICE_PERIMETER. callerNetwork est inclus en plus de callerIp. L'adresse IP est privée et le réseau est spécifié afin de lever toute ambiguïté. Les ressources pertinentes en cause ici sont répertoriées à deux emplacements : VpcServiceControlAuditMetadata.resourceNames et requestMetadata.callerNetwork (le projet qui héberge le réseau).

Le problème se produit car le projet corp-resources-protected se trouve dans un périmètre de service, tandis que data-collector, le projet qui inclut le réseau auquel la VM appartient, n'en fait pas partie. Dans ce cas, l'accès est logiquement refusé.

Requête BigQuery entre projets

Dans cet exemple, une VM appartenant au projet perimeter-network tente d'interroger les instances BigQuery de deux projets différents : corp-resources-protected, qui se trouve dans le même périmètre de service que perimeter-network, et corp-resources-public, qui se trouve lui en dehors.

La VM utilise la commande suivante :

bq query --use_legacy_sql=false \
  'select count(priv.name),count(pub.name) from \
  `corp-resources-protected.babynames.yob2000` as priv, \
  `corp-resources-public.babynames.yob2000` as pub'

La requête renvoie le résultat suivant :

BigQuery error in query operation: Error processing job
'example:bqjob_r211e6f6eec928ffb_000001675c996aa8_1': VPC Service Controls:
Request is prohibited by organization's policy. Operation ID:
dc4fc177-4850-4fc5-b2e7-8c33f302149a

L'enregistrement de journal d'audit suivant est généré :

{
 insertId:  "17kg4exd24ag"
 logName:  "projects/perimeter-network/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/117961063178"
    1:  "projects/690885588241"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "bigquery.googleapis.com/bigquery.tables.getData"
  requestMetadata: {
   callerIp:  "130.211.225.66"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/927005422713"
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-28T20:48:51.384237810Z"
 resource: {
  labels: {
   method:  "bigquery.googleapis.com/bigquery.tables.getData"
   project_id:  "perimeter-network"
   service:  "bigquery.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-28T20:48:50.561884949Z"
}

En examinant callerNetwork et VpcServiceControlAuditMetadata.resourceNames, nous pouvons voir trois projets : perimeter-network, 117961063178 (corp-resources-public) et 690885588241 (corp-resources-protected). Rappelez-vous que corp-resources-public ne se situe pas dans le même périmètre de service que perimeter-network et corp-resources-protected.

L'enregistrement violationReason, RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER indique que certaines ressources de la requête se situent en dehors du périmètre s'appliquant à la requête. Dans le cas présent, il s'agit de la ressource corp-resources-public.

Déplacer un fichier Cloud Storage dans le périmètre

Dans cet exemple, une VM du projet perimeter-network utilise une commande pour déplacer un fichier d'un bucket Cloud Storage, situé dans le projet corp-resources-protected, vers un autre bucket, situé dans le projet corp-resources-public.

La VM utilise la commande suivante :

gcloud storage mv gs://corp-resources-private-1/yob2000.txt gs://corp-resources-public-1/babynames/

La commande renvoie le résultat suivant :

Copying gs://corp-resources-private-1/yob2000.txt [Content-Type=text/plain]...
AccessDeniedException: 403 Request violates VPC Service Controls.

L'enregistrement de journal d'audit suivant est généré :

{
 insertId:  "1xxnssmd2hqo"
 logName:  "projects/perimeter-network/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "storage-accessing@example.iam.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/_/buckets/corp-resources-public-1"
   ]
   violationReason:  "NETWORK_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.storage.BillingRequiredRead"
  requestMetadata: {
   callerIp:  "130.211.225.66"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/927005422713"
  serviceName:  "storage.googleapis.com"
  status: {}
 }
 receiveTimestamp:  "2018-11-28T00:45:31.531623485Z"
 resource: {
  labels: {
   method:  "google.storage.BillingRequiredRead"
   project_id:  "perimeter-network"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-28T00:45:31.351140381Z"
}

Dans ce cas, le journal est moins explicite, car la méthode indiquée est BillingRequiredRead et l'action effectuée est move. Il s'agit d'une limitation associée au journal d'audit actuel de VPC Service Controls.

Bien que le motif soit moins évident, l'enregistrement de journal d'audit nous informe qu'une ressource de la requête se situe en dehors d'un périmètre s'appliquant à la requête. Dans ce cas, cette ressource est corp-resources-public.

Déplacer un fichier Cloud Storage en dehors du périmètre

Dans cet exemple, une VM du projet public-network utilise une commande pour déplacer un fichier d'un bucket Cloud Storage, situé dans le projet corp-resources-protected, vers un autre bucket, situé dans le projet corp-resources-public.

Le projet corp-resources-protected est protégé par un périmètre de service. Les projets public-network et corp-resources-public se situent en dehors du périmètre.

La VM utilise la commande suivante :

gcloud storage mv gs://corp-resources-private-1/yob2000.txt gs://corp-resources-public-1/babynames/

La commande renvoie le résultat suivant :

Copying gs://corp-resources-private-1/yob2000.txt [Content-Type=text/plain]...
AccessDeniedException: 403 Request violates VPC Service Controls.

L'enregistrement de journal d'audit suivant est généré :

{
 insertId:  "10moqhsch9v"
 logName:  "projects/corp-resources-private/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "user@example.biz"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/_/buckets/corp-resources-private-1/objects/yob2000.txt"
    1:  "projects/_/buckets/corp-resources-public-1/objects/out.txt"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.storage.Write"
  requestMetadata: {
   callerIp:  "2620:15c:2c4:203:63d6:5eb8:418d:c034"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/1004338142803"
  serviceName:  "storage.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-30T16:34:46.948010626Z"
 resource: {
  labels: {
   method:  "google.storage.Write"
   project_id:  "corp-resources-private"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-30T16:34:46.898098978Z"
}

Dans cet exemple, le journal d'audit indique qu'il n'est pas possible de copier des données au-delà de la limite du périmètre d'un service (les deux ressources figurent dans l'enregistrement de journal d'audit). Rappelez-vous que la requête provient de l'extérieur du périmètre (la VM du projet public-network) et que l'un des buckets se situe en dehors du périmètre (corp-resources-public-1).

Il est possible d'écrire des données dans le bucket corp-resources-public-1 depuis l'extérieur du périmètre, et de faire ainsi aboutir la vérification qui a échoué dans l'exemple précédent. Toutefois, la vérification ultérieure concernant la copie effective des données va échouer.

Cet exemple montre comment une opération utilisateur unique peut parfois entraîner plusieurs opérations internes qui doivent être autorisées par VPC Service Controls pour être appliquées.

Copie d'un ensemble de données BigQuery à partir d'une VM située dans le périmètre

Dans cet exemple, une VM du projet 927005422713 (perimeter-network) tente de copier un ensemble de données BigQuery du projet corp-resources-private vers le projet corp-resources-public (117961063178). Les projets perimeter-network et corp-resources-private partagent un même périmètre, tandis que corp-resources-public se situe en dehors de ce périmètre.

La VM utilise la commande suivante :

bq cp corp-resources-private:babynames.yob2000 \
  corp-resources-public:babynames.yob2000

La commande renvoie le résultat suivant :

BigQuery error in cp operation: VPC Service Controls: Request is prohibited by
organization's policy. Operation ID: c00dbc44-460f-4bd0-9d09-cda98ac800f9

L'enregistrement de journal d'audit suivant est généré :

{
 insertId:  "146o5fd2hbp"
 logName:  "projects/perimeter-network/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/117961063178"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "bigquery.googleapis.com/bigquery.tables.get"
  requestMetadata: {
   callerIp:  "131.201.221.16"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/927005422713"
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-28T00:27:05.688803777Z"
 resource: {
  labels: {
   method:  "bigquery.googleapis.com/bigquery.tables.get"
   project_id:  "perimeter-network"
   service:  "bigquery.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-28T00:27:05.378584819Z"
}

Dans cet exemple, aucune action d'API sous-jacente unique ne montre toutes les ressources en jeu dans cette requête, en raison des limites du mécanisme de journalisation et de l'architecture distribuée de BigQuery.

L'enregistrement du journal d'audit indique que l'opération a échoué car, pour pouvoir copier les données, BigQuery doit accéder au projet cible (corp-resources-public) en utilisant le réseau du projet perimeter-network (source de la requête). Rappelez-vous que le projet corp-resources-public est situé en dehors du périmètre qui protège perimeter-network. La requête est refusée, car elle est considérée comme une tentative d'exfiltration de données vers corp-resources-public.

Cet exemple illustre le fait qu'une opération conceptuelle, telle que la copie de données, peut déclencher diverses tentatives d'accès aux données de différents systèmes de stockage, comme Cloud Storage, BigQuery ou Bigtable. Selon le mode d'exécution de l'opération, l'enregistrement de journal d'audit généré diffère de la commande utilisateur d'origine. De plus, lorsque plusieurs vérifications sont effectuées au sein d'un service donné et échouent potentiellement, l'enregistrement de journal d'audit généré semble différent de la commande utilisateur d'origine.

Lecture d'une tâche Dataproc à partir d'un projet

Cet exemple montre comment déboguer des erreurs indirectes liées à VPC Service Controls lors de l'utilisation de services de traitement de données tels que Dataproc.

Dans cet exemple, un cluster Dataproc est exécuté dans un projet protégé par VPC Service Controls. Hello-world.py est une tâche pyspark qui tente d'accéder aux données d'un bucket Cloud Storage situé à l'intérieur du périmètre, puis de les écrire dans un autre bucket situé en dehors du périmètre. VPC Service Controls bloque l'opération qui écrit des données dans un bucket situé en dehors du périmètre.

La commande suivante est utilisée pour exécuter Hello-world.py :

gcloud dataproc jobs submit pyspark hello-world.py --cluster test-cluster-new2

La commande renvoie le résultat suivant :

Job [50f16ca8-5102-442b-a545-eed5e4f5f5da] submitted.
Waiting for job output...
18/11/29 00:31:34 INFO org.spark_project.jetty.util.log: Logging initialized @2552ms
18/11/29 00:31:34 INFO org.spark_project.jetty.server.Server: jetty-9.3.z-SNAPSHOT
18/11/29 00:31:34 INFO org.spark_project.jetty.server.Server: Started @2640ms
18/11/29 00:31:34 INFO org.spark_project.jetty.server.AbstractConnector: Started ServerConnector@1f1c18ec{HTTP/1.1,[http/1.1]}{0.0.0.0:4040}
18/11/29 00:31:34 INFO com.google.cloud.hadoop.fs.gcs.GoogleHadoopFileSystemBase: GHFS version: 1.6.4-hadoop2
18/11/29 00:31:35 INFO org.apache.hadoop.yarn.client.RMProxy: Connecting to ResourceManager at test-cluster-new2-m/10.246.0.3:8032
18/11/29 00:31:37 INFO org.apache.hadoop.yarn.client.api.impl.YarnClientImpl: Submitted application application_1522454176466_0005
Traceback (most recent call last):
  File "/tmp/50f16ca8-5102-442b-a545-eed5e4f5f5da/hello-world.py", line 8, in <module>
    lear.saveAsTextFile("gs://corp-resources-public-1/out.txt")
  File "/usr/lib/spark/python/lib/pyspark.zip/pyspark/rdd.py", line 1553, in saveAsTextFile
  File "/usr/lib/spark/python/lib/py4j-0.10.4-src.zip/py4j/java_gateway.py", line 1133, in __call__
  File "/usr/lib/spark/python/lib/py4j-0.10.4-src.zip/py4j/protocol.py", line 319, in get_return_value
py4j.protocol.Py4JJavaError: An error occurred while calling o49.saveAsTextFile.
: java.io.IOException: Error accessing: bucket: corp-resources-public-1, object: out.txt
    at com.google.cloud.hadoop.gcsio.GoogleCloudStorageImpl.wrapException(GoogleCloudStorageImpl.java:1767)
$sp(PairRDDFunctions.scala:961)

 (truncated)

Caused by: com.google.api.client.googleapis.json.GoogleJsonResponseException: 403 Forbidden
{
  "code" : 403,
  "errors" : [ {
    "domain" : "global",
    "message" : "Request violates VPC Service Controls.",
    "reason" : "vpcServiceControls"
  } ],
  "message" : "Request violates VPC Service Controls."
}
    at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)

 (truncated)

18/11/29 00:31:43 INFO org.spark_project.jetty.server.AbstractConnector: Stopped Spark@1f1c18ec{HTTP/1.1,[http/1.1]}{0.0.0.0:4040}
ERROR: (gcloud.dataproc.jobs.submit.pyspark) Job [50f16ca8-5102-442b-a545-eed5e4f5f5da] entered state [ERROR] while waiting for [DONE].

Notez l'exception d'E/S qui se produit lors de l'appel de la méthode saveAsTextFile. Cloud Storage renvoie une erreur 403 avec le message Request violates VPC Service Controls. L'erreur indique que l'opération du journal d'audit Cloud Storage doit être examinée.

Dans les journaux d'audit du projet perimeter-network, où la commande a été exécutée, il existe un enregistrement de journal d'audit pour l'opération saveAsTextFile :

{
 insertId:  "qdj1o9d1run"
 logName:  "projects/corp-resources-private/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "1004338142803-compute@developer.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/_/buckets/corp-resources-public-1/objects/out.txt"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.storage.BillingRequiredRead"
  requestMetadata: {
   callerIp:  "10.246.0.3"
   callerNetwork:  "//compute.googleapis.com/projects/corp-resources-private/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/1004338142803"
  serviceName:  "storage.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-29T00:31:43.666227930Z"
 resource: {
  labels: {
   method:  "google.storage.BillingRequiredRead"
   project_id:  "corp-resources-private"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-29T00:31:43.608250320Z"
}

En raison des limites du journal d'audit, le nom de la méthode (methodName) pour Cloud Storage est défini sur Read alors qu'il s'agit d'une opération write. L'enregistrement du journal d'audit indique que l'opération a échoué, car un réseau du projet corp-resources-private tentait d'accéder aux données (ici, en écriture) d'une ressource dans le bucket corp-resources-public-1. En raison des limites du journal d'audit de Cloud Storage, il n'est pas possible de savoir à quel projet appartient le bucket corp-resources-public-1.

Pour identifier le projet qui contient corp-resources-public-1, utilisez la commande suivante :

gcloud storage ls gs://corp-resources-public-1 --buckets --log-http 2>&1 | grep projectNumber

La commande renvoie le résultat suivant : "projectNumber": "117961063178",

117961063178 est le projet corp-resources-public, qui se situe en dehors du périmètre. L'erreur est donc une conséquence normale.

Erreur due à des services non compatibles

Certains services Google Cloud dépendent d'autres services Google Cloud dans le cadre de leur implémentation. Si un service non compatible tel qu'App Engine est utilisé dans un projet protégé par un périmètre, les ressources du service peuvent ne pas être accessibles.

Pour en savoir plus sur les problèmes connus, consultez la section Limites connues.

Service incompatible avec l'adresse IP virtuelle restreinte

Toute tentative d'accès à une API incompatible avec l'adresse IP virtuelle restreinte de VPC Service Controls génère une erreur 403. Par exemple, VPC Service Controls n'est pas compatible avec App Engine. L'API App Engine Admin n'est donc pas disponible lorsque vous utilisez l'adresse IP virtuelle restreinte.

Par exemple, supposons que la commande suivante soit utilisée pour lister tous les services App Engine dans un périmètre de service:

gcloud app services list

La commande renvoie le résultat suivant :

ERROR: (gcloud.app.services.list) User [***] does not have permission to access apps instance [***] (or it may not exist): <!DOCTYPE html>
<html lang=en>
  <meta charset=utf-8>
  <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
  <title>Error 403 (Forbidden)!!1</title>
  <style>
    *{margin:0;padding:0}html,code{font:15px/22px arial,sans-serif}html{background:#fff;color:#222;padding:15px}body{margin:7% auto 0;max-width:390px;min-height:180px;padding:30px 0 15px}* > body{background:url(//www.google.com/images/errors/robot.png) 100% 5px no-repeat;padding-right:205px}p{margin:11px 0 22px;overflow:hidden}ins{color:#777;text-decoration:none}a img{border:0}@media screen and (max-width:772px){body{background:none;margin-top:0;max-width:none;padding-right:0}}#logo{background:url(//www.google.com/images/branding/googlelogo/1x/googlelogo_color_150x54dp.png) no-repeat;margin-left:-5px}@media only screen and (min-resolution:192dpi){ #logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat 0% 0%/100% 100%;-moz-border-image:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) 0}}@media only screen and (-webkit-min-device-pixel-ratio:2){ #logo{background:url(//www.google.com/images/branding/googlelogo/2x/googlelogo_color_150x54dp.png) no-repeat;-webkit-background-size:100% 100%}}#logo{display:inline-block;height:54px;width:150px}
  </style>
  <a href=//www.google.com/><span id=logo aria-label=Google></span></a>
  <p><b>403.</b> <ins>That's an error.</ins>
  <p>Your client does not have permission to get URL <code>/v1/apps/***/services</code> from this server.  <ins>That's all we know.</ins>

Ce type d'erreur est attendu pour les services non compatibles avec VPC Service Controls et qui ne sont pas disponibles sur l'adresse IP virtuelle restreinte. Si cette erreur se produit pour un service compatible avec VPC Service Controls, nous vous recommandons de consulter les limites connues concernant ce service pour déterminer s'il s'agit d'une erreur prévisible. Dans le cas contraire, signalez le problème.

Exportation de journal vers un projet situé en dehors du périmètre

Dans cet exemple, une exportation de journal est bloquée par VPC Service Controls. La destination de l'exportation (le projet corp-resources-public) se trouve en dehors du périmètre de VPC Service Controls, tandis que le récepteur est créé sur le projet perimeter-network, qui se situe dans le périmètre.

Supposons par exemple que la commande suivante soit utilisée :

gcloud logging sinks describe example-sink

La commande renvoie le résultat suivant :

destination: bigquery.googleapis.com/projects/corp-resources-public/datasets/logs
filter: |-
  resource.type="audited_resource"
  resource.labels.service="bigquery.googleapis.com"
name: example-sink
outputVersionFormat: V2
writerIdentity: serviceAccount:p927005422713-439672@gcp-sa-logging.iam.gserviceaccount.com

L'enregistrement de journal d'audit suivant est généré :

{
 insertId:  "e5i2i8cbqw"
 logName:  "projects/perimeter-network/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "p927005422713-439672@gcp-sa-logging.iam.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "corp-resources-public"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.cloud.bigquery.v2.TableDataService.InsertAll"
  requestMetadata: {
   callerIp:  "2002:a49:8c51::"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/927005422713"
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-11-29T17:32:19.287138882Z"
 resource: {
  labels: {
   method:  "google.cloud.bigquery.v2.TableDataService.InsertAll"
   project_id:  "perimeter-network"
   service:  "bigquery.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-11-29T17:32:19.054662413Z"
}

L'enregistrement de journal d'audit est généré pour BigQuery, et non pour Logging. En effet, BigQuery est le service du récepteur sur lequel Logging tente d'écrire des données.

L'exportation échoue, car corp-resources-public se situe en dehors du périmètre qui protège perimeter-network.

Cet exemple montre que lorsqu'un service Google Cloud appelle un autre service à l'aide d'un compte de service géré interne à Google Cloud, tel que p927005422713-439672@gcp-sa-logging.iam.gserviceaccount.com, le "projet réseau" (ici, perimeter-network) de la requête est dérivé de cette identité. Cette même identité représente la ressource d'exportation de journal elle-même.

Cette tendance est courante dans Google Cloud et s'applique à de nombreux cas d'interaction entre les services.

Extraction BigQuery vers Cloud Storage

Cet exemple explique comment déboguer les échecs d'extraction BigQuery vers Cloud Storage.

Ici, corp-resources-private et perimeter-network sont des projets protégés par un périmètre de service. corp-resources-public est un projet qui se situe en dehors du périmètre.

Supposons que la commande suivante ait été utilisée :

bq extract babynames.yob2000

La commande renvoie le résultat suivant :

gs://corp-resources-public-1/export.txt
Waiting on bqjob_r47ee34109d02b41_000001676b27157c_1 ... (1s) Current status: DONE
BigQuery error in extract operation: Error processing job 'corp-resources-private:bqjob_r47ee34109d02b41_000001676b27157c_1': Access
Denied: BigQuery BigQuery: Permission denied while writing data.

Dans ce cas, l'erreur n'implique pas spécifiquement VPC Service Controls. Une erreur similaire s'affiche en cas d'échec de Cloud IAM.

L'enregistrement de journal d'audit suivant est généré :

{
 insertId:  "4gbh6pe8jld7"
 logName:  "projects/corp-resources-private/logs/cloudaudit.googleapis.com%2Fdata_access"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "storage-accessing@example.iam.gserviceaccount.com"
  }
  methodName:  "jobservice.jobcompleted"
  requestMetadata: {
   callerIp:  "10.5.0.4"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   callerSuppliedUserAgent:  "google-api-python-client/1.6.5 (gzip),gzip(gfe)"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/corp-resources-private/jobs/bqjob_r47ee34109d02b41_000001676b27157c_1"
  serviceData: {
   @type:  "type.googleapis.com/google.cloud.bigquery.logging.v1.AuditData"
   jobCompletedEvent: {
    eventName:  "extract_job_completed"
    job: {
     jobConfiguration: {
      extract: {
       destinationUris: [
        0:  "gs://corp-resources-public-1/export.txt"
       ]
       sourceTable: {
        datasetId:  "babynames"
        projectId:  "corp-resources-private"
        tableId:  "yob2000"
       }
      }
     }
     jobName: {
      jobId:  "bqjob_r47ee34109d02b41_000001676b27157c_1"
      location:  "US"
      projectId:  "corp-resources-private"
     }
     jobStatistics: {
      createTime:  "2018-12-01T19:03:03.908Z"
      endTime:  "2018-12-01T19:03:05.494Z"
      startTime:  "2018-12-01T19:03:04.013Z"
     }
     jobStatus: {
      additionalErrors: [
       0: {
        code:  7
        message:  "Access Denied: BigQuery BigQuery: Permission denied while writing data."
       }
      ]
      error: {
       code:  7
       message:  "Access Denied: BigQuery BigQuery: Permission denied while writing data."
      }
      state:  "DONE"
     }
    }
   }
  }
  serviceName:  "bigquery.googleapis.com"
  status: {
   code:  7
   message:  "Access Denied: BigQuery BigQuery: Permission denied while writing data."
  }
 }
 receiveTimestamp:  "2018-12-01T19:03:05.532169998Z"
 resource: {
  labels: {
   project_id:  "corp-resources-private"
  }
  type:  "bigquery_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-12-01T19:03:05.503Z"
}

Dans cet enregistrement de journal d'audit, storage-accessing@example.iam.gserviceaccount.com est considéré comme l'identité qui tente d'exécuter l'opération. Dans cet exemple, supposons que storage-accessing@example.iam.gserviceaccount.com dispose des autorisations IAM requises pour exécuter la commande.

Comme les autorisations IAM ne sont pas en cause, l'étape suivante consiste à rechercher les échecs liés à VPC Service Controls.

L'enregistrement de journal d'audit pour le service de destination (Cloud Storage) contient les raisons détaillées de l'échec :

{
 insertId:  "1bq397kcfj1"
 logName:  "projects/corp-resources-private/logs/cloudaudit.googleapis.com%2Fpolicy"
 protoPayload: {
  @type:  "type.googleapis.com/google.cloud.audit.AuditLog"
  authenticationInfo: {
   principalEmail:  "storage-accessing@example.iam.gserviceaccount.com"
  }
  metadata: {
   @type:  "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
   resourceNames: [
    0:  "projects/1004338142803"
    1:  "projects/_/buckets/corp-resources-public-1"
   ]
   violationReason:  "RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER"
  }
  methodName:  "google.storage.BillingRequiredRead"
  requestMetadata: {
   callerIp:  "10.5.0.4"
   callerNetwork:  "//compute.googleapis.com/projects/perimeter-network/global/networks/__unknown__"
   destinationAttributes: {
   }
   requestAttributes: {
   }
  }
  resourceName:  "projects/1004338142803"
  serviceName:  "storage.googleapis.com"
  status: {
   code:  7
   details: [
    0: {
     @type:  "type.googleapis.com/google.rpc.PreconditionFailure"
     violations: [
      0: {
       type:  "VPC_SERVICE_CONTROLS"
      }
     ]
    }
   ]
   message:  "Request is prohibited by organization's policy"
  }
 }
 receiveTimestamp:  "2018-12-01T19:03:05.617451586Z"
 resource: {
  labels: {
   method:  "google.storage.BillingRequiredRead"
   project_id:  "corp-resources-private"
   service:  "storage.googleapis.com"
  }
  type:  "audited_resource"
 }
 severity:  "ERROR"
 timestamp:  "2018-12-01T19:03:05.420005215Z"
}

Ce journal indique clairement que les deux projets 1004338142803 (corp-resources-private-1) et corp-resources-public sont tous deux utilisés pour exécuter la commande. Comme ils ne partagent pas de périmètre, la tâche d'extraction échoue.

Cet exemple montre que lorsque vous avez affaire à des opérations multiservices complexes, les journaux d'audit des services sources et de destination peuvent contenir des données de débogage utiles.

Accès au périmètre via la passerelle Cloud NAT

Dans cet exemple, supposons que le projet A de l'organisation A ne soit configuré dans aucun périmètre. Le projet B est sécurisé par un périmètre dans une autre organisation. Les ressources privées du projet A utilisent la passerelle Cloud NAT pour accéder à Internet, ainsi qu'aux API et services Google. Un niveau d'accès est configuré sur le projet B pour autoriser l'accès en fonction des adresses IP de la passerelle externe du projet A.

Une VM appartenant au projet A (qui peut être un nœud Google Kubernetes Engine) tente d'accéder à une ressource protégée dans le projet B, mais la connexion échoue. L'enregistrement de journal d'audit suivant est généré dans le projet B:

{
  "protoPayload": {
    "@type": "type.googleapis.com/google.cloud.audit.AuditLog",
    "status": {
      "code": 7,
      "message": "Request is prohibited by organization's policy. vpcServiceControlsUniqueIdentifier: kmpY9Fgfuhgi2NE90lURjFWuiS1nGRqxCw4L12HdW8h46Un__-_LZw",
      "details": [
        {
          "@type": "type.googleapis.com/google.rpc.PreconditionFailure",
          "violations": [
            {
              "type": "VPC_SERVICE_CONTROLS",
              "description": "kmpY9Fgfuhgi2NE90lURjFWuiS1nGRqxCw4L12HdW8h46Un__-_LZw"
            }
          ]
        }
      ]
    },
    "authenticationInfo": {
      "principalEmail": "my-user@example.iam.gserviceaccount.com",
      "serviceAccountKeyName": "//iam.googleapis.com/projects/my-project/serviceAccounts/my-user@example.iam.gserviceaccount.com/keys/<code><var>ACCOUNT_KEY</var></code>"
    },
    "requestMetadata": {
      "callerIp": "gce-internal-ip",
      "requestAttributes": {},
      "destinationAttributes": {}
    },
    "serviceName": "cloudfunctions.googleapis.com",
    "methodName": "google.cloud.functions.v1.CloudFunctionsService.ListFunctions",
    "resourceName": "<code><var>PROJECT_ID_1</var></code>",
    "metadata": {
      "violationReason": "NETWORK_NOT_IN_SAME_SERVICE_PERIMETER",
      "resourceNames": [
        "projects/<code><var>PROJECT_ID_2</var></code>/locations/-"
      ],
      "securityPolicyInfo": {
        "servicePerimeterName": "accessPolicies/<code><var>ACCESS_POLICY</var></code>/servicePerimeters/us_sandbox",
        "organizationId": "<code><var>ORGANIZATION_ID</var></code>"
      },
      "deviceState": "Unknown",
      "vpcServiceControlsUniqueId": "kmpY9Fgfuhgi2NE90lURjFWuiS1nGRqxCw4L12HdW8h46Un__-_LZw",
      "ingressViolations": [
        {
          "targetResource": "projects/<code><var>PROJECT_ID_1</var></code>",
          "servicePerimeter": "accessPolicies/<code><var>ACCESS_POLICY</var></code>/servicePerimeters/<code><var>PERIMETER_NAME</var></code>",
          "source": "<code><var>PROJECT_ID_2</var></code>"
        }
      ],
      "@type": "type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
    }
  },
  "insertId": "tzf7fd103i",
  "resource": {
    "type": "audited_resource",
    "labels": {
      "service": "cloudfunctions.googleapis.com",
      "method": "google.cloud.functions.v1.CloudFunctionsService.ListFunctions",
      "project_id": "<code><var>PROJECT_ID_2</var></code>"
    }
  },
  "timestamp": "2024-04-02T19:56:10.770681816Z",
  "severity": "ERROR",
  "logName": "projects/<code><var>PROJECT_ID_2</var></code>/logs/cloudaudit.googleapis.com%2Fpolicy",
  "receiveTimestamp": "2024-04-02T19:56:11.463811603Z"
}

La ressource callerIp n'enregistre pas d'adresse IP externe. Au lieu de l'adresse IP externe de la passerelle Cloud NAT, la ressource callerIp affiche gce-internal-ip.

Le champ callerIp est masqué en gce-internal-ip lorsque les requêtes proviennent d'un autre projet ou d'une autre organisation et que la VM Compute Engine source ne dispose pas d'une adresse IP externe.

Cloud NAT est intégré à l'accès privé à Google, ce qui active automatiquement l'accès privé à Google sur le sous-réseau de la ressource et maintient le trafic vers les API et services Google en interne au lieu de le router vers Internet à l'aide de l'adresse IP externe de la passerelle Cloud NAT.

Dans ce cas, comme le trafic est acheminé dans le réseau Google interne, le champ RequestMetadata.caller_ip de l'objet AuditLog est masqué en gce-internal-ip. Pour résoudre ce problème, au lieu d'utiliser l'adresse IP externe de la passerelle Cloud NAT au niveau d'accès de la liste blanche basée sur l'adresse IP, configurez une règle d'entrée pour autoriser l'accès depuis le projet ou le compte de service.

Étape suivante