Soluciona los problemas comunes.

En esta página, se enumeran varios problemas que pueden surgir cuando configuras los Controles del servicio de VPC.

Comportamiento inesperado de la política con alcance

Es posible que notes algunas infracciones inesperadas de los Controles del servicio de VPC que la política con permiso debe permitirlo. Es un problema conocido que, si no se cuenta de acceso a nivel de la organización, es posible que experimentes problemas con tus políticas de acceso con permiso.

Para solucionar este problema, crea una política de acceso a nivel de la organización con el siguiente comando:

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

Reemplaza lo siguiente:

  • ORGANIZATION_ID: El ID de la organización.
  • POLICY_TITLE: Es un título legible para la política de acceso.

Para obtener más información, consulta Crea una política de acceso.

VPC compartida

Cuando usas una VPC compartida, un perímetro de servicio que incluye proyectos que pertenecen a una red de VPC compartida también debe incluir el proyecto que aloja la red. Cuando los proyectos que pertenecen a una red de VPC compartida no están en el mismo perímetro que el proyecto host, es posible que los servicios no funcionen como se espera o que se bloqueen por completo.

Asegúrate de que el host de la red de VPC compartida esté en el mismo perímetro de servicio que los proyectos conectados a la red.

No se puede agregar una red de VPC

El siguiente error puede ocurrir cuando intentas agregar una red de VPC a un perímetro de servicio:

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)

Este error se produce por uno de los siguientes motivos:

  • La red de VPC no existe.
  • La red de VPC existe, pero no tiene una subred.
  • El llamador no tiene el permiso necesario.

Para resolver este problema, realiza los siguientes pasos:

  1. Verifica si la red de VPC especificada en el mensaje de error existe al ver el redes en tu en un proyecto final.

    • Antes de verificar la red de VPC, asegúrate de que la API de Compute Engine esté habilitada en el proyecto asociado con la llamada a la API. Para ello, completa los siguientes pasos:

      1. En la consola de Google Cloud, ve a la página API y servicios.
        Ir hasta APIs y Servicios

      2. En la página APIs y servicios, verifica si la API de Compute Engine aparece en la lista.

      3. Si falta la API de Compute Engine, habilítala.
        Habilite la API

  2. Para verificar si existe al menos una subred en la red de VPC, consulta las subredes. Si no hay subredes, agrega una subred a la red de VPC.

  3. Verifica si el llamador tiene el siguiente permiso en el proyecto host de la red de VPC: compute.networks.get. Este permiso te permite visualizar redes de VPC en un proyecto.

    • Pregunta al administrador de la organización propietaria del proyecto host de a la red de VPC para otorgarle al emisor una IAM con el permiso compute.networks.get en el proyecto host. Por ejemplo, el rol de visualizador de red de Compute.

      Para obtener más información sobre cómo otorgar roles, consulta Administra acceso.

Asegúrate de leer el limitaciones asociada con el uso de redes de VPC en perímetros de servicio.

Solicitudes entre perímetros

Por lo general, los niveles de acceso se usan con el fin de permitir las solicitudes por fuera de un perímetro de servicio para recursos protegidos dentro de un perímetro.

Sin embargo, se rechaza una solicitud de un proyecto que está en el perímetro de un recurso protegido en otro perímetro, incluso si un nivel de acceso suele permitir la solicitud.

Por ejemplo, supongamos que el Proyecto A en el Perímetro 1 solicita un recurso del Proyecto B. El recurso en el Proyecto B está protegido por el Perímetro 2. Dado que el Proyecto A está en un perímetro, incluso si un nivel de acceso para el Perímetro 2 permitiría la solicitud del recurso protegido con normalidad, la solicitud se rechaza.

Usa uno de los siguientes enfoques para facilitar las solicitudes entre perímetros:

  • Usa la política de salida y de entrada. Para permitir solicitudes de otro perímetro a recursos protegidos en y el otro debe usar una política de salida y configurar una de entrada.

  • Usa puentes perimetrales. Los puentes permiten que dos o más proyectos en diferentes perímetros realicen solicitudes a los servicios de esos proyectos. Estas solicitudes están permitidas incluso si servicios están protegidos por los perímetros respectivos.

  • Asegúrate de que los perímetros no protejan al servicio de solicitud ni al recurso de destino. En esta situación, la operación tiene éxito porque los servicios no están protegidos.

