Note: This article was originally published in 2016. Some steps, commands, or software versions may have changed. Check the current Google Cloud documentation for the latest information.

Google IP address ranges

Recently I decided to try the Google Compute Engine Cloud, and one of the things I liked right from the beginning was the ability to connect via SSH to your Ubuntu box. I am going to have to read a bit more about it but basically it seems like it generates a keypair, sets it up on your server and then opens a terminal connection via ssh on your web browser… how cool is that?! In my case I wanted to increase the security by limiting the IP addresses that can access the SSH port. Here is where this post comes along. If you look at the documentation basically it says you need to allow all Google IP addresses because the web client may connect from any Google IP… I know, a lot of IPs to authorize but I guess it is better than opening the port to all IP addresses in the world. I am probably going to enable and disable the rule manually but open it to all Google IP addresses for convenience of using the web client to initiate an ssh connection.


The ranges

Well, the IP ranges that Google owns/manages vary throughout time. Fortunately, there are ways to obtain the lates versions at any given point. Unfortunately, I am not sure how can you dynamically update them in the Google Cloud Engine’s firewall rules so I am manually adding them. In order to identify them I am relying on the spf record google offers: _spf.google.com

Here is the information I’ve found at the time of writting:

v=spf1 include:_netblocks.google.com include:_netblocks2.google.com include:_netblocks3.google.com ~all
PrefixTypeValuePrefixDescDescription
vversionspf1The SPF record version
  • | include | _netblocks.google.com | Pass | The specified domain is searched for an ‘allow’.

  • | include | _netblocks2.google.com | Pass | The specified domain is searched for an ‘allow’.

  • | include | _netblocks3.google.com | Pass | The specified domain is searched for an ‘allow’.
    ~ | all | | SoftFail | Always matches. It goes at the end of your record.

    v=spf1 ip4:64.18.0.0/20 ip4:64.233.160.0/19 ip4:66.102.0.0/20 ip4:66.249.80.0/20 ip4:72.14.192.0/18 ip4:74.125.0.0/16 ip4:108.177.8.0/21 ip4:173.194.0.0/16 ip4:207.126.144.0/20 ip4:209.85.128.0/17 ip4:216.58.192.0/19 ip4:216.239.32.0/19 ~all

PrefixTypeValuePrefixDescDescription
vversionspf1The SPF record version
  • | ip4 | 64.18.0.0/20 | Pass | Match if IP is in the given range

  • | ip4 | 64.233.160.0/19 | Pass | Match if IP is in the given range

  • | ip4 | 66.102.0.0/20 | Pass | Match if IP is in the given range

  • | ip4 | 66.249.80.0/20 | Pass | Match if IP is in the given range

  • | ip4 | 72.14.192.0/18 | Pass | Match if IP is in the given range

  • | ip4 | 74.125.0.0/16 | Pass | Match if IP is in the given range

  • | ip4 | 108.177.8.0/21 | Pass | Match if IP is in the given range

  • | ip4 | 173.194.0.0/16 | Pass | Match if IP is in the given range

  • | ip4 | 207.126.144.0/20 | Pass | Match if IP is in the given range

  • | ip4 | 209.85.128.0/17 | Pass | Match if IP is in the given range

  • | ip4 | 216.58.192.0/19 | Pass | Match if IP is in the given range

  • | ip4 | 216.239.32.0/19 | Pass | Match if IP is in the given range
    ~ | all | | SoftFail | Always matches. It goes at the end of your record.

    v=spf1 ip6:2001:4860:4000::/36 ip6:2404:6800:4000::/36 ip6:2607:f8b0:4000::/36 ip6:2800:3f0:4000::/36 ip6:2a00:1450:4000::/36 ip6:2c0f:fb50:4000::/36 ~all

PrefixTypeValuePrefixDescDescription
vversionspf1The SPF record version
  • | ip6 | 2001:4860:4000::/36 | Pass | Match if IP is in the given range

  • | ip6 | 2404:6800:4000::/36 | Pass | Match if IP is in the given range

  • | ip6 | 2607:f8b0:4000::/36 | Pass | Match if IP is in the given range

  • | ip6 | 2800:3f0:4000::/36 | Pass | Match if IP is in the given range

  • | ip6 | 2a00:1450:4000::/36 | Pass | Match if IP is in the given range

  • | ip6 | 2c0f:fb50:4000::/36 | Pass | Match if IP is in the given range
    ~ | all | | SoftFail | Always matches. It goes at the end of your record.

    v=spf1 ip4:172.217.0.0/19 ~all

PrefixTypeValuePrefixDescDescription
vversionspf1The SPF record version
  • | ip4 | 172.217.0.0/19 | Pass | Match if IP is in the given range
    ~ | all | | SoftFail | Always matches. It goes at the end of your record.

So there you have it. The first block is called netblocks which contains all the blocks in the IPv4 space, then you have netblocks2 which contains all the blocks in the IPv6 space… which leaves netblocks3 which contains an IPv4 address range but I am not sure why not simply include it in netblocks. If anyone knows the reason or has a good guess please share!

If you wish to query this information anytime yourself, you can do it querying the Google DNS servers like so:

  nslookup -q=TXT _spf.google.com 8.8.8.8 nslookup -q=TXT _netblocks.google.com 8.8.8.8 nslookup -q=TXT _netblocks2.google.com 8.8.8.8 nslookup -q=TXT _netblocks3.google.com 8.8.8.8  

So it is possible to automate the update of the ranges via a shell script for example… or an API call… but for me I think it is not necessary seeing updates shouldn’t happen too often and if there is an issue I can always update as required.