Skip to content

GCP Cloud Resource Discovery

Version: 1.1 Last Updated: 2026-06-24

Automated discovery and interrogation of Google Cloud Platform resources for cryptographic configuration collection.


Overview

GCP Cloud Resource Discovery enables automatic discovery and detailed interrogation of GCP resources that terminate TLS/HTTPS, providing comprehensive cryptographic configuration information directly from the GCP Compute Engine API.

GCP uses a proxy-based load balancing architecture. TLS termination happens at Target HTTPS Proxies and Target SSL Proxies, which reference SSL Policies (cipher suite profiles) and SSL Certificates. Forwarding Rules map public IPs to these proxies.


Supported Resources

Target HTTPS Proxy (HTTPS Load Balancer)

External and internal HTTPS load balancers using Target HTTPS Proxies.

  • Discovery: Automatic enumeration of all Target HTTPS Proxies in the project
  • Interrogation: Detailed crypto configuration extraction including:
  • SSL policy (profile, minimum TLS version, cipher suites)
  • SSL certificate metadata (managed/self-managed, SANs, expiry)
  • Forwarding rule details (public IP, port range, load balancing scheme)
  • TLS Handshake: Performs actual TLS handshake against public endpoints to verify negotiated parameters and extract certificate chains

Target SSL Proxy (SSL Proxy Load Balancer)

SSL Proxy load balancers for non-HTTP TLS termination.

  • Discovery: Automatic enumeration of all Target SSL Proxies in the project
  • Interrogation: Same crypto configuration extraction as HTTPS proxies
  • TLS Handshake: Same handshake verification as HTTPS proxies

Cloud KMS (key management inventory)

  • Discovery: Enumerates KMS locations → key rings → crypto keys across the project
  • Interrogation: Per key — algorithm normalized to a canonical key spec (e.g. GOOGLE_SYMMETRIC_ENCRYPTION→AES-256, RSA_DECRYPT_OAEP_4096_*→RSA-4096, EC_SIGN_P256_*→ECC P-256), key state, purpose, protection level (SOFTWARE / HSM / EXTERNAL), and rotation period
  • Keys are recorded in the key inventory (Inventory → Keys, provider gcp), which also creates each key's Key Store Infrastructure Asset
  • Note: key metadata only — Cloud KMS does not expose key material, and the platform does not retrieve it

Cloud Storage (at-rest encryption)

  • Discovery: Enumerates buckets in the project
  • Interrogation: at-rest encryption is always AES-256; surfaces Google-managed (default) vs customer-managed (CMEK, defaultKmsKeyName set) plus the key reference

Cloud SQL (at-rest encryption)

  • Discovery: Enumerates Cloud SQL instances in the project
  • Interrogation: at-rest encryption (AES-256); surfaces Google-managed vs customer-managed (CMEK, diskEncryptionConfiguration.kmsKeyName), with the database engine derived from databaseVersion

What is enumerated

Alongside the cryptographic resources above, a run inventories the project's compute and network estate: Compute Engine instances, VPC networks, their subnetworks, and firewall membership. This is inventory rather than cryptography — an instance negotiates no protocol and states no at-rest encryption — and it is what makes the rest of a run legible.

It is controlled by one switch per integration, Inventory compute instances and their networks in Discovery → Cloud → Edit integration. It is on by default, including for integrations created before this feature existed.

Exact API calls

