Public Assets from Cloud Asset Inventory

Table of contents

An unfortunately common vulnerability with cloud deployments is unintentionally publicly accessible resources. The first several sheets described below use the Cloud Asset Inventory service to list public assets as well describe how to use Organization Policies to restrict future public exposure. See the Limiting public IPs on Google Cloud blog post and video for an excellent summary on using organization policies to restrict public IPs for most Google Cloud resources.

Public IAM Policies

This sheet contains the list of resources with IAM policies attached containing the allUsers or allAuthenticatedUsers effectively making that resource publicly accessible. Storage buckets, Cloud Functions, Cloud Run services are several of the resources that can be made public through use of these IAM principles.

The iam.allowedPolicyMemberDomains organization policy can be used to restrict usage of the allUsers and allAuthenticatedUsers principles and consequently restrict resources from being made publicly accessible.

Below is a Cloud Asset Inventory gcloud command used to generate a similar output to this sheet for your organization by specifying an $ORGANIZATION_ID.

gcloud beta asset search-all-iam-policies --scope="organizations/$ORGANIZATION_ID" \
  --query='memberTypes:("allUsers" OR "allAuthenticatedUsers")'

Public GCE VMs

This sheet contains the list of running Compute Engine instances with external (aka. public) IP addresses attached. This can be useful for enabling the compute.vmExternalIpAccess organization policy when creating an initial list of projects to be exempted from the policy.

While removing external IP addresses in favor of accessing Compute Engine instances via internal IP addresses using Google External Load Balancers or the Identity Aware Proxy, VPC firewall rules can also be used to limit the destination ports, destination protocols, and source IP addresses that can access the instances as an alternative.

Below is an equivalent Cloud Asset Inventory gcloud command used to generate a CSV of this sheet for your organization by specifying an $ORGANIZATION_ID.

gcloud beta asset list --organization=$ORGANIZATION_ID --content-type='resource' \
  --asset-types='compute.googleapis.com/Instance' \
  --filter="resource.data.networkInterfaces[].accessConfigs[].type='ONE_TO_ONE_NAT' AND resource.data.status='RUNNING'" \
  --format="csv(name.scope(projects).segment(0), resource.data.name, resource.data.networkInterfaces[].accessConfigs[0].natIP, resource.data.status, resource.data.creationTimestamp, resource.data.lastStartTimestamp)" > public_instances.csv

Public CloudSQL Instances

This sheet contains the list of running CloudSQL database instances with a public ip address. This can be useful for enabling the sql.restrictPublicIp organization policy when creating an initial list of projects to be exempted from the policy.

Keep in mind that CloudSQL database instances can have authorized networks which limit the sources from where the database with a public instance can be accessed on the internet, although private IP connectivity should be preferred for security along with Cloud SQL Auth proxy or IAM database authentication.

Below is an equivalent Cloud Asset Inventory gcloud command used to generate a CSV of this sheet for your organization by specifying an $ORGANIZATION_ID.

gcloud beta asset list --organization=$ORGANIZATION_ID --content-type='resource' \
  --asset-types='sqladmin.googleapis.com/Instance' \
  --filter="resource.data.settings.activationPolicy='ALWAYS' AND resource.data.settings.ipConfiguration.ipv4Enabled='TRUE'" \
  --format="csv(resource.data.project, resource.data.name, resource.data.gceZone, resource.data.settings.ipConfiguration.ipv4Enabled, resource.data.settings.ipConfiguration.requireSsl, resource.data.serverCaCert.createTime, resource.data.settings.activationPolicy)" > public_cloudsql_instances.csv

Public Cloud Functions

This sheet contains the list of running Cloud Functions with an HTTPS Trigger and ingress settings allowing all traffic as opposed to restricting it to internal VPC traffic.

By default, Cloud Functions require IAM authentication and to make a function truly public it needs to have an unauthenticated invocation IAM binding set after January 15, 2020 which this sheet does also check. The results in this sheet will overlap with the Public IAM Policies sheet for Cloud Functions which have either allUsers or allAuthentication invocation IAM bindings. Because of this both the iam.allowedPolicyMemberDomains (Recommended) and the cloudfunctions.allowedIngressSettings organization policies can be used to restrict Cloud Functions from being made public.

Below are two Cloud Asset Inventory gcloud commands listing assets and search IAM policies that when combined can be used to generate a similar output of this sheet for your organization by specifying an $ORGANIZATION_ID.

gcloud beta asset list --organization=$ORGANIZATION_ID --content-type='resource' \
  --asset-types='cloudfunctions.googleapis.com/CloudFunction' \
  --filter="resource.data.status='ACTIVE' AND resource.data.list(show="keys"):'httpsTrigger' AND resource.data.ingressSettings='ALLOW_ALL'" \
  --format="csv(resource.data.httpsTrigger.url)" > public_cloud_functions.csv
gcloud beta asset search-all-iam-policies --scope="organizations/$ORGANIZATION_ID" --query='memberTypes:("allUsers" OR "allAuthenticatedUsers") AND policy.role.permissions:cloudfunctions.functions.invoke'

Public GKE Clusters

This sheet contains the list of running Google Kubernetes Engine (GKE) clusters with a public endpoint enabled. Authorized Networks (essentially a firewall for the Kubernetes API) for the public clusters are also listed as they are a recommended hardening mechanism if the private cluster endpoint cannot be enabled exclusively. GKE clusters by default, allow any authenticated Google account as well as unauthenticated users access to some read-only APIs which can leak information such as installed CustomResourceDefinitions. In order to block the public exposure of these discovery APIs, it is recommended to use authorized networks or a private GKE cluster.

Alternative authentication mechanisms and legacy ABAC (Attribute-Based Access Control) are also included in the list of public GKE clusters as by default in newer deployments of GKE they should be disabled.

