In this post I would like to show you a scenario to use Google Cloud’s API with your Check Point CloudGuard instance to create or delete custom (static) routes.


How does Check Point handle Failover in Google Cloud

During your Check Point CloudGuard HA deployment, you may notice that there are some new routes created in each VPC where the instance is connected to, starting with: x-chkp-<VPC-NAME>-to-member-<a/b>.

Since there is no Layer2 network in cloud environments and the cluster has no VIP (Virtual IP), these routes will make sure that your traffic is always directed to the active member.

These are “high priority” routes according to the CloudGuard deployment documentation.

(sc1.checkpoint.com/documents/)

The integrated HA daemon is monitoring the cluster status of each member and if a failover occurs it will delete or create routes:

    • If member A becomes the active member, it will create high priority routes that will direct all outbound traffic in the internal networks to itself.
      Note: A lower priority number equals a higher priority for the route.
    • If member B becomes the active member, it will remove the high priority routes created by member A. The result is that existing, lower priority routes will be affected and route all outbound traffic in the internal networks to themselves.

The routing changes are done with API calls to the GCP’s API service and the expected failover times are about 40 seconds (depending on the GCP API).


Why static routes?

In some scenarios you may have a VPN to your on-premise network or to a cloud proxy, e.g. Zscaler or Symantec WSS, and the traffic from your backend VPC needs to be routed into the VPN tunnel as shown in figure 1:

google-cloud-network-example
Figure 1: Google Cloud network example

Let’s say you have a route based VPN connection and everything (0.0.0.0/0) is sent into the tunnel in Google Cloud towards your on-premise gateway.

example-route-screenshot-from-google-cloud-march-2021
Figure 2: Example route, screenshot from Google Cloud, march 2021

Let’s also assume that on the peer site you just want to send your backend network 172.17.20.0/24 towards Google Cloud.

In this scenario, once you initiate a connection from your backend VPC into the tunnel, the packet arrives from the remote GW to its destination and the response packet goes all the way back into your frontend VPC. GCP is checking your routing table but cannot find a route for 172.17.20.0/24 pointing to the CloudGuard instances, so the packet will simply hit the 0.0.0.0/0 route towards the VPN. On the peer site, the gateway sees an incoming packet on the VPN interface but from an internal IP. Therefore the gateway will or should simply drop it as a spoofed packet because it is still the response packet.

traffic-flow
Figure 3: Traffic flow

To eliminate this back-and-forth routing, you need to create a static route in your frontend VPC for your backend network pointing to your CloudGuard instance.

You should implement the static routes exactly the same as the x-chkp routes with priority 1 pointing to member A and priority 2 to member B in your frontend VPC subnetwork:

– network 172.17.20.0/24 pointing to member A with priority 1

– network 172.17.20.0/24 pointing to member B with priority 2

static-routes-to-check-point-cluster-screenshot-from-google-cloud-march-2021
Figure 4: Static routes to Check Point cluster, screenshot from Google Cloud, march 2021

Make sure that you name the routes with either “-a” or “-b” at the end to identify them quickly.


How to automate

The only thing we need to do now is to automatically check the cluster status and call the API to either delete or create priority 1 route to member A.

For this we are using two simple bash scripts running as a cronjob on the members.

You can use the following script for member „a“ and place it in the /bin folder or wherever you prefer.

This script checks if the status of member A is active or not. If the status is active, you need to check if there is a route pointing to this member for the backend network. If there is no route found, a new one is created.

Please make sure you replace the values marked with <> with your GCP values.

#!/bin/bash -f
source /opt/CPshrd-<VERSION>/tmp/.CPprofile.sh

