gcloud-nat-private-subnet-disabled: Cloud NAT Not Enabled for Private Subnets

日期: 2025-08-01 | 影响软件: gcloud nat private subnet disabled | POC: 已公开

漏洞描述

Ensure that Cloud NAT is enabled for all private VPC subnets that require outbound access. Cloud NAT enables your VMs and container pods to establish outbound connections to the Internet or other Virtual Private Cloud (VPC) networks. It utilizes a Cloud NAT gateway to manage these connections efficiently.

PoC代码[已公开]

id: gcloud-nat-private-subnet-disabled

info:
  name: Cloud NAT Not Enabled for Private Subnets
  author: princechaddha
  severity: medium
  description: |
    Ensure that Cloud NAT is enabled for all private VPC subnets that require outbound access. Cloud NAT enables your VMs and container pods to establish outbound connections to the Internet or other Virtual Private Cloud (VPC) networks. It utilizes a Cloud NAT gateway to manage these connections efficiently.
  impact: |
    If Cloud NAT is not enabled, private subnets may not have outbound access, leading to connectivity issues and potential misconfigurations for workloads requiring internet or inter-network communication.
  remediation: |
    Configure Cloud NAT for all private subnets that require outbound access. Use Compute Engine routers to define NAT configuration and associate them with your VPC subnets.
  reference:
    - https://cloud.google.com/nat/docs/overview
  tags: cloud,devops,gcp,gcloud,google-cloud-nat,gcp-cloud-config

flow: |
  code(1)
  for(let projectId of iterate(template.projectIds)){
    set("projectId", projectId)
    code(2)
    for(let networkName of iterate(template.networks)){
      set("networkName", networkName)
      code(3)
      for(let subnetDetail of iterate(template.subnets)){
        set("subnetDetail", subnetDetail)
        code(4)
      }
      code(5)
      for(let natGateway of iterate(template.natGateways)){
        set("natGateway", natGateway)
        javascript(1)
      }
    }
  }

self-contained: true

code:
  - engine:
      - sh
      - bash
    source: |
      gcloud projects list --format="json(projectId)"

    extractors:
      - type: json
        name: projectIds
        internal: true
        json:
          - '.[].projectId'

  - engine:
      - sh
      - bash
    source: |
      gcloud compute networks list --project $projectId --format="json(name)"

    extractors:
      - type: json
        name: networks
        internal: true
        json:
          - '.[].name'

  - engine:
      - sh
      - bash
    source: |
      gcloud compute networks subnets list --network=$networkName --project=$projectId --format="json(selfLink,privateIpGoogleAccess)"

    extractors:
      - type: json
        name: subnets
        internal: true
        json:
          - '.[] | {selfLink, privateIpGoogleAccess}'

  - engine:
      - sh
      - bash
    source: |
      gcloud compute routers list --project=$projectId --filter="network:($networkName)" --format="json(name,region)"

    extractors:
      - type: json
        name: routers
        internal: true
        json:
          - '.[] | {name, region}'

  - engine:
      - sh
      - bash
    source: |
      gcloud compute routers nats list --router=$router.name --region=$router.region --format="json(name,subnetworks)"

    extractors:
      - type: json
        name: natGateways
        internal: true
        json:
          - '.[] | {name, subnetworks}'

javascript:
  - code: |
        let subnet = template.subnetDetail;
        let natGateways = template.natGateways;
        let privateIpGoogleAccess = subnet.privateIpGoogleAccess;

        if (privateIpGoogleAccess === "true") {
          let natEnabled = natGateways.some(gw => gw.subnetworks.includes(subnet.selfLink));
          if (!natEnabled) {
            Export(`Cloud NAT is not enabled for private subnet: ${subnet.selfLink} in project: ${template.projectId}`);
          }
        }

    extractors:
      - type: dsl
        dsl:
          - response
# digest: 490a00463044022010d2a3557469225826eba4a0c8fba27724c5a25126213da6293371db9dd971e90220316e982fbec97caa7003b86431b4cd4226fe0c54be0893ff5fd2dd06cf541b4b:922c64590222798bb761d5b6d8e72950