During one of our Google Cloud Platform (GCP) security assessments, we noticed that one of the Predefined IAM Roles had more permissions than before. After a bit, we noticed the GCP IAM Permissions Change Log explained which permissions were added. So, we decided to automatically track those changes, and the results have been enlightening.
The primitive roles in GCP are
owner, and they represent the most coarse way to assign permissions to identities inside GCP. In nearly all use cases, their use immediately violates the principle of least privilege as they include permissions across all GCP services to “read all the things”, “edit all the things”, and “full control”, respectively. If you wanted to grant the ability to view logs in a GCP project, you could assign
viewer and it would work. But, it would grant thousands more permissions than needed to view logs. For example, it would grant read access to GCS buckets, GCR images, and much more. Instead, consider assigning the predefined role named
Predefined roles are another form of built-in IAM Roles that are more granular in nature, and they should be the starting point for access control in most use cases. There are some predefined roles like
roles/browser that don’t seem to change much as their permissions for reading the
project hierarchy are foundational. But what about predefined roles that correspond to a job function like
roles/iam.securityReviewer that touches many services? As it turns, out, these can and do change – sometimes multiple times in a single day.
If you review the GCP IAM Permissions Change Log closely, you can see that changes are posted for a given week. But what happens during the week is actually quite a bit more than that. In order to capture this, we set out to write some simple automation. Like many things, it started with quick shell script in a local repo. A few days later, it captured the first change that wasn’t yet public on the change log, and that’s when we knew this could be useful to run autonomously.
What started as a simple script is now a Github Project leveraging Github Actions to automatically enumerate the currently available primitive and predefined roles and permissions into the repository on a twice-daily basis. If any changes are detected, it tags and creates a date/time named release.
One of the early “catches” was the removal of
container.secrets.list from the
roles/iam.securityReviewer predefined role.
Why is this particular permission removal so interesting? A few reasons:
Being able to
secrets inside all GKE clusters via IAM means that role allows that identity to read all of the Kubernetes Service Account Tokens that are stored as native Kubernetes secrets. In nearly all clusters in practical use, one or more Kubernetes Service Accounts are bound to privileges that can afford the attacker-desired capabilties of cluster-admin. With access to the Bearer token associated with those Kubernetes Service Accounts, the
roles/iam.securityReviewer is actually
cluster-admin inside all GKE clusters in scope. Thankfully, this specific privilege escalation path is no longer possible.
GCP administrators should understand that the primitive and predefined IAM roles in GCP can actually change at any time, and these changes may not appear on the GCP IAM Permissions Change Log right away, if at all. To be notified of each GCP IAM Role and permission change automatically, consider subscribing to the GCP IAM Role Permissions Release Page. The changes may surprise you!