Below is an equivalent Cloud Asset Inventory gcloud command used to generate a CSV of this sheet for your organization by specifying an $ORGANIZATION_ID.

gcloud beta asset list --organization=$ORGANIZATION_ID --content-type='resource' \
  --asset-types='container.googleapis.com/Cluster' \
  --filter="resource.data.privateClusterConfig.enabledPrivateEndpoint AND resource.data.status='RUNNING'" \
  --format="csv(name.scope(projects).segment(0), resource.data.name, resource.data.endpoint, resource.data.privateClusterConfig.enablePrivateEndpoint, resource.data.masterAuthorizedNetworksConfig.cidrBlocks, resource.data.status, resource.data.createTime)" > public_clusters.csv

Public App Engine

This sheet contains the serving App Engine applications that are publicly accessible by default including all running versions of the application. Using Serverless VPC Access an App Engine application can be made private by configuring the ingress traffic to be only allowed from your VPC using the Ingress Settings by setting it to Internal-only.

Google’s Identity Aware Proxy can be enabled on App Engine applications to provide a default authentication mechanism for publicly accessible apps.

Below are two Cloud Asset Inventory gcloud commands that when combined are used to generate a similar output of this sheet for your organization by specifying an $ORGANIZATION_ID.

gcloud beta asset list --organization=$ORGANIZATION_ID --content-type='resource' \
  --asset-types='appengine.googleapis.com/Service'
gcloud beta asset list --organization=$ORGANIZATION_ID --content-type='resource' \
  --asset-types='appengine.googleapis.com/Application'

Public Cloud Run

This sheet contains the active Cloud Run services with ingress settings allowing all traffic as opposed to restricting it to internal VPC traffic using Serverless VPC Access.

By default, Cloud Run services require IAM authentication and to make a service truly public it needs to have an unauthenticated invocation IAM binding which this sheet does also check. The results in this sheet will overlap with the Public IAM Policies sheet for Cloud Run services which have either allUsers or allAuthentication invocation IAM bindings. Because of this both the iam.allowedPolicyMemberDomains (Recommended) and the run.allowedIngress organization policies can be used to restrict Cloud Run services from being made public.

Below are two Cloud Asset Inventory gcloud commands listing assets and search IAM policies that when combined can be used to generate a similar output of this sheet for your organization by specifying an $ORGANIZATION_ID.

gcloud beta asset list --organization=$ORGANIZATION_ID --content-type='resource' \
  --asset-types='run.googleapis.com/Service'
gcloud beta asset search-all-iam-policies --scope="organizations/$ORGANIZATION_ID" --query='memberTypes:("allUsers" OR "allAuthenticatedUsers") AND policy.role.permissions:run.routes.invoke'

External Load Balancers

The sheets below list the several components of external Google Cloud Load Balancers (GCLBs or GLBs) that can be queried from the Cloud Asset inventory service using Cloud Asset Inventory gcloud commands.

GCLBs require two components: a frontend “forwarding rule” and a backend service. The external frontend “forwarding rules” can be restricted using the compute.restrictProtocolForwardingCreationForTypes organization policy. The external backend services can be restricted using the compute.restrictLoadBalancerCreationForTypes organization policy.

External Global Forwarding Rules

Below is an equivalent Cloud Asset Inventory gcloud command used to generate a CSV of this sheet for your organization by specifying an $ORGANIZATION_ID.G

gcloud beta asset list --organization=$ORGANIZATION_ID --content-type='resource' \
  --asset-types='compute.googleapis.com/GlobalForwardingRule' \
  --filter="resource.data.loadBalancingScheme='EXTERNAL'" \
  --format="csv(name.scope(projects).segment(0), resource.data.name, resource.data.IPAddress, resource.data.portRange, resource.data.loadBalancingScheme, resource.data.creationTimestamp)" > external_global_forwarding_rule.csv

External Forwarding Rules

Below is an equivalent Cloud Asset Inventory gcloud command used to generate a CSV of this sheet for your organization by specifying an $ORGANIZATION_ID.

gcloud beta asset list --organization=$ORGANIZATION_ID --content-type='resource' \
  --asset-types='compute.googleapis.com/ForwardingRule' \
  --filter="resource.data.loadBalancingScheme='EXTERNAL'" \
  --format="csv(name.scope(projects).segment(0), resource.data.name, resource.data.IPAddress, resource.data.portRange, resource.data.loadBalancingScheme, resource.data.creationTimestamp)" > external_forwarding_rule.csv

External Backend Services

Below is an equivalent Cloud Asset Inventory gcloud command used to generate a CSV of this sheet for your organization by specifying an $ORGANIZATION_ID.

gcloud beta asset list --organization=$ORGANIZATION_ID --content-type='resource' \
  --asset-types='compute.googleapis.com/BackendService' \
  --filter="resource.data.loadBalancingScheme='EXTERNAL'" \
  --format="csv(name.scope(projects).segment(0), resource.data.name, resource.data.protocol, resource.data.port, resource.data.loadBalancingScheme, resource.data.creationTimestamp)" > external_backend_service.csv

External Regional Backend Services

Below is an equivalent Cloud Asset Inventory gcloud command used to generate a CSV of this sheet for your organization by specifying an $ORGANIZATION_ID.

gcloud beta asset list --organization=$ORGANIZATION_ID --content-type='resource' \
  --asset-types='compute.googleapis.com/RegionBackendService' \
  --filter="resource.data.loadBalancingScheme='EXTERNAL'" \
  --format="csv(name.scope(projects).segment(0), resource.data.name, resource.data.protocol, resource.data.port, resource.data.loadBalancingScheme, resource.data.creationTimestamp)" > external_regional_backend_service.csv