Apr 20, 2022
In previous posts, we’ve discussed the basics of IAM Policies in Google Cloud Platform (GCP) and the risks of lateral movement posed by default service accounts. In this new installment, we’ll discuss one of the tools provided to us by GCP to govern and manage permissions which may be given erroneously by default controls.
As discussed in our Basics post, permissions in GCP are managed in a hierarchical manner. An Organization is the top node of that hierarchy, making policies defined at this level extremely powerful, as they automatically apply to all resources under the Organization. Additionally, the Organization Policy Admin can define policies at the Folder and Project levels – either merging them with the existing policies higher up the hierarchy, or overriding them entirely.
While IAM Policies focus on granting permissions to entities, Organization Policies focus on restricting which configurations can be applied to resources. These restrictions are called Constraints, and at the time of writing, there are 75 of them which you can apply in your policies. These constraints come in two flavors – List and Boolean. You can also add Conditions to apply the Constraint only to certain resources, based on resource tags. Overwhelmed? Keep on reading.
Constraints are created and managed by GCP; you can find the full list of currently supported constraints in the official documentation. Think of these constraints as guardrails preventing your developers and resource admins from making unwanted mistakes, such as making a storage bucket publicly accessible.
I’ve mentioned two flavors of Constraints – List and Boolean. The Boolean Constraints are or aren’t enforced. For example, the sql.restrictPublicIp constraint, when set to True, will prevent new Cloud SQL instances from being configured with a public IP address.
List Constraints can be enforced, or not enforced, based on a list of allowed or denied values which you provide to the organization policy admin. In contrast to the previous example, the compute.vmExternalIpAccess constraint allows you to define which VM instances by name may be configured with an external IP.
Both List and Boolean Constraints may be further scoped down using Conditions. At the moment, the only supported condition type is Resource Tags. Resource Tags are only applicable to the same hierarchy nodes as Organization Policies – i.e. Organization, Folder, and Project – and of course, follow the same inheritance model.
The structure of the condition builder in the GCP Console suggests additional types of conditions are coming, but that is only speculation at this point.
Conditions allow you to create arbitrarily complex rules to decide on which resources the Constraint should be enforced. For example, only resources which have a certain tag, but not another tag, can be enforced.
Let’s look at an example policy constraint:
If we look in the console, the name of the Constraint is “Define allowed external IPs for VM instances” – which is a bit misleading. The description reveals more:
“This list constraint defines the set of Compute Engine VM instances that are allowed to use external IP addresses. All VM instances are allowed to use external IP addresses by default. The allowed/denied list of VM instances must be identified by the VM instance name, in the form: projects/PROJECT_ID/zones/ZONE/instances/INSTANCE”
So this constraint defines which VM instances may be assigned an external IP. By looking at the values, we can see the only two instances which are exempt from this restriction are `sample-VM` and `sample-VM2`.
Additionally, there is the condition expression, which states that the constraint only applies to resources which are tagged with disallow_external_ip : true but are not tagged with allow_external_ip : true
The keen readers among you might have noticed that this isn’t a very effective policy. It is generally considered a better practice to explicitly allow something, such as access to external IP addresses, than explicitly deny it. Moreover, if a project does not have any tags, the constraint won’t apply to it, and the effective policy will fall back to the default behavior of allowing all VM instances to be configured with an external IP.
Instead, a better condition would look like this:
This condition states the Constraint will apply to all resources unless they are explicitly exempt.
Google has recently announced the introduction of Deny Policies. The feature is still very much in beta, so we won’t get too much into it in this post. The general concept, however, is very similar to Organization Policies. Deny Policies provide an additional “guard rail” which can be managed at the Organization, Folder, or Project level. Like traditional IAM Policies, they can be applied to entities in order to prevent them from being granted specific permissions, regardless of any roles they are assigned – in any part of the hierarchy. This will allow you, for example, to grant a user the role of Storage Administrator over an entire Folder, but then deny him that access for specific Projects which reside in that Folder. Stay tuned, as we will be sure to cover this new feature in full once it’s released from beta.
GCP’s Organization Policies give administrators a set of powerful tools to control the potential exposure of resources to unnecessary risks. You might ask yourself, “why are they not all enabled by default, then?”. The answer is a little tricky. Some of the constraints available require you to implement workflows which may not suit your organization’s needs. Others apply to services which you may never use, and others still might outright disable a feature you were actually using.
If you are ready to implement some Organization Policies in your GCP environment – I suggest that you give Org Policies by default a read. The article lists 16 of the most “bang for your buck” policies to help you get started on installing those guardrails. Good luck!