title: Google Cloud Functions with VPC Serverless Connector Egress with Cloud NAT not working
body: <p>This is related to the following questions, which are outdated</p>
  
  <ul>
  <li><a href="https://stackoverflow.com/questions/38811882/possible-to-get-static-ip-address-for-google-cloud-functions">Possible to get static IP address for Google Cloud Functions?</a></li>
  <li><a href="https://stackoverflow.com/questions/51818290/google-cloud-egress-ip-nat-proxy-for-google-cloud-functions">Google Cloud - Egress IP / NAT / Proxy for google cloud functions</a></li>
  </ul>
  
  <p>Currently GCP has VPC Serverless Connector that allows you to route all traffic through a VPC Connector and set up Cloud NAT to get static IP addresses.</p>
  
  <p>I have followed the following guide <a href="https://cloud.google.com/functions/docs/networking/network-settings#associate-static-ip" rel="nofollow noreferrer">https://cloud.google.com/functions/docs/networking/network-settings#associate-static-ip</a> using the region <code>us-east4</code> but external requests from my cloud function always timed out.</p>
  
  <p>I'm not sure this is a bug or I have missed something.</p>
  
  <p>Edit:
  To make sure I have followed everything, I did all the steps using <code>gcloud</code>, command where possible. These commands are copied from the guides from GCP.</p>
  
  <ol>
  <li>Setting project id for future use</li>
  </ol>
  
  <pre class="lang-sh prettyprint-override"><code>PROJECT_ID=my-test-gcf-vpc-nat
  </code></pre>
  
  <ol start="2">
  <li><p>Go to Console and enable billing</p></li>
  <li><p>Set up a VPC and a test VM to test Cloud NAT</p></li>
  </ol>
  
  <pre class="lang-sh prettyprint-override"><code>gcloud services enable compute.googleapis.com \
    --project $PROJECT_ID
  
  gcloud compute networks create custom-network1 \
    --subnet-mode custom \
    --project $PROJECT_ID
  
  gcloud compute networks subnets create subnet-us-east-192 \
    --network custom-network1 \
    --region us-east4 \
    --range 192.168.1.0/24 \
    --project $PROJECT_ID
  
  gcloud compute instances create nat-test-1 \
    --image-family debian-9 \
    --image-project debian-cloud \
    --network custom-network1 \
    --subnet subnet-us-east-192 \
    --zone us-east4-c \
    --no-address \
    --project $PROJECT_ID
  
  gcloud compute firewall-rules create allow-ssh \
    --network custom-network1 \
    --source-ranges 35.235.240.0/20 \
    --allow tcp:22 \
    --project $PROJECT_ID
  </code></pre>
  
  <ol start="4">
  <li><p>Created IAP SSH permissions using Console</p></li>
  <li><p>Test network config, the VM should not have internet access without Cloud NAT</p></li>
  </ol>
  
  <pre class="lang-sh prettyprint-override"><code>gcloud compute ssh nat-test-1 \
    --zone us-east4-c \
    --command "curl -s ifconfig.io" \
    --tunnel-through-iap \
    --project $PROJECT_ID
  </code></pre>
  
  <p>command responded with <code>connection timed out</code></p>
  
  <ol start="6">
  <li>Set up Cloud NAT</li>
  </ol>
  
  <pre class="lang-sh prettyprint-override"><code>gcloud compute routers create nat-router \
    --network custom-network1 \
    --region us-east4 \
    --project $PROJECT_ID
  
  gcloud compute routers nats create nat-config \
    --router-region us-east4 \
    --router nat-router \
    --nat-all-subnet-ip-ranges \
    --auto-allocate-nat-external-ips \
    --project $PROJECT_ID
  </code></pre>
  
  <ol start="7">
  <li>Test network config again, the VM should have internet access with Cloud NAT</li>
  </ol>
  
  <pre class="lang-sh prettyprint-override"><code>gcloud compute ssh nat-test-1 \
    --zone us-east4-c \
    --command "curl -s ifconfig.io" \
    --tunnel-through-iap \
    --project $PROJECT_ID
  </code></pre>
  
  <p>command responded with IP address</p>
  
  <ol start="8">
  <li>Created VPC Access Connector</li>
  </ol>
  
  <pre class="lang-sh prettyprint-override"><code>gcloud services enable vpcaccess.googleapis.com \
    --project $PROJECT_ID
  
  gcloud compute networks vpc-access connectors create custom-network1-us-east4 \
    --network custom-network1 \
    --region us-east4 \
    --range 10.8.0.0/28 \
    --project $PROJECT_ID
  
  gcloud compute networks vpc-access connectors describe custom-network1-us-east4 \
    --region us-east4 \
    --project $PROJECT_ID
  </code></pre>
  
  <ol start="9">
  <li>Added permissions for Google Cloud Functions Service Account</li>
  </ol>
  
  <pre class="lang-sh prettyprint-override"><code>gcloud services enable cloudfunctions.googleapis.com \
    --project $PROJECT_ID
  
  PROJECT_NUMBER=$(gcloud projects describe $PROJECT_ID --format="value(projectNumber)")
  
  gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member=serviceAccount:service-$PROJECT_NUMBER@gcf-admin-robot.iam.gserviceaccount.com \
    --role=roles/viewer
  
  gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member=serviceAccount:service-$PROJECT_NUMBER@gcf-admin-robot.iam.gserviceaccount.com \
    --role=roles/compute.networkUser
  </code></pre>
  
  <ol start="10">
  <li>There are suggestions I should add additional firewall rules and service account permissions</li>
  </ol>
  
  <pre class="lang-sh prettyprint-override"><code># Additional Firewall Rules
  gcloud compute firewall-rules create custom-network1-allow-http \
    --network custom-network1 \
    --source-ranges 0.0.0.0/0 \
    --allow tcp:80 \
    --project $PROJECT_ID
  
  gcloud compute firewall-rules create custom-network1-allow-https \
    --network custom-network1 \
    --source-ranges 0.0.0.0/0 \
    --allow tcp:443 \
    --project $PROJECT_ID
  
  
  # Additional Permission, actually this service account has an Editor role already.
  gcloud projects add-iam-policy-binding $PROJECT_ID \
    --member=serviceAccount:$PROJECT_ID@appspot.gserviceaccount.com \
    --role=roles/compute.networkUser
  </code></pre>
  
  <ol start="11">
  <li>Deployed test Cloud Functions</li>
  </ol>
  
  <p>index.js</p>
  
  <pre class="lang-js prettyprint-override"><code>const publicIp = require('public-ip')
  
  exports.testVPC = async (req, res) =&gt; {
    const v4 = await publicIp.v4()
    const v6 = await publicIp.v6()
    console.log('ip', [v4, v6])
    return res.end(JSON.stringify([v4, v6]))
  }
  exports.testNoVPC = exports.testVPC
  </code></pre>
  
  <pre class="lang-sh prettyprint-override"><code># Cloud Function with VPC Connector
  gcloud functions deploy testVPC \
    --runtime nodejs10 \
    --trigger-http \
    --vpc-connector custom-network1-us-east4 \
    --egress-settings all \
    --region us-east4 \
    --allow-unauthenticated \
    --project $PROJECT_ID
  
  # Cloud Function without VPC Connector
  gcloud functions deploy testNoVPC \
    --runtime nodejs10 \
    --trigger-http \
    --region us-east4 \
    --allow-unauthenticated \
    --project $PROJECT_ID
  </code></pre>
  
  <p>The Cloud Function without VPC Connector responded with IP address
  <a href="https://us-east4-my-test-gcf-vpc-nat.cloudfunctions.net/testNoVPC" rel="nofollow noreferrer">https://us-east4-my-test-gcf-vpc-nat.cloudfunctions.net/testNoVPC</a></p>
  
  <p>The Cloud Function with VPC Connector timed out
  <a href="https://us-east4-my-test-gcf-vpc-nat.cloudfunctions.net/testVPC" rel="nofollow noreferrer">https://us-east4-my-test-gcf-vpc-nat.cloudfunctions.net/testVPC</a></p>