Dépannage

Restez organisé à l'aide des collections Enregistrez et classez les contenus selon vos préférences.

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

Rechercher les erreurs liées à VPC Service Controls

Cette section décrit les méthodes suivantes pour trouver les erreurs de VPC dans vos journaux d'audit :

Utiliser l'identifiant unique de l'erreur

Une erreur générée par VPC Service Controls inclut un identifiant unique permettant d'identifier les journaux d'audit correspondants.

Cette procédure utilise les termes définis dans la documentation de Logging. Pour en savoir plus, consultez la page Requêtes de journaux de base.

Pour obtenir des informations sur une erreur en utilisant l'identifiant unique, procédez comme suit :

  1. Dans la console Google Cloud, accédez à la page Stackdriver Logging du projet situé dans le périmètre de service qui a déclenché l'erreur.

    Accéder à la page Stackdriver Logging

  2. Dans la zone de filtre de recherche, saisissez l'identifiant unique de l'erreur.

Filtrer les journaux à l'aide de métadonnées

Pour identifier les erreurs liées à VPC Service Controls, utilisez Cloud Logging.

Console

Cette procédure utilise les termes définis dans la documentation de Logging. Pour en savoir plus, consultez la page Requêtes de journaux de base.

Pour obtenir les erreurs liées à VPC Service Controls survenues au cours des dernières 24 heures dans Logging, procédez comme suit :

  1. Dans Google Cloud Console, accédez à la page Stackdriver Logging du projet situé dans le périmètre de service.

    Accéder à la page Stackdriver Logging

  2. Dans la zone de filtre de recherche, saisissez les informations suivantes :

    protoPayload.metadata.@type:"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"
    
  3. Dans le menu de sélection de base des ressources, sélectionnez Ressource auditée.

  4. Dans le menu déroulant du sélecteur de période, sélectionnez Dernières 24 heures.

  5. Facultatif : Si vous souhaitez rechercher les erreurs liées à VPC Service Controls survenues au cours d'une période différente, utilisez le menu déroulant Sélecteur de période.

gcloud

  • Pour obtenir les erreurs liées à VPC Service Controls survenues au cours des dernières 24 heures dans Logging, exécutez la commande suivante :

    gcloud logging read 'protoPayload.metadata.@type:"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"'
    

    Par défaut, la commande read est limitée aux dernières 24 heures. Pour obtenir les journaux VPC Service Controls pour une période différente, exécutez l'une des commandes ci-dessous :

  • Pour limiter les journaux en fonction d'une durée spécifique à la date actuelle, exécutez la commande suivante :

    gcloud logging read \
    'protoPayload.metadata.@type:"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"' \
      --freshness=DURATION
    

    Où :

    • DURATION est une période de temps mise en forme. Pour plus d'informations sur la mise en forme, reportez-vous aux formats de durée/heure relative pour gcloud.

    Par exemple, la commande suivante permet d'obtenir toutes les erreurs liées à VPC Service Controls survenues au cours de la dernière semaine :

    gcloud logging read \
    'protoPayload.metadata.@type:"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata"' \
      --freshness=7d
    
  • Pour limiter les journaux à une période spécifique, exécutez la commande suivante :

    gcloud logging read \
    'protoPayload.metadata.@type:"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata" AND
      timestamp>="START_DATETIME" AND
      timestamp<="END_DATETIME"'
    

    Où :

    • START_DATETIME et END_DATETIME sont des chaînes date/heure mises en forme. Pour plus d'informations sur la mise en forme, reportez-vous aux formats de date/heure absolue pour gcloud.

    Par exemple, la commande suivante permet d'obtenir toutes les erreurs liées à VPC Service Controls survenues entre le 22 et le 26 mars 2019 :

    gcloud logging read \
    'protoPayload.metadata.@type:"type.googleapis.com/google.cloud.audit.VpcServiceControlAuditMetadata" AND
      timestamp>="2019-03-22T23:59:59Z" AND
      timestamp<="2019-03-26T00:00:00Z"'
    

Services incompatibles

Pour en savoir plus sur les produits et services compatibles avec VPC Service Controls, consultez la page Produits compatibles et limites.

