Solucionar problemas habituales

En esta página se enumeran varios problemas que pueden surgir al configurar Controles de Servicio de VPC.

Comportamiento inesperado de la política de ámbito

Es posible que observes algunas infracciones inesperadas de Controles de Servicio de VPC que tu política de ámbito debería permitir. Se trata de un problema conocido: si no tienes una política de acceso a nivel de organización, es posible que tengas algunos problemas inesperados con tus políticas de acceso con ámbito.

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

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

Haz los cambios siguientes:

  • ORGANIZATION_ID: el ID de la organización.
  • POLICY_TITLE: título legible para personas de tu política de acceso.

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

VPC compartida

Cuando se usa una VPC compartida, un perímetro de servicio que incluya proyectos que pertenezcan a una red de VPC compartida también debe incluir el proyecto que aloja la red. Si los proyectos que pertenecen a una red de VPC compartida no están en el mismo perímetro que el proyecto del host, es posible que los servicios no funcionen correctamente 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 añadir una red VPC

Puede producirse el siguiente error al intentar añadir 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 ninguna subred.
  • El método llamador no tiene el permiso necesario.

Para solucionar este problema, siga estos pasos:

  1. Comprueba si la red de VPC especificada en el mensaje de error existe. Para ello, consulta las redes de tu proyecto.

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

      1. En la Google Cloud consola, ve a la página APIs & Services (APIs y servicios).
        Ve a APIs y servicios

      2. En la página APIs & Services (APIs y servicios), comprueba si la API Compute Engine aparece en la lista.

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

  2. Comprueba si existe al menos una subred en la red de VPC viendo las subredes. Si no hay subredes, añade una subred a la red de VPC.

  3. Comprueba si la persona que llama tiene el siguiente permiso en el proyecto host de la red VPC: compute.networks.get. Este permiso te permite ver las redes de VPC de un proyecto.

    • Pide al administrador de la organización propietaria del proyecto host de la red de VPC que conceda al llamante un rol de IAM con el permiso compute.networks.get en el proyecto host. Por ejemplo, el rol Lector de red de Compute.

      Para obtener más información sobre cómo conceder roles, consulta el artículo sobre cómo gestionar el acceso.

Asegúrate de leer las limitaciones asociadas al uso de redes de VPC en perímetros de servicio.

Solicitudes entre perímetros

Normalmente, los niveles de acceso se usan para permitir solicitudes de recursos protegidos que proceden de fuera de un perímetro de servicio y que se dirigen a recursos que se encuentran dentro de un perímetro.

Sin embargo, se deniega una solicitud de un proyecto de un perímetro para acceder a un recurso protegido de otro perímetro, aunque un nivel de acceso normalmente permita la solicitud.

Por ejemplo, supongamos que el proyecto A del perímetro 1 solicita un recurso del proyecto B. El recurso del proyecto B está protegido por el perímetro 2. Como el proyecto A está en un perímetro, aunque un nivel de acceso del perímetro 2 normalmente permita la solicitud del recurso protegido, la solicitud se deniega.

Utiliza uno de los siguientes métodos para facilitar las solicitudes entre perímetros:

  • Usa políticas de salida y de entrada. Para permitir que las solicitudes de otro perímetro accedan a los recursos protegidos de tu perímetro, el otro perímetro debe usar una política de salida y tú debes definir una política de entrada en tu perímetro.

  • Usa perímetros puente. Los puentes permiten que dos o más proyectos de perímetros diferentes hagan solicitudes a cualquier servicio de esos proyectos. Estas solicitudes se permiten aunque los servicios estén protegidos por los perímetros correspondientes.

  • Asegúrate de que tanto el servicio que envía la solicitud como el recurso de destino no estén protegidos por los perímetros. En este caso, la operación se realiza correctamente porque los servicios no están protegidos.

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

Al actualizar un perímetro que contiene un principal eliminado, puede producirse un error The email address is invalid or non-existent.

