Restricting Write Permissions on Folders in Google Cloud Storage with IAM Conditions
No matter what kind of project you’re working on in GCP, chances are you’ve probably dealt with more than a couple of core technologies along the way. You’re probably no stranger to Cloud IAM and if you’re storing any data you’ve probably got several Cloud Storage buckets.
One of the cool things about Cloud Storage is the ability to use the logical concept of “folders” for your objects. Where this falls down though is the fact that Cloud Storage is an object store and not a file system, meaning it won’t behave like a file system. That means you can’t restrict write permissions at the “folder level” because the “folder” does not really exist. Using uniform permissions, assigning the role of Storage Object Creator gives the account write access to the whole bucket, which might not be ideal if you are trying to adhere to the principle of least privilege.
Fine-grained permissions allow you to use Access Control Lists (ACLs) but you can only assign these at an object level and ACLs aren’t really helpful here as the object needs to exist before you can add an ACL to it. Sure, you can create the ACL when writing the object but that would require your account to have write access to the whole bucket in order to create it, thus defeating the object of the ACL in restricting write access!
So that’s it then, there’s no way to restrict write access to a folder in a Cloud Storage bucket.
Or is there?
This is where IAM Conditions can really help you out. IAM Conditions allow you to define the specific circumstances in which to apply an IAM role to an account. If you haven’t seen where this is going yet; this means you can set the Storage Object Creator role (write access) on an account only when it is writing an object to a specific folder.
Sort of.
Remember, a “folder” in a Cloud Storage bucket is essentially an object, it is merely a “folder” in conceptual terms. As mentioned before, Cloud Storage is an object store, not a file system. In actuality, it is the name of an object within a Cloud Storage bucket, objects “within the folder” are simply objects whose names are prefixed with the folder name… If that sounds confusing here’s a diagram to hopefully explain it.
On the left of this diagram is a traditional File System. It works in a hierarchical manner and allows permissions to be set at an individual folder level to propagate down to the files below.
On the right is an Object Store where everything is on one flat hierarchy and each object has a unique identifier. This unique identifier can be given the logical concept of a “folder” by adding a “/” to the object name. You can see in the diagram several objects which are named things like “folder-a/file-e”. Therefore, in an Object Store, a “folder” is simply a logical concept and not a hierarchical structure for file storage. The folder does not really exist.
This allows us to take advantage of object naming conventions and define an IAM Condition based on a common expression. For example:
I have a Cloud Storage bucket called “gs://my-test-project-bucket-001”. Under that bucket, I have several folders containing various objects. I want to ensure that a particular service account can only write to a specific folder in that bucket called “folder-a”.
In this example, an object called “test.txt” being written to this folder would have an object name of “folder-a/test.txt”. Cloud Storage is clever enough to know that the “/” in the object name denotes the logical concept of a folder; so if my account has write access to the whole bucket and a folder called “folder-a” does not exist, the Cloud Storage API will create it for me and place the file called “test.txt” under it. In reality, what is actually happening is an object is created in the bucket called “folder-a/test.txt”. Since there is no hierarchical structure to an object store, this object will be at the same level as all other objects in the bucket.
If I want to restrict an account’s write access to only “folder-a” I can define an IAM Condition that uses “folder-a” as a prefix. As long as the folder already exists, IE it was created before the account attempts to write anything to it, this will work. When attempting to write an object to “folder-a” it will be successful but if it attempts to write to any other folder in the bucket including the root of the bucket it will receive a 403 Access Denied Exception.
What this means in object storage terms is that the account is only allowed to write objects to the bucket whose names begin with “folder-a/”.
Here’s how it’s done.
- In Cloud Storage go to the bucket you want to restrict access on. Ensure the folder you want to set write access on exists.
2. Go to the Permissions tab. You need to ensure the bucket is set to Uniform Permissions for this to work. Click “+ADD”.
3. Enter the full email address of the account you want to set access for. Then add the Storage Object Viewer role. This allows the account to list objects but not write.
4. Now click “+ADD ANOTHER ROLE” and select Storage Object Creator from the dropdown menu then click “Add Condition”.
5. You can use the Condition Builder but I found it easier to use the Condition Editor which allows you to type out the condition using Common Expression Language (CEL).
To set a condition where the Storage Object Creator role is only granted on “folder-a” enter the following:
resource.name.startsWith(“projects/_/buckets/my-test-project-bucket-001/objects/folder-a”)
Let’s break down what this means.
resource.name.startsWith
This is pretty self-explanatory. In this instance, the “resource” is the target object in the bucket. The “name.startsWith” tells the API we are targeting a prefix on the object name.
projects/_/buckets/my-test-project-bucket-001/
This is the attribute reference for the Google Storage API for the bucket named “my-test-project-bucket-001”.
/objects/folder-a
This part of the attribute reference tells the API that we are targeting any objects whose names are prefixed with the value “folder-a”.
6. Click Save to create the condition and then click Save again to set the IAM policy on the bucket.
Et Voila! You have now restricted your account to only have Storage Object Creator permissions on the folder called “folder-a”.
Remember
CLOUD STORAGE IS NOT A FILE SYSTEM. This means you MUST use absolute paths when writing objects. If you happen to have several layers of subfolders like “folder-a/subfolder-1/another-folder/”, do not expect Cloud Storage to suddenly start allowing you to write files to subfolders like this:
gsutil cp test.txt gs://my-test-project-bucket-001/folder-a/../another-folder/test.txt
This command will not go down several sublevels of folders to write the file. Instead, it will create a subfolder under “folder-a” called “..” which is probably not what you wanted it to do. What you need to do instead is this:
gsutil cp test.txt gs://my-test-project-bucket-001/folder-a/subfolder-1/another-folder/test.txt
IAM Conditions are an incredibly powerful and useful tool in GCP. There are a lot more things you can do with them involving all kinds of other use cases, not just limited to object permissions in Cloud Storage.
Stay tuned for more articles about IAM Conditions and other tips and tricks on GCP.