Dépannage

Cette page répertorie les problèmes pouvant survenir lors de la configuration de VPC Service Controls.

Rechercher les erreurs liées à VPC Service Controls

Cette section décrit deux méthodes permettant de détecter les erreurs de VPC dans vos journaux d'audit : en utilisant l'identifiant unique de l'erreur ou en utilisant des métadonnées pour identifier les erreurs.

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 Cloud Console, 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. Si vous souhaitez rechercher les erreurs liées à VPC Service Controls survenues au cours d'une période différente, vous pouvez également modifier la plage à l'aide du 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 relative à la date actuelle, exécutez la commande suivante :

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

Où :

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>="DATETIME" AND
  timestamp<="DATETIME"'

Où :

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 non compatibles

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

Toute tentative visant à limiter un service non compatible à l'aide de l'outil de ligne de commande gcloud ou de l'API Access Context Manager génère une erreur.

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, les requêtes provenant d'un projet situé dans un périmètre et portant sur une ressource protégée dans un autre périmètre seront refusées, 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.

Il existe deux façons de faciliter les requêtes entre les périmètres :

  • 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 aucun service n'est protégé.

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

Étant donné que VPC Service Controls modifie certaines propriétés de bas niveau de Google Cloud, il 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. Pour ce faire, utilisez l'outil de ligne de commande gcloud ou Cloud Console.

Si vous utilisez un service (potentiellement indirectement, via un autre service) désigné comme service restreint par VPC Service Controls dans un projet situé dans un périmètre de service, il est possible que VPC Service Controls soit responsable du problème.

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.

Dans la plupart des cas, lorsque l'accès a été bloqué de manière inattendue, vous pouvez consulter les journaux d'audit du projet à l'origine de la requête. 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 l'affichage des journaux, consultez la section Afficher les journaux.

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

Valeur de violationReason Explication
RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER Les ressources répertoriées sous resourceNames dans l'enregistrement du journal d'audit ne se trouvent pas dans le même périmètre de service.
NETWORK_NOT_IN_SAME_SERVICE_PERIMETER Les ressources correspondant à callerNetwork et resourceNames dans l'enregistrement du journal d'audit ne se trouvent pas dans le même périmètre de service.
NO_MATCHING_ACCESS_LEVEL

L'adresse IP associée à callerIp dans l'enregistrement de journal d'audit ne correspond à aucune plage d'adresses IP spécifiée dans un niveau d'accès attribué au périmètre de service.

Exemples de cas de figure

Les exemples suivants couvrent des cas de figure 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, une requête envoyée depuis un poste de travail d'employé (identifié par callerIp) vers un bucket Cloud Storage dans le projet corp-storage est bloquée par VPC Service Controls.

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 l'erreur suivante :

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 l'erreur suivante :

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éplacement d'un fichier Cloud Storage depuis une VM située 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 l'erreur suivante :

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éplacement d'un fichier Cloud Storage depuis une VM située 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 l'erreur suivante :

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 l'erreur suivante :

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 plusieurs tentatives d'accès aux données de différents systèmes de stockage, comme Cloud Storage, BigQuery ou Cloud Bigtable. Selon le mode d'exécution de l'opération, l'enregistrement de journal d'audit généré peut sembler différent de la commande utilisateur d'origine, en particulier lorsque plusieurs vérifications sont effectuées au sein d'un service donné et échouent potentiellement.

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, ce qui constitue une opération qui devrait être bloquée par VPC Service Controls.

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 l'erreur suivante :

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 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, la commande suivante est utilisée :

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

La commande renvoie l'erreur suivante :

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 non compatible 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, dans la mesure où Cloud DNS n'est actuellement pas compatible avec VPC Service Controls, 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 l'erreur suivante :

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, consultez 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 l'erreur suivante :

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 l'erreur suivante :

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 semblable s'afficherait en cas d'échec lié à 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 le même 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.