La dirección de correo electrónico no es válida o no existe

Cuando actualices un perímetro que contiene un principal borrado, es posible que veas el mensaje de error The email address is invalid or non-existent.

Para solucionar este problema, puedes realizar una de las siguientes tareas:

  • Quita la dirección de correo electrónico no válida del perímetro, que incluye lo siguiente: y las reglas de entrada y salida.

    Puedes usar la consola de Google Cloud o Google Cloud CLI.

  • Realiza una operación masiva (solo en Google Cloud CLI) si la dirección de correo electrónico está en ambos, en la prueba sin conexión y en el perímetro aplicado.

    1. Obtén todos tus perímetros:
      gcloud access-context-manager perimeters list --format=list \
       --policy=<POLICY_NAME> > my-perimeters.yaml
    
    1. Quita la dirección de correo electrónico no válida del archivo my-perimeters.yaml y guárdala como my-perimeters-updated.yaml.

    2. Reemplaza todos tus perímetros:

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

Incumplimientos de las reglas de entrada y salida

El registro de auditoría contiene información sobre los incumplimientos de reglas de entrada y salida que te ayudan a comprender los incumplimientos de perímetros.

Incumplimiento de la regla de entrada

Un incumplimiento de la regla de entrada indica que un cliente de API fuera del perímetro intentó acceder a un recurso dentro del perímetro. El perímetro de servicio rechaza la solicitud, ya que no hay reglas de entrada ni niveles de acceso que coincidan.

Un incumplimiento de la regla de entrada en el registro de auditoría contiene los siguientes detalles:

  • El nombre del perímetro en el que se produjo el incumplimiento de la regla de entrada.
  • El recurso dentro del perímetro al que el cliente de la API fuera del perímetro intentó acceder.

En el siguiente ejemplo de incumplimiento de la regla de entrada, un cliente de API fuera del perímetro intenta acceder al bucket de Cloud Storage prod-protected-storage-bucket dentro del perímetro prod-perimeter.

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

Para resolver este problema, crea una regla de entrada para tu perímetro. Para obtener más información sobre las reglas de entrada, consulta la referencia de las reglas de entrada.

Incumplimiento de la regla de salida

Un incumplimiento de la regla de salida en el registro de auditoría indica uno de los siguientes eventos:

  • Un cliente de la API dentro del perímetro intentó acceder a un recurso fuera del perímetro.
  • Una solicitud a la API que involucra un recurso dentro del perímetro y un recurso fuera del perímetro. Por ejemplo, un cliente de Cloud Storage que llama a un comando de copia en el que un bucket está dentro del perímetro y el otro está fuera del perímetro.

El perímetro de servicio rechaza la solicitud porque no hay reglas de salida que coincidan. Un incumplimiento de la regla de salida en el registro de auditoría incluye los siguientes detalles:

  • El tipo de fuente, como red o recurso.
  • La fuente, que es un recurso o una red, cuyo perímetro encontró una infracción de salida.
  • El perímetro que encontró una infracción de salida.
  • El recurso de destino fuera del perímetro al que la solicitud intentó acceder.

En el siguiente ejemplo de incumplimiento de la regla de salida, la solicitud a la API incluye un recurso de projects/5678, que está dentro del perímetro prod-perimeter, y un objeto del bucket de Cloud Storage external-storage-bucket, que está fuera del perímetro.

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

Para resolver este problema, crea una regla de salida para tu perímetro. Para obtener más información sobre las reglas de salida, consulta Reglas de salida. referencia.

Solicitudes de depuración bloqueadas por los Controles del servicio de VPC

El registro de auditoría de los Controles del servicio de VPC es la herramienta principal para depurar una solicitud bloqueada por los Controles del servicio de VPC.

Cuando el acceso se bloquea de manera inesperada, consulta los registros de auditoría del proyecto protegido por el perímetro de servicio. Estos registros contienen datos importantes sobre los recursos solicitados y el motivo del rechazo de la solicitud. Para obtener información sobre los registros de auditoría, consulta Cómo diagnosticar problemas con el Solucionador de problemas.