Para solucionar este problema, debe eliminar la dirección de correo no válida de todos los perímetros:

  1. Exporta todos tus perímetros. El siguiente comando de ejemplo exporta una lista de perímetros de servicio en formato YAML:

    gcloud access-context-manager perimeters list \
        --policy=POLICY_NAME \
        --format="json(name,title,description,perimeterType,status,spec,useExplicitDryRunSpec)" \
        > my-perimeters.yaml
  2. Elimina la dirección de correo no válida del archivo my-perimeters.yaml y guárdalo como my-perimeters-updated.yaml.

  3. Reemplaza todos tus perímetros en bloque.

Infracciones de las reglas de entrada y salida

El registro de auditoría contiene información sobre las infracciones de las reglas de entrada y salida, lo que te ayuda a comprender las infracciones del perímetro.

Infracción de regla de entrada

Una infracción de una regla de entrada indica que un cliente de API que está fuera del perímetro ha intentado acceder a un recurso que se encuentra dentro del perímetro. El perímetro de servicio rechaza la solicitud porque no hay ninguna regla de entrada ni ningún nivel de acceso que coincida.

Una infracción de una regla de entrada en el registro de auditoría contiene los siguientes detalles:

  • Nombre del perímetro en el que se ha producido la infracción de la regla de entrada.
  • El recurso que se encuentra dentro del perímetro al que ha intentado acceder el cliente de la API que está fuera del perímetro.

En el siguiente ejemplo de infracción de una regla de entrada, un cliente de API que está fuera del perímetro intenta acceder al segmento de Cloud Storage prod-protected-storage-bucket que está dentro del perímetro prod-perimeter.

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

Para solucionar 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.

Infracción de regla de salida

Una infracción de una regla de salida en el registro de auditoría indica uno de los siguientes eventos:

  • Un cliente de API que se encuentra dentro del perímetro ha intentado acceder a un recurso que está fuera del perímetro.
  • Una solicitud de API que implica 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 segmento está dentro del perímetro y el otro está fuera.

El perímetro de servicio rechaza la solicitud porque no hay ninguna regla de salida que coincida. Una infracción de una regla de salida en el registro de auditoría incluye los siguientes detalles:

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

En el siguiente ejemplo de infracción de una regla de salida, la solicitud de API incluye un recurso de projects/5678, que está dentro del perímetro prod-perimeter, y un objeto del segmento 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 solucionar este problema, crea una regla de salida para tu perímetro. Para obtener más información sobre las reglas de salida, consulta la referencia de las reglas de salida.

Depurar solicitudes bloqueadas por Controles de Servicio de VPC

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

Si el acceso se ha bloqueado de forma inesperada, consulta los registros de auditoría del proyecto protegido por el perímetro de servicio. Estos registros contienen datos significativos sobre los recursos solicitados y el motivo por el que se ha denegado la solicitud. Para obtener información sobre los registros de auditoría, consulta el artículo Diagnosticar problemas con la herramienta para solucionar problemas.

En las secciones siguientes se enumeran los valores de violationReason que puedes encontrar al usar Controles de Servicio de VPC.

NETWORK_NOT_IN_SAME_SERVICE_PERIMETER

Este problema puede deberse a uno de los siguientes motivos:

  • Un cliente de una red de VPC que se encuentra dentro de un perímetro de servicio intenta acceder a un proyecto que no está en el mismo perímetro. Esta solicitud provoca una infracción de salida. Crea una regla de salida para solucionar este problema.
  • Un cliente de una red de VPC que está fuera de un perímetro de servicio intenta acceder a un proyecto protegido por el perímetro de servicio. Esta solicitud provoca una infracción de entrada. Crea una regla de entrada para solucionar este problema.

El cliente puede enviar la solicitud desde una máquina virtual de Compute Engine o Google Kubernetes Engine, o desde una red local a través de Cloud Interconnect o una VPN configurada mediante una red de VPC.

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

Infracción de salida debido a NETWORK_NOT_IN_SAME_SERVICE_PERIMETER.

Aquí tienes 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>"
}
]

Donde:

  • <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 del proyecto Google Cloud que contiene tu red de VPC.
  • <RESOURCE_PROJECT_NUMBER> es el número de proyecto del Google Cloud proyecto que contiene el recurso.

En el siguiente diagrama se muestra que se produce una infracción de entrada cuando un cliente que está fuera del perímetro intenta acceder a un proyecto que está dentro del perímetro:

Una infracción de entrada debido a NETWORK_NOT_IN_SAME_SERVICE_PERIMETER.

