GCP: Self-serve timed access to GCP resources using Cloud Identity and Slack (Part 1)
Introduction
To contextualize the close relationship between Identity and Access Management (IAM) and cloud infrastructures, one must (naturally) look toward the Marvel universe: if Marvel’s realm of Asgard is a cloud infrastructure, then Heimdall — the all-seeing gatekeeper of Asgard who protects the realm from unauthorized access — is IAM.
Because Identity and Access Management (IAM)is the key to access cloud resources, granting access to users only when required — and not by default — is key. But often times, because access is granted manually, users maintain access to cloud resources beyond the necessary.
In this two-part series, we unpack how to grant and automate the timed access to the GCP resources so that users can have access on-demand vs. by default.
IAM in GCP
To start, here’s a quick introduction into IAM in GCP:
- Principal : A principal can be a Google Account (for end users), a service account (for applications and compute workloads), a Google group, or a Google Workspace account or Cloud Identity domain that can access a resource. The identity of a principal is an email address associated with a user, service account, or Google group.
- Role: A role is a collection of permissions. Permissions determine what operations are allowed on a resource. When you grant a role to a principal, you grant all of the permissions that the role contains.
- Resources: Everything that is being used on Google Cloud Platform is said to be resources in the context of IAM. From the organization to folders, projects, buckets, instances, etc, all resources are organized hierarchically.
IAM Policy
The IAM policy is a collection of role bindings that bind one or more principals to individual roles. When you want to define who (principal) has what type of access (role) on which resource, you create a policy and attach it to the resource.
In GCP, access is managed through IAM policies. Every time we create, update, or remove access in the console, GCP modifies the bindings in the policy accordingly behind the scenes.
We can’t access this IAM policy in console. Instead, we can fetch it through gcloud command using getIamPolicy() and apply it using setIamPolicy()
# Example policy yaml - 1 {
"version": 1,
"etag": "Xxxxxxxxx=",
"bindings": [
{
"role": "roles/editor",
"members": [
"user:project-editor@example.com"
]
},
{
"role": "roles/iam.securityReviewer",
"members": [
"user:sundar.pichai@example.com"
]
}
]
}
GCP IAM supports conditional role bindings in IAM policies which allow us to grant temporary access to GCP resources. By using the date/time attributes, we can enforce time-based controls when accessing a given resource.
# Example policy yaml - 2{
"version": 1,
"etag": "Xxxxxxxx=",
"bindings": [
{
"role": "roles/editor",
"members": [
"user:project-editor@example.com"
]
},
{
"role": "roles/iam.securityReviewer",
"members": [
"user:sundar.pichai@example.com"
]
"condition": {
"title": "Expires_Mar_22_2022",
"description": "Expires on Mar 22, 2022",
"expression":
"request.time < timestamp('2022-22-03T00:00:00.000Z')"
}
}
]
}
Conditional IAM policies can be applied at any resource levels — organization, projects, buckets, etc. — and as long as the condition satisfies the user/identity can access the resources.
Although this looks like a straightforward approach, there are many challenges in adopting this in a production environment.
Challenges with IAM conditional role bindings
1. Cleaning up expired roles in the policy bindings
Even though access to the principals/users expire after the specified date/time, the binding will continue to remain in the policy unless we remove it.
So, every time we add a time based conditional role, we have to keep a track of it and remove it from the policy once it expires — which is a lot of management overhead.
2. Limitations on the policies role bindings
Every time we grant/modify access, the IAM policy is updated. There are certain limitations on this which will affect us at a later stage.
As highlighted in point number #1, we can’t add more than 20 different condition expressions to the same user and the role, unless we clean up the older bindings.
3. Playing with policy (or fire)
When we make changes directly to the policy, GCP will overwrite the existing policy and apply the newer policy.
This poses a huge risk of wiping out all of the existing role bindings (i.e delete all access granted at the IAM) if we inadvertently pass an empty or a new binding. So whenever we grant access, we have to create a copy of the existing policy and make changes to it, which requires careful tracking and handling of it.
Also, the higher the level of resource that is changed in the policy (base resource -> project -> folder -> organization), the higher the risk. There are cases where engineers locked themselves out of the project by accidentally deleting the IAM policy.
When we faced the same challenges at Zeotap, we decided not to explore this route, instead going with an out-of-the-box (or out of the IAM) solution.
Google Cloud Identity
Cloud Identity is an Identity as a Service (IDaaS) solution that helps centrally manage the users, groups, apps, and devices. Using Cloud Identity, we can centrally manage access to Gmail, Google Drive, Google Cloud Platform and all other google services with a SSO.
A Cloud Identity or Google Workspace account (formerly G Suite) is created when a company signs up for Cloud Identity or Google Workspace. By default, the account name in Cloud Identity will be our organization name in Google Cloud Platform.
When we create users or groups in cloud identity, the same can be used in Google Cloud Platform as principals to grant access to any resources. So instead of adding users to IAM, we can add/remove users to groups in our Google workspace and map the groups in IAM.
This way we won’t be interacting with the IAM policy in Google Cloud Projects and the role bindings will continue to remain the same.
Membership expiration
Last year, Google Workspace introduced the Google memberships expiration feature. It enables the following:
The Cloud Identity Groups API feature that enables you to set expirations for group memberships is now generally available.
This enables admins to set an amount of time that users and service accounts are members of a group. Once the specified time has passed, users will be removed from the group automatically.
With the membership expiration feature, there is no operation overhead of maintaining the status and removing users from the group. Google Workspace takes care of it and the users won’t be able to access the GCP resources once the time duration expires.
We can manage this groups membership using Groups API provided by Cloud Identity. (Ref: https://cloud.google.com/identity/docs/how-to/memberships-google-groups#rest)
# Sample Code to add a member with expiration policyfrom googleapiclient.discovery import buildservice = build('cloudidentity', 'v1')body = {
"roles": [
{
"name": "MEMBER",
"expiryDetail": {
"expireTime": "2022-03-22T00:00:00Z"
}
}
],
"preferredMemberKey": {
"id": "sundar.pichai@example.com"
}
}results = service.groups().memberships().create(parent=bucket-viewers@example.com', body=body).execute()
Note: This feature is only available to Google Workspace Enterprise Standard, Enterprise Plus, and Enterprise for Education, and Cloud Identity Premium accounts.
Summary
As we have seen, GCP’s IAM expiry option comes with a lot of operational overhead, limits, and risks. Google Cloud Identity provides a seamless way to handle the timed access to our production resources.
In Part 2 of this series, I will demonstrate how to implement this as an application and trigger it using Slack commands to make it a completely automated self-serve model.