En las siguientes secciones, se enumeran los valores violationReason que puedes encontrar cuando usas los Controles del servicio de VPC.

NETWORK_NOT_IN_SAME_SERVICE_PERIMETER

El motivo de este problema puede ser uno de los siguientes:

  • Un cliente en una red de VPC dentro de un perímetro de servicio intenta acceder a un proyecto que no está en el mismo perímetro. Esta solicitud genera un incumplimiento de salida. Crea una regla de salida para corregir este problema.
  • Un cliente en una red de VPC que está fuera del perímetro de servicio intenta acceder un proyecto que está protegido por el perímetro de servicio. Esta solicitud genera un incumplimiento de entrada. Crea una regla de entrada para solucionar este problema.

El cliente puede enviar la solicitud desde una VM de Compute Engine o de Google Kubernetes Engine, o de una red local a través de Cloud Interconnect o de una VPN configurada con una red de VPC.

En el siguiente diagrama, se muestra que se produce un incumplimiento de salida cuando un cliente en una red de VPC dentro de un perímetro de servicio intenta acceder a un proyecto fuera del perímetro:

Una infracción de salida debido a NETWORK_NOT_IN_SAME_SERVICE_PERIMETER.

Este es un ejemplo de una infracción de salida:

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

Aquí:

  • <POLICY_NAME> es el nombre numérico de tu política de acceso.
  • <PERIMETER_NAME> es el nombre del perímetro de servicio.
  • <NETWORK_PROJECT_NUMBER> es el número de proyecto de Google Cloud que contiene tu red de VPC.
  • <RESOURCE_PROJECT_NUMBER> es el número del proyecto de Google Cloud que contiene el recurso.

En el siguiente diagrama, se muestra que se produce un incumplimiento de entrada cuando un cliente fuera del perímetro intenta acceder a un proyecto dentro del perímetro:

Una infracción de entrada debido a NETWORK_NOT_IN_SAME_SERVICE_PERIMETER.

Este es un ejemplo de un incumplimiento de entrada:

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

Aquí:

  • <RESOURCE_PROJECT_NUMBER> es el número de proyecto de Google Cloud que contiene el recurso.
  • <NETWORK_PROJECT_NUMBER> es el número de proyecto de Google Cloud que contiene tu red de VPC.
  • <POLICY_NAME> es el nombre numérico de tu política de acceso.
  • <PERIMETER_NAME> es el nombre del perímetro de servicio.

Solución

Para resolver este error, crea una entrada o salida estándar de su perímetro de servicio.

RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER

Este problema ocurre cuando una sola solicitud accede a varios recursos, pero recursos no están en el mismo perímetro de servicio. Este problema ocurre independientemente de dónde se encuentre el cliente y de si tiene acceso a los recursos.

En el siguiente diagrama, se muestra un cliente que accede a recursos desde un proyecto fuera del perímetro y desde un proyecto dentro del perímetro de servicio:

Una infracción de salida debido a que un cliente accede a los recursos de un proyecto fuera del
perímetro de servicio.

En el siguiente diagrama, se muestra un cliente que accede a recursos de proyectos que se encuentran en dos perímetros de servicio diferentes, pero los perímetros no se comunican entre sí:

Una infracción de salida debido a que un cliente accede a recursos desde proyectos que están
en dos perímetros de servicio diferentes.

Este es un ejemplo de un incumplimiento de salida:

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

Aquí:

  • <POLICY_NAME> es el nombre numérico de tu política de acceso.
  • <PERIMETER_NAME> es el nombre del perímetro de servicio.
  • <RESOURCE_PROJECT_INSIDE_THIS_PERIMETER> es el número de proyecto del proyecto de Google Cloud que se encuentra dentro del perímetro.
  • <RESOURCE_PROJECT_OUTSIDE_THIS_PERIMETER> es el número del proyecto de Google Cloud que está fuera del perímetro.

Solución

A fin de resolver este problema, crea una regla de salida para tu perímetro.

NO_MATCHING_ACCESS_LEVEL