Aquí tienes un ejemplo de una infracción de entrada:

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

Donde:

  • <RESOURCE_PROJECT_NUMBER> es el número de proyecto del Google Cloud proyecto que contiene el recurso.
  • <NETWORK_PROJECT_NUMBER> es el número del proyecto 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.

Resolución

Para solucionar este error, cree una regla de entrada o salida para su perímetro.

RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER

Este problema se produce cuando una sola solicitud accede a varios recursos, pero estos no están en el mismo perímetro de servicio. Este problema se produce independientemente de la ubicación del cliente y de si tiene acceso a los recursos.

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

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

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 de proyectos que se encuentran en dos perímetros de servicio diferentes.

Aquí tienes un ejemplo de una infracción 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>"
}
]

Donde:

  • <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 Google Cloud proyecto que está dentro del perímetro.
  • <RESOURCE_PROJECT_OUTSIDE_THIS_PERIMETER> es el número de proyecto del proyecto Google Cloud que está fuera del perímetro.

Resolución

Para resolver este problema, cree una regla de salida para su perímetro.

NO_MATCHING_ACCESS_LEVEL

Este problema se produce cuando la dirección IP, el requisito del dispositivo o la identidad del usuario no coinciden con ninguna regla de entrada ni con ningún nivel de acceso asignado al perímetro. Esto significa que un cliente que no forma parte de la red Google Cloud intenta acceder Google Cloud a los recursos de la red desde fuera del perímetro. Por ejemplo, la dirección IP correspondiente al campo callerIp del registro de auditoría no coincide con ningún intervalo CIDR definido en los niveles de acceso del perímetro de servicio.

Si falta la dirección IP de la persona que llama o aparece como una dirección IP interna, es posible que esta infracción se deba a un servicio Google Cloud que no esté integrado con Controles de Servicio de VPC. El motivo puede ser que el servicioGoogle Cloud intente acceder a un servicio protegido y falle, como es de esperar.

Para solucionar este problema, te recomendamos que crees una regla de entrada en lugar de un nivel de acceso, ya que las reglas de entrada proporcionan un control de acceso granular.

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

Una infracción de entrada debido a NO_MATCHING_ACCESS_LEVEL.

Aquí tienes 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>"
        }
  ]

Donde:

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

    Si usas un Google Cloud servicio que Controles de Servicio de VPC no admite, las direcciones de correo que pertenezcan al dominio google.com se ocultarán y se sustituirán por google-internal. google-internal hace referencia a las identidades internas propiedad de Google.

  • <PUBLIC_IP_ADDRESS> es la dirección IP de la persona que llama. En el caso de una persona que llama desde Internet, será la dirección IPv4 o IPv6 pública.

  • <RESOURCE_PROJECT_NUMBER> es el número de proyecto del Google Cloud proyecto 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 es posible que estos niveles de acceso no se especifiquen en el perímetro infringido.

SERVICE_NOT_ALLOWED_FROM_VPC

Este problema se produce cuando un cliente intenta acceder a Google Cloud recursos de una red de VPC. El cliente puede enviar la solicitud desde una máquina virtual de Compute Engine o Google Kubernetes Engine, o desde una red local a través de Cloud Interconnect o una VPN configurada mediante una red de VPC.

Para solucionar este problema, asegúrate de que el servicio al que se llama esté permitido en la configuración Servicios accesibles de VPC del perímetro de servicio.

Casos de ejemplo

En los siguientes ejemplos se tratan problemas que pueden surgir al usar Controles de Servicio de VPC.

Acceso a Cloud Storage desde un entorno local

En este ejemplo, Controles de Servicio de VPC bloquea una solicitud de la estación de trabajo de un empleado (identificada por callerIp) a un segmento de Cloud Storage del 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 está incluido en un perímetro de servicio. La estación de trabajo del empleado no forma parte de ninguna red dentro de ese perímetro. Como la estación de trabajo del empleado está fuera del perímetro, la solicitud se bloquea.

Acceso a 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 le deniega el acceso.

La VM usa la siguiente consulta:

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

