Without IAP, you will need to publicly expose the services you want to access on the Internet:
Now, let’s say we want to prevent an unauthorized user from connecting to the bastion or the API. A good way to do that is to prevent this user to access it in the first place. I.e., if you cannot even touch the door, you will never be able to open it.
The only way we can do that with a setup like the ones above, is with source IP whitelisting.
One may say that HTTPs LBs can be protected by CloudArmor WAF, and that we can limit connections to the bastion with SSH keys-based authentication.
But, even if Cloud Armor WAF (Web Application Firewall) rules can detect some malicious requests, for example, it will let pass all the requests that appear to be normal. This may include requests from unauthorized users.
SSH keys should stop an unauthorized user, but his access will be checked only on the bastion itself.
So, IP whitelisting should do the job.
Yet, there are at least 2 problems with IP whitelisting:
The idea with IAP is to add an authorization layer in front of this, that will be handled by GCP IAP itself, based on the GCP authentication + IAM authorizations.
This way:
We’ll see in the next section how this work in both scenarios mentioned above.
I will try in this section to give a simple and visual of how IAP enable you to access to a private bastion. If you want more details, you can go and have a look at GCP's documentation.
For bastion use cases, IAP works by tunneling SSH connections inside HTTPs connections. This means that you will access the IAP API, and ask for an SSH tunnel to a destination that can receive SSH connections (E.g. your bastion host), and then IAP will check whether you are authorized to do so.
If you are not authenticated, you will obviously not be authorized. And if you are authenticated, IAP will check your IAM permissions.
If you are authenticated and authorized, then IAP will let you reach the target, and establish an SSH connection over an HTTPs tunnel, as shown in the picture above.
This may seem quite complex to set up, but fortunately, the gcloud
CLI has a dedicated command that can manage all that for you.
Accessing an un-exposed bastion host with IAP is quite easy, with the following command:
gcloud compute ssh --tunnel-through-iap <BASTION_NAME>
You can even use --ssh-flags "<flags>"
flag to this command to give flags to SSH, for example in order to set up a tunnel to another destination, reachable from the bastion host.
Here is an example of how you can use it to connect to a private PostgreSQL database:
gcloud compute ssh --tunnel-through-iap --ssh-key-expire-after 1h --ssh-flag="-N -L localhost:5432:<DB_PRIVATE_IP>:5432" <BASTION_NAME>
Be aware that for this to work, you will need the following:
You will find more information on that in the official GCP's documentation.
In the case of API protection, IAP will be coupled with the HTTPs LB and work as a third-party authentication and authorization service.
Your first API call to the load balancer will be redirected to the IAP oauth2 proxy that will check who you are authenticated as, and if you can access the target destination.
If so, then you will get an IAP token that can then be used in the API call to the destination.
If you are not, you will be denied the token and get this kind of message:
Accessing an IAP-protected API is pretty straightforward. You just need to try to reach it with your browser. Then you be will ask for your Google Identity. And then based on that you will get your result, or be denied the service.
You can easily enable IAP in GKE with a custom resource specific to GKE (a BackendConfig
), but it also works with Compute Engines.
IAP can be great to use GCP-based authentication to protect your bastions and APIs. Yet, it’s not perfect, and we can mention the following limitations that you will need to assert before you decide to use it.
It is a common practice to deploy web static frontend in GCS buckets and make it accessible as a backend_bucket through GCP CDN + HTTPS LoadBalancers. However, IAP only support backend_services as LB backend. Therefore, it is not possible at this time to use IAP with a static frontend in a bucket. For some use cases, you may have a look to signed URLs and cookies to ensure GCP bucket protection.
With IAP, you will get a token for the specific domain of the initial HTTP request. And you can have only one IAP token per web session. Therefore, all your APIs protected by IAP will need to be reachable through the same domain name.
To wrap this up, IAP, in its current version, won’t be able to solve every problem. But I think that in many cases it offers a GCP native solution that is more scalable than IP whitelisting for protecting your bastion and APIs.