Sep 7, 2023
Hugo
David
Today, in How to Automate, we will learn how to use Mindflow to automate the process of managing and deleting Google Cloud projects in your organization.
Projects are organizational and administrative units that manage and organize cloud resources and services. They isolate resources by providing logical and physical isolation. Consequently, each project has its resources, ensuring no interference or unauthorized access.
Projects also allow owners to control access to Google resources through IAM policies and fine-grain access control up to the privileges one would have on the set of resources. Each project can be logged and monitored differently, making it easier to track and analyze activities, performances, quotas, and costs associated with the underlying set of resources. Each APIs can be activated per project, and different permissions can be enabled according to the project's needs, reducing the attack surface.
However, without proper monitoring, even when projects' creation is authorized only to admins, projects can multiply and lead to rising overhead, complexity, and security risks. Hence, besides the general organization of the projects (hierarchy, naming conventions, and IAM best practice, for instance), it is recommended that regular reviews and cleanups be performed to decommission projects that are no longer needed.
This can be done through Mindflow, preventing admins from fetching the targeted projects on the Google Cloud console. Automating this process typically divides by more than ten the time needed to perform a process that should be undergone every month.
To do so, we will only have to orchestrate two services: Google Resource Manager and Slack.
Manage and delete Google Cloud projects: the basics
Before getting our hands in the flow building, we must ensure we have the correct permissions. For Google Cloud, we will need either:
https://www.googleapis.com/auth/cloud-platform
https://www.googleapis.com/auth/cloudplatformprojects
Make sure that the Google Resource Manager API is enabled in the Google Cloud console and that the Mindflow client has the mentioned permissions granted in the Domain Wide Delegation page in the admin console. Then, in the Mindflow Vault, update the credentials in the scope you registered.
For Slack, we have to make sure that we have the chat:write
scope granted for our Bot.
We are ready to create the first flow. Proceed and name it as you want!
Manage and delete Google Cloud projects: Listing current projects
We will first configure a scheduler for this flow to be automatically triggered monthly. Do so by clicking the calendar icon on the top left of the canvas. Select "At regular intervals," then "Monthly," and set the day, hour, and minutes you want to trigger the flow. Click "Save." Scheduler is set.
First, we want to set a global variable we need later in the flow. Do so by creating a Transform Data (TD) step named setting variables. Open the configuration panel and click "Add an item." Name this item projects
and leave it empty.
Following this, create a new step and, in the Finder, search for Lists projects that are direct children of the specified folder or organization resource / cloudresourcemanager.projects.list. Open the configuration tab and ensure the credentials are selected in the SETTINGS tab. Inside the INPUT tab, we must populate the parameter "Parent" with organizations/YOUR_ORG_ID. You can find the 12-digit long ID in your project lists on the Google Cloud console. Copy and paste it in the field. You can dry-run the step by clicking the "Play" button at the bottom right of the step to generate logs.
Create a For-each loop that you will name For each project. Open the For-each configuration tab and, in "Source," type "/" to open the Data Picker tool. In the newly opened pop-over, select the Google step and its execution log. In the log, select the object projects
.
Inside For each project
, create a step by searching for Gets IAM policy projects
cloudresourcemanager.projects.getIamPolicy
. We need to retrieve the owner(s) of the project. To do so, we have to retrieve the IAM policy attached to this project to know who the owner is in case we need to ask questions about it. Open the configuration tab, and, under "Resource", type "/" and click For each projects
under FLOW. In the logs, pick the key name
.
Before the step' configuration is done, we need to apply a function to the value we just picked. Click the fx button at the right end of the field. Then, click "Add a function" and search for "Slice" in the Finder. Under "Start," type "9." Leave "End" empty. Now, dry run the step to generate logs.
After this step, create a TD named prepare output. In it, add an item named projects
. We are calling our global variable to write on it at each iteration. Type "/" and fetch the projects
variable. Then, you can add different sets of information, such as projectId
, name
, project Owner, or project creationTime
. Type "/" each time and go inside either the For each project's logs or the cloudresourcemanager.projects.getIamPolicy to pick the keys associated with the values you are looking for. Your message should resemble something like this:
Now, we have to send all the information to Slack on the targeted channel. Do so by opening the Finder and searching for Sends a message to a channel / chat_postMessage. Under "Channel," pick the channel_Id
from which you want to send the message. Under "Text," write the message you want to send, followed by the variable projects you will invoke through the Data Picker. Ensure the right Slack credentials are set, and you are ready!
We also want to notify the team that they can choose to delete one of the projects from Slack. Create another Sends a message to a channel / chat_postMessage. Click the "Advanced" icon at the top right of the pop-over to display all the available parameters. We need "Thread ts" to post a new message in reply to the initial message. You will find the key ts
by opening the Data Picker and looking in the first Slack step logs inside body
. Repeat this process to pick the key channel
to populate the field "Channel."
Under the parameter "Text," write down the following: "If you wish to delete a project, please type '/deleteproject + projectId.'" Once configured, run the flow to check that everything ticks green. The first flow is complete! On to the second flow.
Manage and delete Google Cloud projects: Deleting a project.
Create a new flow and name it as you want. Open it and click the gear icon next to the flow's name. Copy the second webhook URL starting from the bottom. Go to https://api.slack.com/apps/YOUR_WORKSPACE_ID/slash-commands?
and create a new command in the "Request URL" field, paste the webhook URL, and fill the other fields as such. Click "Save" once done. On Slack, query this command to trigger the flow and generate logs.
As the first step, you can create a condition to triage who can trigger this flow if needed. So, create the condition and a branch named yes leading to the action Retrieves the Project identified by the specified project_id / cloudresourcemanager.projects.get
. Fill in the first field with authorized user IDs, select "Contains," and, in the third field, type "/" and find the key user_id
in query
.§
Open the cloudresourcemanager.projects.get
configuration panel, and in "Resource," type "/" and pick the key text
in query
in the Slackbot webhook. Run the step. Create a second step leading to Gets iam policy projects / cloudresourcemanager.projects.getIamPolicy
. We repeat these two steps because we want information displayed in the notification preceding the deletion. Dry-run the second step.
Following this, create a chat_postMessage Slack step. We want to confirm the project's deletion on Slack before proceeding. Populate "Channel," then click "Advanced" and find the field "Blocks." Paste the following JSON:
Once done, create a condition named proceed?
and a branch called yes
, leading to a TD named Prepare impersonation. Run the whole flow from Slack. This will prompt you back. Click "No." Go back to Mindflow and open proceed?
configuration tab. In the first field, open the Data Picker and select the Slack step, then the last execution with "(resume)." Inside, navigate to query/payload/actions/actions[0] and pick style
. Then, select the operator "is equal to" and write "primary" in the third field.
Open the Prepare impersonation TD. Inside, create 5 items that you will name: iat
, sub
, exp
, impersonated_claim_set
, and escape
. Configure them as such:
iat
(issued at): Create a Get time function to generate the current Unix time in seconds.
sub
(the impersonated user): Pick the keymembers[0]
in the second Google step and apply a Slice function starting from "5."
exp
: invoke iat and apply a Sum function where you will add 3600 seconds to the previous value, which is the current Unix time. This will set the lifetime duration of the JSON Web Token that we will generate later.
impersonated_claim_set
: Paste and complete the following JSON:
escape
: callimpersonated_claim_set
and apply an Escape string function configured as such: Escape level * Special chars, Escape quote * Double, JSON Compatible enabled.
You are ready to proceed forward! From there, we will have to create HTTP Requests by hand. Create the first request named Generate impersonated JWT token. Set Method * to POST. In URL * paste https://iamcredentials.googleapis.com/v1/projects/-/serviceAccounts/[YOUR SERVICE ACCOUNT ADDRESS]:signJwt
. Open the Body section and mark it as JSON. Inside write
In the SETTINGS panel, make sure you have selected your JWT credential. Run it once to generate a JWT.
Once done, create another HTTP Request named Generate impersonated access token. Select POST and paste https://oauth2.googleapis.com/token in URL *. In Body as URL-encoded, create grant_type
and paste urn:ietf:params:oauth:grant-type:jwt-bearer
. Below, create assertion
and Pick signedJwt
from the first HTTP Request logs. Run it once to generate logs. At this point, the impersonation process is done. We will now configure steps to find and revert the files' visibility to private
.
Create one last HTTP Request that you will name Mark a project for deletion. Set Method to DELETE
. In the URL, paste https://cloudresourcemanager.googleapis.com/v3/projects/["/" pick projectId
]. In Headers, add an item named Authorization
, type "Bearer," press space, and pick access_token
from Generate impersonated access token's logs.
Finally, we have to create two Slack chat_postMessage steps. One that we will use in the proceed? as the else branch. Create the second branch, click the three dots at the left of the field, and click "use as else." To configure the step, Configure Channel and Thread ts by opening the Data Picker and inspecting the first Slack step logs to pick channel_id
and ts
. As a text, you can write "Task aborted. Project not submitted for deletion."
Repeat the same process by creating a chat_postMessage step after the HTTP Request but, as a text, write "Project submitted for deletion."
Flow complete!