La consulta devuelve 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 desambiguarla. Los recursos pertinentes en este caso se indican en dos lugares: VpcServiceControlAuditMetadata.resourceNames y requestMetadata.callerNetwork (el proyecto propietario de 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 lo está. En este caso, se deniega el acceso, como es de esperar.

Consulta de BigQuery entre proyectos

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 está en el mismo perímetro de servicio que perimeter-network, y corp-resources-public, que no lo está.

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 devuelve 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 observamos callerNetwork y VpcServiceControlAuditMetadata.resourceNames, vemos tres proyectos: perimeter-network, 117961063178 (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 y el RESOURCES_NOT_IN_SAME_SERVICE_PERIMETER indican que algún recurso de la solicitud está fuera de un perímetro que se aplica a la solicitud. En este caso, el recurso es corp-resources-public.

Mover un archivo de Cloud Storage dentro del perímetro

En este ejemplo, una VM del proyecto perimeter-network usa un comando para mover un archivo de un segmento de Cloud Storage, ubicado en el proyecto corp-resources-protected, a otro segmento, 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 devuelve 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 que aparece es BillingRequiredRead y la acción realizada es move. Esta es una limitación de la función de registro de auditoría actual de los Controles de Servicio de VPC.

Aunque el motivo no está tan 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, el recurso es corp-resources-public.

Mover un archivo de Cloud Storage fuera del perímetro

En este ejemplo, una VM del proyecto public-network usa un comando para mover un archivo de un segmento de Cloud Storage, ubicado en el proyecto corp-resources-protected, a otro segmento, 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 devuelve 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 entre los límites de un perímetro de servicio (ambos recursos están en el registro de auditoría). Recuerda que la solicitud procede de fuera del perímetro (la VM de public-network) y que uno de los segmentos se encuentra fuera del perímetro (corp-resources-public-1).

Desde fuera del perímetro, se puede escribir en el contenedor corp-resources-public-1, por lo que la comprobación que ha fallado en el ejemplo anterior se supera. Sin embargo, la comprobación posterior para copiar los datos no se realiza correctamente.

En este ejemplo se muestra cómo, en ocasiones, una sola operación de usuario da lugar a varias operaciones internas que deben superar la aplicación de Controles de Servicio de VPC.

Copia de conjuntos de datos de BigQuery desde una máquina virtual 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 devuelve 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 una sola acción de API subyacente que muestre todos los recursos que intervienen en esta solicitud debido a las limitaciones del mecanismo de registro y la arquitectura distribuida de BigQuery.

El registro de auditoría indica que la operación ha fallado porque, para copiar los datos, BigQuery debe acceder al proyecto de destino (corp-resources-public) mediante la red del proyecto perimeter-network (el origen de la solicitud). Recuerda que corp-resources-public está fuera del perímetro que protege perimeter-network. La solicitud se ha denegado porque se ha intentado exfiltrar datos a corp-resources-public.

En este ejemplo se muestra que una operación conceptual, como copiar datos, puede activar varios intentos de acceder a datos de diferentes sistemas de almacenamiento, como Cloud Storage, BigQuery y Bigtable. En función de cómo se ejecute la operación, el registro de auditoría generado será diferente del comando de usuario original. Además, cuando se realizan varias comprobaciones en un servicio determinado y es posible que fallen, el registro de auditoría generado tiene un aspecto diferente al del comando de usuario original.

Lectura de tareas de Dataproc de un proyecto

En este ejemplo se muestra cómo depurar errores indirectos de Controles de Servicio de VPC que se producen al usar servicios de procesamiento de datos, como Dataproc.

En este ejemplo, un clúster de Dataproc se ejecuta en un proyecto protegido por Controles de Servicio de VPC. Hello-world.py es un trabajo de PySpark que intenta acceder a los datos de un segmento de Cloud Storage que está dentro del perímetro y, a continuación, escribirlos en otro segmento que está fuera del perímetro. Controles de Servicio de VPC bloquea la operación que escribe datos en un bucket que está 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 devuelve 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].

Ten en cuenta la excepción de E/S que se produce cuando se llama al método saveAsTextFile. Cloud Storage devuelve un error 403 con el mensaje Request violates VPC Service Controls. El error indica que se debe revisar la operación del registro de auditoría de Cloud Storage.

En los registros de auditoría del proyecto perimeter-network, donde se ejecutó el comando, hay un registro de auditoría de 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 de los registros de auditoría, el methodName de Cloud Storage se indica como Read, aunque en realidad es una operación write. El registro de auditoría indica que la operación ha fallado porque una red del proyecto corp-resources-private intentaba acceder a los datos (en este caso, escribir) de un recurso del segmento corp-resources-public-1. Debido a las limitaciones del registro de auditoría de Cloud Storage, no está claro a qué proyecto pertenece el segmento 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 devuelve el siguiente resultado: "projectNumber": "117961063178",

117961063178 es el proyecto corp-resources-public, que está fuera del perímetro. Por lo tanto, es normal que se produzca un error.

Error debido a servicios no admitidos

Algunos Google Cloud servicios dependen de otros Google Cloud servicios como parte de su implementación. Si se usa un servicio no compatible, como App Engine, en un proyecto protegido por un perímetro, es posible que no se pueda acceder a los recursos del servicio.

Para obtener información sobre los casos problemáticos conocidos, consulta Limitaciones conocidas del servicio.

Servicio no admitido con VIP restringido

Si intentas acceder a una API que no es compatible con la IP virtual restringida de Controles de Servicio de VPC, se producirá un error 403. Por ejemplo, Controles de Servicio de VPC no es compatible con App Engine, por lo que la API Admin de App Engine no está disponible cuando se usa la IP virtual 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 devuelve 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 habitual en los servicios que no son compatibles con Controles de Servicio de VPC y que no están disponibles en la IP virtual restringida. Si se produce este error en un servicio que es compatible con Controles de Servicio de VPC, te recomendamos que consultes las limitaciones conocidas del servicio para ver si se trata de una limitación conocida. De lo contrario, debes informar del problema.

Exportación de registros a un proyecto fuera del perímetro

En este ejemplo, los Controles de Servicio de VPC bloquean una exportación de registros. El destino de exportación, el proyecto corp-resources-public, está fuera del perímetro de Controles de 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 devuelve 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á fuera del perímetro que protege perimeter-network.

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

Este patrón es habitual en Google Cloud y se aplica a numerosos casos de interacción entre servicios.

Extracción de BigQuery a Cloud Storage

En este ejemplo se describe cómo depurar extracciones de BigQuery a Cloud Storage que han fallado.

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 existe fuera del perímetro.

Supongamos que se ha usado el siguiente comando:

bq extract babynames.yob2000

El comando devuelve 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 específicamente a Controles de Servicio de VPC. Se muestra un error similar si se produce un fallo en Gestió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 gestión de identidades y accesos necesarios para ejecutar el comando.

Como los permisos de gestión de identidades y accesos no son el problema, el siguiente paso es comprobar si hay errores en Controles de Servicio de VPC.

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

{
 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, se puede ver que se están usando los dos proyectos 1004338142803 (corp-resources-private-1) y corp-resources-public para completar el comando. Como esos proyectos no comparten un perímetro, la tarea de extracción falla.

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

Acceso al perímetro a través de una pasarela de Cloud NAT

En este ejemplo, supongamos que el proyecto A de la organización A no está configurado en ningún perímetro. El proyecto B está protegido por un perímetro de otra organización. Los recursos privados del proyecto A usan la pasarela Cloud NAT para acceder a Internet y a las APIs y servicios de Google. Se configura un nivel de acceso en el proyecto B para permitir el acceso en función de las direcciones IP de la pasarela 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 del 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 pasarela Cloud NAT, el recurso callerIp muestra gce-internal-ip.

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

Cloud NAT se integra con Acceso privado de Google para habilitar automáticamente Acceso privado de Google en la subred del recurso y mantener el tráfico a las APIs y los servicios de Google interno en lugar de enrutarlo a Internet mediante la dirección IP externa de la puerta de enlace de Cloud NAT.

En este caso, como el tráfico se enruta en la red interna de Google, el campo RequestMetadata.caller_ip del objeto AuditLog se oculta y se muestra como gce-internal-ip. Para solucionar este problema, en lugar de usar la dirección IP externa de la pasarela Cloud NAT en el nivel de acceso de la lista de permitidas basada en IP, configura una regla de entrada para permitir el acceso desde el proyecto o la cuenta de servicio.

Siguientes pasos