Este problema ocurre cuando la dirección IP, los requisitos del dispositivo o la identidad del usuario no coincide con ninguna regla de entrada ni nivel de acceso asignado al perímetro. Esta significa que un cliente que no forma parte de la red de Google Cloud intenta acceder a los recursos de red de Google Cloud desde fuera del perímetro. Para Por ejemplo, la dirección IP correspondiente al campo callerIp de la auditoría registro no coincide con ninguno de los rangos de CIDR definidos en los niveles de acceso del en ese perímetro de servicio.

Si falta la dirección IP del emisor o aparece como una dirección IP interna, este incumplimiento podría deberse a un servicio de Google Cloud que no está integrados en los Controles del servicio de VPC. La razón podría ser que el El servicio de Google Cloud intenta acceder a un servicio protegido y falla, ya que lo esperado.

Para solucionar este problema, recomendamos crear una regla de entrada en lugar de una regla de acceso porque una regla de entrada proporciona control de acceso detallado.

En el siguiente diagrama, se muestra a un cliente que intenta acceder a los recursos desde fuera del perímetro:

Un incumplimiento de entrada debido a NO_MATCHING_ACCESS_LEVEL.

A continuación, se muestra un ejemplo de una infracción de entrada:

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

Aquí:

  • <EMAIL> es la dirección de correo electrónico de la cuenta de servicio o del usuario autenticado.

    Si usas un servicio de Google Cloud que no es compatible con los Controles del servicio de VPC, las direcciones de correo electrónico que pertenecen al dominio google.com se ocultan y se reemplazan por google-internal. google-internal se refiere a las identidades internas de Google.

  • <PUBLIC_IP_ADDRESS> es la dirección IP del emisor de la llamada. Para un llamador desde Internet, esta será la dirección IPv4 o IPv6 pública.

  • <RESOURCE_PROJECT_NUMBER> es el número del proyecto de Google Cloud que contiene el recurso.

  • <POLICY_NAME> es el nombre numérico de tu política de acceso.

  • <PERIMETER_NAME> es el nombre del perímetro de servicio.

Ten en cuenta que, en este caso, metadata.accessLevels podría seguir presente, ya que estos niveles de acceso podrían no estar especificados en el perímetro vulnerado.

SERVICE_NOT_ALLOWED_FROM_VPC

Este problema ocurre cuando un cliente intenta acceder a los recursos de Google Cloud desde una red de VPC. El cliente puede enviar la solicitud desde una VM de Compute Engine o de Google Kubernetes Engine o desde una red local a través de Cloud Interconnect o una VPN configurada con una red de VPC.

Para solucionar este problema, asegúrate de que la configuración de servicios accesibles de VPC del perímetro de servicio permita el servicio al que se llama.

Situaciones de ejemplo

Los siguientes ejemplos abarcan situaciones que podrías encontrarte cuando uses los Controles del servicio de VPC.

Acceso a Cloud Storage desde las instalaciones locales

En este ejemplo, los Controles del servicio de VPC bloquean una solicitud de una estación de trabajo de empleado (identificada por callerIp) a un bucket de Cloud Storage en el proyecto corp-storage.

La solicitud genera el siguiente registro de auditoría:

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

El proyecto corp-storage se incluye en un perímetro de servicio. La estación de trabajo de empleado no forma parte de ninguna red dentro de ese perímetro. Debido a que la estación de trabajo de empleado está fuera del perímetro, la solicitud se bloquea.

Acceso de BigQuery desde una VM fuera del proyecto

En este ejemplo, una VM que pertenece al proyecto 458854174376 (data-collector) intenta ejecutar una consulta de BigQuery en un conjunto de datos del proyecto 798816221974 (corp-resources-protected) y se ve rechazada.

La VM usa la siguiente consulta:

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

La consulta muestra el siguiente resultado:

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

Se genera el siguiente registro de auditoría:

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

En este ejemplo, el violationReason es NETWORK_NOT_IN_SAME_SERVICE_PERIMETER. callerNetwork se incluye, además de callerIp. La dirección IP es privada, y la red se proporciona para que no haya ambigüedad. Aquí se detallan los recursos relevantes en dos lugares: VpcServiceControlAuditMetadata.resourceNames y requestMetadata.callerNetwork (el proyecto que posee la red).