#gets the hostname
hostname=$(hostname)
#gets the Member status
status=$(cphaprob stat | grep local | awk '{print $5}' | cut -c 1-6)
#gets the token bearer
token=$(curl_cli -s http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token -H "Metadata-Flavor: Google" | jq '."access_token"')
#gets the next hop instance from the route
instance=$(curl_cli -s -H "Authorization: Bearer "$token https://www.googleapis.com/compute/v1/projects/<YOUR PROJECT NAME>/global/routes/<ROUTE NAME> --insecure | jq '."nextHopInstance"' | awk -F / '{print $NF}' | cut -d '"' -f 1)
#gets the destination of the desired route
destination=$(curl_cli -s -H "Authorization: Bearer "$token https://www.googleapis.com/compute/v1/projects/<YOUR PROJECT NAME>/global/routes/<ROUTE NAME> --insecure | jq -r '."destRange"')
#defines the network range from your backend VPC
network="172.17.20.0/24"
#getting the zone the vm is running in
zone=$(curl_cli -s http://metadata.google.internal/computeMetadata/v1/instance/zone -H "Metadata-Flavor: Google" |awk -F"/" '{print $4}')
#log file
log=/var/log/gcp_logs/log_$(date +"%Y_%m_%d").txt
#old logs to remove (older than 3 days)
old_log=$(find /var/log/gcp_logs -maxdepth 1 -type f -mtime +3 -name log_*.txt' -execdir rm  -- '{}' \;)

#if status is Active
if [ $status == ACTIVE ]
then
        #check if the route for the backend network already exists and pointing to this member
        if [ $instance == $hostname ] && [ $destination == $network ]
        then
                #if true, write into Log file
                echo "$(date +"%Y_%m_%d %H:%M") : route $network to $instance in $zone exists for <VPC NAME>" >> $log
                #remove old log files
                $old_log
        else
                #if false, create the route
                echo "$(date +"%Y_%m_%d %H:%M") : creating route for network $network to $hostname in $zone for <VPC NAME>" >> $log
				curl_cli -s -H "Authorization: Bearer "$token -X POST -d '{"destRange":"'$network'","name":"<ROUTE_NAME>","network":"global/networks/<VPC_NAME>","priority":"1","nextHopInstance":"https://www.googleapis.com/compute/v1/projects/<YOUR PROJECT NAME>/zones/'$zone'/instances/'$hostname'"}' https://www.googleapis.com/compute/v1/projects/<YOUR_PROJECT_NAME>/global/routes --insecure --header "Content-Type: application/json" >> $log
    fi
fi
exit

For the status of member B, the script below can be used. If member B is active, it will simply just delete the route to member A and the traffic will hit the priority 2 route. No following actions are required for the priority 2 route, as this will always remain and has no impact to the traffic at all if member B is not active.

Please make sure you replace the values marked with <>.

#!/bin/bash -f
source /opt/CPshrd-<VERSION>/tmp/.CPprofile.sh

hostname="<HOSTNAME_OF_MEMBER_A>"
node=$(cphaprob stat | grep local | awk '{print $6}')
status=$(cphaprob stat | grep local | awk '{print $5}' | cut -c 1-6)
token=$(curl_cli -s http://169.254.169.254/computeMetadata/v1/instance/service-accounts/default/token -H "Metadata-Flavor: Google" | jq '."access_token"')
instance=$(curl_cli -s -H "Authorization: Bearer "$get_token https://www.googleapis.com/compute/v1/projects/<PROJECT_NAME>/global/routes/<ROUTE_NAME_MEMBER_A> --insecure | jq '."nextHopInstance"' | awk -F / '{print $NF}' | cut -d '"' -f 1)
destination=$(curl_cli -s -H "Authorization: Bearer "$get_token https://www.googleapis.com/compute/v1/projects/<PROJECT_NAME>/global/routes/<ROUTE_NAME_MEMBER_A> --insecure | jq -r '."destRange"')
network="172.17.20.0/24"
past=$(date +"%Y_%m_%d" --date="-3 days")
zone="<ZONE_OF_MEMBER_A>"
#log file
log=/var/log/gcp_logs/log_$(date +"%Y_%m_%d").txt
#old logs to remove (older than 3 days)
old_log=$(find /var/log/gcp_logs -maxdepth 1 -type f -mtime +3 -name log_*.txt' -execdir rm  -- '{}' \;)


if [ $status == ACTIVE ] 
then
	if [ $instance == $hostname ] && [ $destination == $network ] 
	then
		echo "$(date +"%Y_%m_%d %H:%M") : deleting existing route $network to inactive member" >> $log
		curl_cli -s -H "Authorization: Bearer "$get_token -X DELETE https://www.googleapis.com/compute/v1/projects/<PROJECT_NAME>/global/routes/<ROUTE_NAME_MEMBER_A> --insecure >> $log
      $old_log
	fi
fi
exit

After you have placed the script for both members you can add it to the crontab and run it for example every 30sec.

This is just an example to automate this specific scenario. Of course there are some other scenarios where you could use the API to automate your processes.