Une erreur se produira si vous essayez de restreindre un service non compatible à l'aide de l'outil de ligne de commande gcloud ou de l'API Access Context Manager.

L'accès entre projets aux données de services non compatibles est bloqué par VPC Service Controls. De plus, il est possible d'utiliser une adresse IP virtuelle restreinte pour empêcher les charges de travail d'appeler des services non compatibles.

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.

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.

Utilisez l'une des approches suivantes pour faciliter les requêtes entre les périmètres:

  • Utilisez la règle de sortie et la règle d'entrée. Pour autoriser les requêtes provenant d'un autre périmètre vers les ressources protégées de votre périmètre, celui-ci 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 vont être autorisées, même si les services sont protégés par les périmètres.

  • 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.

Déterminer si une erreur est due à VPC Service Controls

VPC Service Controls modifie les propriétés de Google Cloud et peut produire des effets en cascade sur des services difficiles à déboguer si vous ne savez pas quoi rechercher.

Pour déterminer si l'erreur est liée à VPC Service Controls, vérifiez si vous avez activé cette solution et si vous l'avez appliquée aux projets et services que vous tentez d'utiliser. Vous pouvez vérifier si les projets et les services sont protégés par VPC Service Controls à l'aide de l'outil de ligne de commande gcloud ou de la console Google Cloud.

Considérez que vous utilisez indirectement un service désigné comme service restreint par VPC Service Controls dans un projet situé dans un périmètre de service. En pareil cas, il est possible que VPC Service Controls soit en cause.

Pour en savoir plus sur les problèmes connus, reportez-vous à la section Limites connues.

Habituellement, les services propagent les messages d'erreur à partir de leurs dépendances. Les erreurs suivantes indiquent un problème avec VPC Service Controls :

  • Cloud Storage : 403: Request violates VPC Service Controls.

  • BigQuery : 403: VPC Service Controls: Request is prohibited by organization's policy.

  • Autres services : 403: Request is prohibited by organization's policy.

Déboguer une requête bloquée de manière inattendue 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 dans le projet à l'origine de la requête. Ces journaux contiennent des données importantes sur les ressources demandées et la raison pour laquelle la requête a été refusée.

Pour en savoir plus sur l'affichage des journaux, consultez la section Utiliser l'explorateur de journaux.

Le tableau suivant présente les valeurs de violationReason que vous pouvez rencontrer lors de l'utilisation de VPC Service Controls.

violationReason Explication
RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER Les ressources répertoriées sous resourceNames dans l'enregistrement de journal d'audit n'appartiennent pas au même périmètre de service.
NETWORK_NOT_IN_SAME_SERVICE_PERIMETER Les ressources correspondant à callerNetwork et resourceNames dans l'enregistrement de journal d'audit n'appartiennent pas au même périmètre de service.
NO_MATCHING_ACCESS_LEVEL

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. 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. Le service Google Cloud tente d'accéder à un service protégé et échoue comme prévu.

SERVICE_NOT_ALLOWED_FROM_VPC Le service appelé n'est pas autorisé par la configuration des services accessibles par VPC du périmètre de service.

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

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

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@example.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 :

gsutil 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.

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

La VM utilise la commande suivante :

gsutil 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@example.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 :

gsutil --debug ls -L -b gs://corp-resources-public-1 2>&1 | grep projectNumber

La commande renvoie le résultat suivant :

projectNumber: u'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.

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 404. Par exemple, VPC Service Controls n'est pas compatible avec Cloud DNS, et l'API Cloud DNS n'est pas disponible lors de l'utilisation de l'adresse IP virtuelle restreinte.

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

gcloud dns managed-zones list

La commande renvoie le résultat suivant :

ERROR: (gcloud.dns.managed-zones.list) Project [corp-resources-private] not found: <!DOCTYPE html>
<html lang=en>
  <meta charset=utf-8>
  <meta name=viewport content="initial-scale=1, minimum-scale=1, width=device-width">
  <title>Error 404 (Not Found)!!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>404.</b> <ins>That's an error.</ins>
  <p>The requested URL <code>/dns/v1/projects/corp-resources-private/managedZones</code> was not found on 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, nous vous conseillons de signaler 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 à GCP, 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.