El problema es que el proyecto corp-resources-protected está dentro de un perímetro de servicio, mientras que data-collector, el proyecto que incluye la red a la que pertenece la VM, no. En este caso, se rechazó el acceso como se esperaba.

Consulta entre proyectos de BigQuery

En este ejemplo, una VM que pertenece al proyecto perimeter-network intenta consultar las instancias de BigQuery de dos proyectos diferentes: corp-resources-protected, que se encuentra en el mismo perímetro de servicio que perimeter-network, y corp-resources-public, que no se encuentra en el mismo perímetro.

La VM usa el siguiente comando:

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 consulta muestra el siguiente resultado:

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

Se genera el siguiente registro de auditoría:

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

Si analizamos callerNetwork y VpcServiceControlAuditMetadata.resourceNames, podemos ver tres proyectos: perimeter-network117961063178 (corp-resources-public) y 690885588241 (corp-resources-protected). Recuerda que corp-resources-public no está en el mismo perímetro de servicio que perimeter-network y corp-resources-protected.

El violationReason, RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER indica que algún recurso de la solicitud está fuera de un perímetro que se aplica a la solicitud. En este caso, ese recurso es corp-resources-public.

Mueve el archivo de Cloud Storage dentro del perímetro

En este ejemplo, en una VM del proyecto perimeter-network, se usa un comando para transferir un archivo de un depósito de Cloud Storage, ubicado en el proyecto corp-resources-protected, a otro depósito, ubicado en el proyecto corp-resources-public.

La VM usa el siguiente comando:

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

El comando muestra el siguiente resultado:

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

Se genera el siguiente registro de auditoría:

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

En este caso, el registro es menos claro porque el método enumerado es BillingRequiredRead, y la acción que se realiza es move. Esta es una limitación de la funcionalidad del registro de auditoría actual de los Controles del servicio de VPC.

Aunque el motivo es menos claro, este registro de auditoría indica que algún recurso de la solicitud está fuera de un perímetro que se aplica a la solicitud. En este caso, ese recurso es corp-resources-public.

Mueve el archivo de Cloud Storage fuera del perímetro

En este ejemplo, en una VM del proyecto public-network, se usa un comando para transferir un archivo de un depósito de Cloud Storage, ubicado en el proyecto corp-resources-protected, a otro depósito, ubicado en el proyecto corp-resources-public.

El proyecto corp-resources-protected está protegido por un perímetro de servicio. Los proyectos public-network y corp-resources-public están fuera del perímetro.

La VM usa el siguiente comando:

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

El comando muestra el siguiente resultado:

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

Se genera el siguiente registro de auditoría:

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

En este ejemplo, el registro de auditoría indica que no se pueden copiar datos en el límite de un perímetro de servicio (ambos recursos están en el registro de auditoría). Recuerda que la solicitud se origina fuera del perímetro (la VM en public-network) y que uno de los buckets está fuera del perímetro (corp-resources-public-1).

Desde afuera del perímetro, se puede escribir en el bucket corp-resources-public-1, por lo que se aprueba la verificación que falló en el ejemplo anterior. Sin embargo, la verificación posterior para copiar los datos falla.

En este ejemplo se muestra cómo, en ciertas ocasiones, una sola operación del usuario da como resultado varias operaciones internas que deben pasar la aplicación de los Controles del servicio de VPC.

Copia de un conjunto de datos de BigQuery desde una VM dentro del perímetro

En este ejemplo, una VM del proyecto 927005422713 (perimeter-network) intenta copiar un conjunto de datos de BigQuery del proyecto corp-resources-private a corp-resources-public (117961063178). perimeter-network y corp-resources-private comparten un perímetro, mientras que corp-resources-public está fuera del perímetro.

La VM usa el siguiente comando:

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

El comando muestra el siguiente resultado:

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

Se genera el siguiente registro de auditoría:

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

En este ejemplo, no hay ninguna acción subyacente de la API que muestre todos los recursos en juego en esta solicitud debido a limitaciones del mecanismo de registro y la arquitectura distribuida de BigQuery.

El registro de auditoría indica que la operación falló porque para copiar los datos, BigQuery debe acceder al proyecto de destino (corp-resources-public) mediante la red del proyecto perimeter-network (la fuente de la solicitud). Recuerda que corp-resources-public está fuera del perímetro que protege perimeter-network. Se rechaza la solicitud como un intento de robo de datos a corp-resources-public.