Call Scope Produces
compute.instances.aggregatedList Project, all zones, paginated One asset per instance, with its network interfaces
compute.networks.list Project (networks are global), paginated The VPC networks the prefixes belong to (a legacy network's own range is a prefix)
compute.subnetworks.aggregatedList Project, all regions, paginated One prefix per regional range (Inventory → Networks)
compute.firewalls.list Project (firewalls are global), paginated Firewall membership — never the rules

The two aggregated forms are deliberate: GCP has around a hundred zones, and a per-zone instances.list loop would be a hundred calls to find a project with three VMs in it.

Cost. Four extra project-wide calls per run, each paginated. GCP enumeration is not per-region, so the number does not grow with the number of regions you use.

IAM permissions to add

compute.instances.list
compute.networks.list
compute.subnetworks.list
compute.firewalls.list

All four are in roles/compute.viewer, which the load-balancer discovery already requires — so a service account that can already discover HTTPS load balancers needs no change. The integration's existing cloud-platform.read-only scope covers them.

What lands in the inventory

GCP resource Lands as Identified by
Compute Engine instance Compute instance asset projects/<p>/zones/<z>/instances/<name>
Network interface an interface of the instance (type Virtual), named as in GCE (nic0, …) the instance and the interface's name
A network's regional range a prefix, in Inventory → Networks the range, and projects/<p>/global/networks/<name> as its cloud network
Firewall rule not an asset recorded as membership on the instances it targets

The identifier is the partial resource name, not the self link. The Compute API echoes www.googleapis.com on some surfaces and compute.googleapis.com on others, and an identifier that changed with the endpoint host would create a second asset for one instance.

A VPC network and its ranges are not assets: each range is a prefix naming the network it belongs to (a custom-mode network has no range of its own, so it contributes none), and the network an instance is in is the prefix its address falls in. Each instance's Interfaces tab lists its network interfaces with their internal addresses at their range's prefix length; GCE states no MAC for one, and the external NAT address is not collected. The instance also carries its machine type, its labels, and the cloud.* placement facts.

Firewall membership is computed, because GCP has no security-group object: a firewall rule attaches to a network and selects instances by network tag. The rules implemented are GCP's own —

  • same network, and
  • the rule's targetTags intersect the instance's tags, or
  • the rule targets neither tags nor service accounts, in which case it applies to every instance on the network.

A rule targeted by service account is not claimed to apply: the platform does not collect an instance's service account, and a false membership is worse than a missing one. Disabled rules select nothing.

New assets arrive in Pending approval. A re-run matches on the resource name and updates.

Two machines that share a private address

A private address is not unique in a project, and the inventory is built so that it never has to be.

  • Two VPC networks using the same address range are two address spaces. Two instances at the same private address in two different VPC networks are two assets, and neither is affected by the other.
  • An address reused inside one VPC network — the provider gives a freed address to the next instance created — is genuinely the same address space, and the platform cannot tell from outside whether an address that changed hands means a new machine or a rebuilt one. So it does not guess: the new instance is recorded as its own asset in Pending approval, and a review item appears in Approvals asking whether it is the machine that used to answer to that address. You decide; nothing is merged on your behalf.

The previous asset is left exactly as it was, so its history, tags and findings stay with the machine they were recorded against.

What is deliberately NOT collected

  • metadata.items. This is GCP's user-data — startup-script and per-instance ssh-keys — and it routinely carries credentials. There is no field for it.
  • disks[]. It carries diskEncryptionKey, which can hold a customer-supplied key's rsaEncryptedKey, and licenses, which is an image label rather than a statement about the running guest.
  • Firewall rule content. allowed, denied, sourceRanges and destinationRanges are a map of your network. Only a rule's identity and its targeting are read, and the targeting only so that membership can be computed.
  • serviceAccounts[]. A VM's service-account email and scopes describe what it is authorised to do, not what it is.
  • accessConfigs (the external address). Public exposure is a posture question answered by probing, and an ephemeral external address changes on every stop/start.
  • Guest operating system and source image. GCE states neither on a list call; the image is on the boot disk, which is not collected. The OS fields stay empty rather than carrying a guess.
  • The default internal DNS name. <name>.c.<project>.internal is derived, not stated. An instance's hostname is recorded only when the operator set a custom one.

Workflow

1. Configure GCP Integration

Store GCP credentials in platform integrations:

UI: Discovery → Cloud → Add integration, choose provider GCP.

Required Fields: - Integration Type: gcp - Project ID: GCP project ID (not project number) - Service Account JSON: Complete JSON key file for a service account, exactly as Google issued it. Its token_uri must be Google's OAuth endpoint (https://oauth2.googleapis.com/token, as every Google-issued key says); a key naming any other token endpoint is refused rather than used.

Credentials are encrypted at rest using the platform's master encryption key.

Test the connection

Discovery → Cloud → the plug icon on the integration contacts Google for real: it builds the same client discovery uses from the stored integration, exchanges the service-account key for an access token, and reads the project through the Compute API (listing at most one SSL policy). A green test therefore proves the key is live and the account can read the project with roles/compute.viewer.

When it fails, it shows Google's own answer — invalid_grant for a revoked or deleted key, PERMISSION_DENIED with the missing permission when the account has no role on the project, or a not found that points at the project ID or a disabled Compute Engine API. A stored key the platform can no longer read (saved under a retired encryption key) is reported with an instruction to re-enter it, and is never sent to Google.

The integration's Enabled switch stops it being used: Discover and scheduled runs of a disabled integration fail at once with the integration is disabled.

2. Discover GCP Resources

Initiate cloud resource discovery:

UI: Discovery → Cloud → the ▶ (play) icon on the integration. The dialog offers every type below — HTTPS Load Balancer, SSL Proxy, Cloud KMS keys, Cloud Storage encryption and Cloud SQL encryption — all ticked by default.

A schedule for the integration (Discovery → Scheduled Scans) runs that same default set and delivers the same results, the at-rest bucket and Cloud SQL records included.

API: POST /api/v1/device-interrogation-service/cloud/discover

Request Body:

{
  "integration_id": "uuid-of-gcp-integration",
  "resource_types": ["load_balancer", "ssl_proxy", "kms", "storage", "cloudsql"]
}

Resource types: load_balancer (Target HTTPS Proxies), ssl_proxy (Target SSL Proxies), kms / cloudkms (Cloud KMS keys), storage / gcs (Cloud Storage at-rest encryption), cloudsql / sql (Cloud SQL at-rest encryption).

Note: GCP load balancer resources are global (not regional), so no region parameter is needed for discovery. The integration's region field is informational metadata only. KMS is enumerated across all KMS locations in the project.

3. Automatic Processing

The service automatically: 1. Creates a discovery job 2. Authenticates using the service account credentials (JWT-based OAuth2) 3. Enumerates Target HTTPS Proxies and/or Target SSL Proxies 4. For each proxy, fetches the associated SSL Policy and SSL Certificates 5. Resolves the Forwarding Rule to determine the public IP 6. Performs a TLS handshake against reachable endpoints 7. Creates or updates device records with crypto configuration metadata 8. Writes discoveries to the sensor_discoveries table (unified pipeline)

4. Automatic Asset Creation

Cloud discoveries are automatically processed by the discovery-processor-service:

  1. Unified Pipeline: GCP discoveries flow through the same sensor_discoveries pipeline as AWS, Azure, and sensor discoveries
  2. Auto-Processing: The discovery-processor-service automatically processes discoveries within seconds
  3. Network Classification: Discoveries are classified by the account they were listed from — a cloud resource's ownership comes from the account it lives in, not from an IP address it may not have
  4. Auto-Approval: The project's account-level rule is evaluated — the integration's Auto-approve resources switch, on by default; the resource also hangs off the project's Cloud Account asset. See Asset Approval
  5. Asset Creation: Assets are created with monitoring (if auto-approved) or pending_approval status

5. Review and Approve Assets

Review cloud-discovered assets in the Discovery Approvals modal:

UI: Navigate to Assets > Discovery Approvals

GCP-discovered assets appear alongside other discoveries with: - Hostname or public IP address - Port (typically 443) - Protocol (TLS/HTTPS) - Protocol version (from SSL policy or TLS handshake) - Cipher suite (from SSL policy or TLS handshake) - Certificate information (SANs, expiry, managed status) - Device ID (links asset to parent GCP device) - Discovery source indicator (shows as cloud discovery)


Crypto Configuration Details

SSL Policies

For each proxy, the service extracts SSL policy configuration:

  • Policy Name: e.g., my-ssl-policy
  • Profile: COMPATIBLE, MODERN, RESTRICTED, or CUSTOM
  • Minimum TLS Version: TLS 1.0, TLS 1.1, or TLS 1.2
  • Enabled Cipher Suites: Complete list of effective cipher suites
  • Custom Features: For CUSTOM profiles, the explicitly configured cipher suites

GCP SSL Policy Profiles

Profile Min TLS Description
COMPATIBLE TLS 1.0 Broadest compatibility, includes legacy ciphers
MODERN TLS 1.0 Modern ciphers only, wider client support
RESTRICTED TLS 1.2 Strict security, limited cipher set
CUSTOM Configurable User-selected cipher suites

Default behavior: Proxies without an explicit SSL policy use GCP's default settings (equivalent to COMPATIBLE profile with TLS 1.0 minimum).

SSL Certificates

The service discovers certificate metadata:

  • Certificate Name: GCP resource name
  • Type: SELF_MANAGED or MANAGED (Google-managed)
  • Subject Alternative Names: Domain names covered
  • Expiry Time: Certificate expiration date
  • Managed Status: For managed certificates — provisioning status and per-domain status

TLS Handshake Verification

For proxies with a reachable public IP (via Forwarding Rules), the service performs a live TLS handshake to extract:

  • Negotiated TLS version and cipher suite
  • Full certificate chain (leaf + intermediates)
  • Certificate fingerprints (SHA-256, SHA-1)
  • Key algorithm and size
  • Subject Alternative Names

Fallback Behavior

  • Internal load balancers: If the forwarding rule uses INTERNAL scheme, the TLS handshake may fail. The device and crypto configuration are still created from API metadata.
  • No forwarding rule: Proxies without associated forwarding rules are still discovered with SSL policy details.
  • Handshake timeout: Default 10-second timeout prevents blocking on unreachable endpoints.
  • The handshake_verified flag indicates whether crypto config was obtained via TLS handshake (true) or API metadata only (false).

Example Discovery Result

{
  "job_id": "uuid",
  "devices": [
    {
      "id": "device-uuid",
      "device_type": "gcp_https_load_balancer",
      "vendor": "Google Cloud",
      "hostname": "34.120.10.50",
      "ip_address": "34.120.10.50",
      "metadata": {
        "gcp_resource_id": "https://compute.googleapis.com/compute/v1/projects/my-project/global/targetHttpsProxies/my-lb",
        "proxy_type": "target_https_proxy",
        "project_id": "my-project",
        "ssl_policy_name": "modern-ssl-policy",
        "ssl_policy_profile": "MODERN",
        "forwarding_rule": "my-forwarding-rule",
        "load_balancing_scheme": "EXTERNAL",
        "port_range": "443-443",
        "crypto_configs": [
          {
            "protocol": "HTTPS",
            "protocol_version": "TLS 1.3",
            "cipher_suite": "TLS_AES_256_GCM_SHA384",
            "cipher_suites": ["TLS_AES_128_GCM_SHA256", "TLS_AES_256_GCM_SHA384"],
            "port": 443,
            "handshake_verified": true,
            "certificates": [
              {
                "subject_dn": "CN=example.com",
                "issuer_dn": "CN=GTS CA 1P5,O=Google Trust Services LLC,C=US",
                "not_before": "2026-01-15T00:00:00Z",
                "not_after": "2026-04-15T00:00:00Z",
                "fingerprint_sha256": "abcdef1234...",
                "key_algorithm": "ECDSA",
                "key_size": 256,
                "chain_order": 0
              }
            ],
            "metadata": {
              "ssl_policy": "modern-ssl-policy",
              "ssl_policy_profile": "MODERN"
            }
          }
        ],
        "certificates": [
          {
            "name": "my-managed-cert",
            "type": "MANAGED",
            "managed": true,
            "managed_status": "ACTIVE",
            "managed_domains": ["example.com", "www.example.com"],
            "subject_alternative_names": ["example.com", "www.example.com"],
            "expire_time": "2026-04-15T00:00:00Z"
          }
        ]
      }
    }
  ],
  "count": 1
}

Error Handling

Each resource type is collected independently and its outcome is recorded on the job (Discovery → Discovery Jobs → the job → Resource types), the same way as for AWS — see Reading the result:

  • Permission errors — recorded against the type with Google's own status (PERMISSION_DENIED) and message, which names the missing permission. The type reads Could not collect, never "none found".
  • One type failing never stops the others. A load-balancer or SSL-proxy listing that is refused no longer abandons the run, and a Cloud KMS, Cloud Storage or Cloud SQL listing that is refused no longer reports success with zero found. A run where anything failed is partly collected, not a success.
  • Token errors — a key Google refuses fails every type with invalid_grant; the connection test shows the same.

Security Considerations

Credential Management

  • Service account key encrypted at rest in platform_integrations table
  • Decrypted only when needed for API calls
  • JWT-based OAuth2 token exchange — tokens are short-lived (1 hour) and cached
  • Credentials never logged or exposed in responses

IAM Permissions Required

Minimum IAM roles for GCP discovery, by resource family:

Resource family Role
Load balancers / SSL proxies roles/compute.viewer
Cloud KMS keys roles/cloudkms.viewer
Cloud Storage buckets roles/storage.admin (read is sufficient: storage.buckets.list/get)
Cloud SQL instances roles/cloudsql.viewer

The compute portion maps to these granular permissions:

compute.targetHttpsProxies.list
compute.targetSslProxies.list
compute.sslPolicies.get
compute.sslPolicies.list
compute.sslCertificates.list
compute.sslCertificates.get
compute.globalForwardingRules.list
cloudkms.keyRings.list
cloudkms.cryptoKeys.list
storage.buckets.list
storage.buckets.get
cloudsql.instances.list

The integration requests the read-only superset scope https://www.googleapis.com/auth/cloud-platform.read-only, so the service account's granted roles (above) are what actually bound access — not the OAuth scope.

Service Account Setup

  1. Create a service account in the GCP Console (IAM & Admin > Service Accounts)
  2. Grant roles/compute.viewer (plus roles/cloudkms.viewer, roles/cloudsql.viewer, and storage read for the at-rest families you want) on the project
  3. Create and download a JSON key
  4. Paste the key contents into the integration form

Limitations

Current Implementation

  • Discovery is project-scoped (one project per integration)
  • Load balancing: global resources only (Target HTTPS/SSL Proxies, Global Forwarding Rules); regional forwarding rules and regional SSL resources are not yet discovered
  • ✅ Cloud KMS key inventory, Cloud Storage at-rest encryption, and Cloud SQL at-rest encryption are implemented
  • 🚧 Not yet covered: GCP Certificate Manager, Secret Manager, persistent-disk encryption
  • Google-managed certificates show metadata but not PEM content (by design — GCP does not expose private keys or PEM data for managed certs)

API Quotas

  • GCP Compute Engine API quotas apply
  • Default quota: 1,500 requests per 100 seconds
  • Large projects with many proxies may require quota increases