Posted on 2 June 2022.
Having development and production environments in the cloud, IAP always creates the same questions: how can I have access to machines that are not right behind me, without everyone in the world being able to do the same? On AWS, you would use SSM to solve this issue. On GCP there is IAP (Identity Aware Proxy). We will see in the following sections the advantages of IAP in regard to other security mechanisms, along with use cases and their limits.
Non-IAP solutions pain points
Without IAP, you will need to publicly expose the services you want to access on the Internet:
- For a Bastion host, using SSH, you will have to make it accessible on its port 22 (or whatever port your SSH service is listening to), either directly or through a network Load Balancer
- For an HTTP API, you will have to make it accessible on its 80/443 port, once again either directly or through à Load Balancer
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:
- It doesn’t scale well if you do not have a VPN (which can be overkill in some contexts, or too expensive) or access to a shared network (which is less and less the case with the development of remote working). Especially if people work remotely, you will end up whitelisting a lot of IPs, that change frequently.
- You can only give access to everyone or no one on the network, because you will whitelist the public IP used by a user on the network to reach out to the Internet. This means that if you whitelist, for example, the public IP of your company’s Wi-Fi on your GCP dev environment, then anyone in the company will be able to connect to this environment.
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.
- You can ensure that an unauthenticated user cannot have access to even the door of your service
- You can easily manage this access on a per-user basis using GCP IAM policies and roles
We’ll see in the next section how this work in both scenarios mentioned above.
Access a full-private bastion using IAP
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.
How it works
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.
How-to use it
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>
How to set it up
Be aware that for this to work, you will need the following:
- A Firewall rule that authorizes GCP IP addresses used by IAP
- The proper IAM permissions to the user that needs access to the Bastion
You will find more information on that in the official GCP's documentation.
Protect an API deployed in GKE with IAP
How it works
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:
How to use it
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.
How to set it up
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.
- As of today, IAP is only able to establish SSH or RDP connections. So, if you want to connect to a private database, you need to create an SSH tunnel first.
- Since IAP cannot connect you directly to the end service (E.g. a database), this means that it cannot control your access to this service. It will only control your access to the bastion itself
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.
- A client service that needs to interact with an IAP-protected API needs to be compliant with it. This means that for some client services, you may need to have another front door, may be protected by a whitelist for this specific use case. This is often made easier because SaaS services, like GitLab for example, often export their public IPs through their API.
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.