En este ejemplo, se muestra que una operación conceptual, como copiar datos, puede activar varios intentos para acceder a datos de diferentes sistemas de almacenamiento, como Cloud Storage, BigQuery y Bigtable. Según cómo se ejecute la operación, el registro de auditoría generado difiere del comando del usuario original. Además, cuando se realizan varias verificaciones dentro de un servicio determinado y estas fallan, el registro de auditoría generado se parece al comando del usuario original.

Lectura de trabajo de Dataproc desde el proyecto

En este ejemplo, se muestra cómo depurar errores de los Controles del servicio de VPC indirectos que se generan cuando se usan servicios de procesamiento de datos, como Dataproc.

En este ejemplo, un clúster de Dataproc se ejecuta en un proyecto que protegen los Controles del servicio de VPC. Hello-world.py es un trabajo pyspark que intenta acceder a los datos del depósito de Cloud Storage dentro del perímetro y, luego, escribirlo en otro depósito fuera del perímetro. Los Controles del servicio de VPC bloquean la operación que escribe datos en un bucket fuera del perímetro.

El siguiente comando se usa para ejecutar Hello-world.py:

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

El comando muestra el siguiente resultado:

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

Presta atención a la excepción de IO que se produce cuando se llama al método saveAsTextFile. Cloud Storage muestra un error 403 con el mensaje Request violates VPC Service Controls. El error indica que la operación del registro de auditoría de Cloud Storage debe revisarse.

En los registros de auditoría del proyecto perimeter-network, en los que se ejecutó el comando, hay un registro de auditoría para la operación 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"
}

Debido a las limitaciones del registro de auditoría, el methodName para Cloud Storage aparece como Read, aunque en realidad es una operación write. El registro de auditoría indica que la operación falló porque una red del proyecto corp-resources-private intentó acceder a los datos (como escribir, en este caso) de un recurso en el depósito corp-resources-public-1. Debido a las limitaciones del registro de auditoría de Cloud Storage, no está claro a qué bucket de proyecto pertenece corp-resources-public-1.

Para identificar el proyecto que contiene corp-resources-public-1, usa el siguiente comando:

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

El comando muestra el siguiente resultado: "projectNumber": "117961063178",

117961063178 es el proyecto corp-resources-public, que está fuera del perímetro externo. Por lo tanto, se espera que falle.

Error debido a servicios no compatibles

Algunos servicios de Google Cloud dependen de otros servicios, ya que parte de su implementación. Si un servicio no compatible, como App Engine se usa dentro de un proyecto protegido por un perímetro, el los recursos del servicio podrían no ser accesibles.

Para obtener información sobre casos problemáticos conocidos, consulta Limitaciones de servicios conocidas.

Servicio no compatible con la VIP restringida

Intentar acceder a una API que no es compatible con la VIP restringida de los Controles del servicio de VPC dará como resultado un error 403. Por ejemplo, los Controles del servicio de VPC no son compatibles con App Engine, por lo que la API de App Engine Admin no está disponible cuando se usa la VIP restringida.

Por ejemplo, supongamos que se usa el siguiente comando para enumerar todos los servicios de App Engine dentro de un perímetro de servicio:

gcloud app services list

El comando muestra el siguiente resultado:

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>

Este tipo de error es el esperado para los servicios que no son compatibles con los Controles del servicio de VPC y que no están disponibles en la VIP restringida. Si este error para un servicio que es compatible con los Controles del servicio de VPC, te recomendamos que revises el servicio limitaciones para ese servicio ver si se trata de una limitación conocida. De lo contrario, el problema debe denunciarse.

Exportación de registros al proyecto fuera del perímetro

En este ejemplo, los Controles del servicio de VPC bloquean una exportación de registro. El destino de la exportación, el proyecto corp-resources-public, está fuera del perímetro de los Controles del servicio de VPC, mientras que el receptor se crea en el proyecto perimeter-network, que está dentro del perímetro.

Por ejemplo, supongamos que se usa el siguiente comando:

gcloud logging sinks describe example-sink

El comando muestra el siguiente resultado:

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

Se genera el siguiente registro de auditoría:

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

El registro de auditoría se genera para BigQuery, no para Logging. Esto se debe a que BigQuery es el servicio de receptor al que Logging intenta escribir.

La exportación falla porque corp-resources-public está por fuera del perímetro que protege a perimeter-network.

En este ejemplo, se muestra que, en los casos en que un servicio de Google Cloud llama y otro con una cuenta de servicio administrada interna de Google Cloud como, por ejemplo, p927005422713-439672@gcp-sa-logging.iam.gserviceaccount.com, la "red" proyecto" (en este caso, perimeter-network) de la solicitud se deriva de esa con tu identidad. La misma identidad representa el recurso de exportación de registros en sí.

Este patrón es común en Google Cloud y se aplica a muchos casos de interacción de servicio a servicio.

Extracción de BigQuery a Cloud Storage

En este ejemplo, se describe cómo depurar extracciones de BigQuery con errores a Cloud Storage.

En este ejemplo, corp-resources-private y perimeter-network son proyectos protegidos por un perímetro de servicio. corp-resources-public es un proyecto que está fuera del perímetro.

Supongamos que se usó el siguiente comando:

bq extract babynames.yob2000

El comando muestra el siguiente resultado:

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.

En este caso, el error no implica de manera específica los Controles del servicio de VPC. Se muestra un error similar si hay una falla de administración de identidades y accesos.

Se genera el siguiente registro de auditoría:

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

En este registro de auditoría, storage-accessing@example.iam.gserviceaccount.com se identifica como la identidad que intenta ejecutar la operación. En este ejemplo, supongamos que storage-accessing@example.iam.gserviceaccount.com tiene los permisos de IAM necesarios para ejecutar el comando.

Debido a que los permisos de IAM no son el problema, el siguiente paso es verificar las fallas de los Controles del servicio de VPC.

El registro de auditoría del servicio de destino (Cloud Storage) contiene los motivos detallados de la falla:

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

En este registro, queda claro que se están usando los dos proyectos 1004338142803 (corp-resources-private-1) y corp-resources-public para completar el comando. Debido a que estos proyectos no comparten un perímetro, el trabajo de extracción falla.

En este ejemplo, se demuestra que, en las operaciones de varios servicios complejas, los registros de auditoría para los servicios de origen y de destino pueden contener datos de depuración útiles.

Acceso al perímetro a través de la puerta de enlace de Cloud NAT

En este ejemplo, supongamos que el proyecto A de la Org A no está configurado dentro de ningún perímetro. El proyecto B está protegido por un perímetro en otra organización. Los recursos privados del proyecto A usan la puerta de enlace de Cloud NAT para llegar en Internet, así como los servicios y las APIs de Google. Se configura un nivel de acceso en el proyecto B para permitir el acceso según las direcciones IP de la puerta de enlace externa del proyecto A.

Una VM que pertenece al proyecto A (que puede ser un nodo de Google Kubernetes Engine) intenta acceder a un recurso protegido en el proyecto B, pero la conexión falla, y se genera el siguiente registro de auditoría en el proyecto 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"
}

El recurso callerIp no registra una dirección IP externa. En lugar de la dirección IP externa de la puerta de enlace de Cloud NAT, el recurso callerIp muestra gce-internal-ip.

El campo callerIp se oculta como gce-internal-ip cuando las solicitudes provienen de un proyecto o una organización diferente, y la VM de Compute Engine de origen no tiene una dirección IP externa.

Cloud NAT tiene una integración con el Acceso privado a Google que habilita automáticamente el Acceso privado a Google en la subred del recurso y mantiene el tráfico a las APIs y los servicios de Google interno, en lugar de enrutarlo a Internet con la dirección IP externa de la puerta de enlace de Cloud NAT.

En este caso, como el tráfico se enruta dentro de la red interna de Google, el El campo RequestMetadata.caller_ip del objeto AuditLog se oculta como gce-internal-ip Para solucionar esto, en lugar de usar la puerta de enlace dirección IP externa de la puerta de enlace en el nivel de acceso para la lista de entidades permitidas basada en IP configurar una regla de entrada para permitir desde el proyecto o la cuenta de servicio.

¿Qué sigue?