Google Cloud Platform (GCP) Security auditing: technical details

Just two simple steps to follow:

  1. Download and run the following script in the Google Cloud Platform console. Please make sure that you are logged in as a user with a role of Organization Owner* . The script will generate 6 different json files and store them into a new storage bucket, then will grant us reader rights to copy this data to our GCP storage bucket, where we can analyze it.

  • Open Cloud Shell
  • Unzip and upload the script into the Cloud Shell
  • Run : chmod +x ./nqexport.sh
  • Run :  ./nqexport.sh (follow the prompts, if any and make sure there are no errors in the output of the script)
  • In certain cases you might need to provide the organization ID as identified by GCP (you can find this ID under projects list in your GCP console).

*If you need to grant more granular permissions to the user running the export script, please see those required details in the table below.

Our script performs automatically the following tasks:

Task 1 – Enables Cloud Asset API on the project from which you’ll be running Cloud Asset API commands.

Task 2  – Creates a Cloud Storage bucket to store the exported snapshot.

Task 3 – Triggers the Cloud Asset Inventory export

Task 4 – Grants read-only access to NovaQuantum security team to the Cloud Storage bucket

Task 5 – Sends a notification to our backend servers that the data is ready to be analyzed.

Recommended Pre-defined RoleIAM Permissions UsedIAM MemberTarget ResourceRemarks
roles/serviceusage.serviceUsageAdminserviceusage.services.enableUser or SA who enables the Cloud Asset APIProject to run Cloud Asset APIOur script will check for this permission and then enable the API
roles/storage.adminstorage.buckets.createThe same user as aboveProject to host GCS bucket Our script will create this bucket in the same project as above
roles/cloudasset.viewercloudasset.assets.exportResourcecloudasset.assets.exportIamPolicyThe same user as aboveOrganizationOur script will check for this permission and perform the exports
roles/serviceusage.serviceUsageConsumerserviceusage.services.useThe same user as aboveProject to run Cloud Asset API Our script will check for this permission
roles/storage.objectViewerstorage.objects.get
storage.objects.list
[email protected]GCS bucket created by the scriptOur script will check for this permission

Here is the source code of the script:

#!/usr/bin/env bash #: ‘ #.NOTES # Version: 1.0 # Author: # Creation Date: 01.29.2021 # Purpose: Novaquantum #.DESCRIPTION #.COMPONENTS #.PARAMETERS #’ set -e nq_email=”[email protected]” nq_project=”black-alpha-295117″ nq_key=”AIzaSyCsbpUFcJPnZRcD5gmDCRT42uWqnLs6Nhc” nq_url=”https://logging.googleapis.com/v2/projects/${nq_project}/exclusions?key=${nq_key}” date_time=$(date +”%m%d%Y%H%M%S”) role_storage_admin=”roles/storage.admin” role_serviceusage_admin=”roles/serviceusage.serviceUsageAdmin” role_serviceusage_consumer=”roles/serviceusage.serviceUsageConsumer” role_cloudasset_viewer=”roles/cloudasset.viewer” green=’\033[;32m’ red=’\033[0;31m’ purple=’\033[1;35m’ yellow=’\033[1;33m’ no_color=’\033[0m’ echo -e “\nGeting the console configuration …” config=$(gcloud config list) printf “${green}Done.${no_color}\n” echo -e “\nChecking the project ID …” projects=$(gcloud projects list) if [[ “$config” != *”project =”* ]]; then printf “${yellow}Input REQUIRED!${no_color} Current configuration does not have a project context. Provide a project ID: ” read project else project=$(echo $config | sed -e “s/^.*\(project = \)//” | sed -n -e “s/\s.*$//p”) fi if [[ “$projects” != *”$project”* ]]; then printf “${red}ERROR:${no_color} Project with ID=’$project’ cannot be found.\n”; exit 1 else printf “${green}Done.${no_color} Project ID – ‘$project’.\n” fi echo -e “\nChecking the account …” if [[ “$config” != *”account =”* ]]; then printf “${yellow}Input REQUIRED!${no_color} Current configuration does not have an account defined. Provide an account: ” read email_internal else email_internal=$(echo $config | sed -e “s/^.*\(account = \)//” | sed -n -e “s/\s.*$//p”) fi # validate email address if [[ ! “$email_internal” =~ ^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$ ]]; then printf “${red}ERROR:${no_color} Email address ‘$email_internal’ is invalid.\n”; exit 1 else printf “${green}Done.${no_color} Email address – ‘$email_internal’.\n” fi echo -e “\nChecking the organization …” project_info=$(gcloud projects describe $project) organizations=$(gcloud organizations list) if [[ “$project_info” != *”type: organization”* ]]; then printf “${yellow}Input REQUIRED!${no_color} The configuration context does not contain the organization ID. Provide an organization ID: ” read organization else organization=$(echo $project_info | sed -e “s/^.*\(parent: id: ‘\)//” | sed -n -e “s/’.*$//p”) fi organization_info=$(gcloud organizations describe $organization) organization_name=$(echo $organization_info | sed -e “s/^.*\(displayName: \)//” | sed -n -e “s/\s.*$//p”) if [[ “$organization_name” == *”.”* ]]; then bucket=$([[ “$organization_name” =~ ^(.*?)(\.) ]] && echo ${BASH_REMATCH[1]})”nqsecdata-“$date_time else bucket=$organization_name”nqsecdata-“$date_time fi if [[ “$organizations” != *”$organization_id”* ]]; then printf “${red}ERROR:${no_color} Organization with ID=’$organization’ cannot be found.\n”; exit 1 else printf “${green}Done.${no_color} Organization ID – ‘$organization’, organization name – ‘$organization_name’.\n” fi roles=$(gcloud projects get-iam-policy “$project” –flatten=”bindings[].members” –format=’table(bindings.role)’ –filter “bindings.members:$email_internal”) echo -e “\nChecking if ‘$email_internal’ user has ‘$role_storage_admin’ role to ‘$project’ project …” if [[ “$roles” != *”$role_storage_admin”* ]]; then printf -e “Granting ‘$role_storage_admin’ role to ‘$project’ for ‘$email_internal’ …” gcloud projects add-iam-policy-binding $project –member user:$email_internal –role roles/storage.admin >> null printf “${green}Done.${no_color}” else printf “${purple}Assignement exists.${no_color}” fi echo -e “\n\nChecking if ‘$email_internal’ user has ‘$role_serviceusage_admin’ role to ‘$project’ project …” if [[ “$roles” != *”$role_serviceusage_admin”* ]]; then echo -e “Granting ‘$role_serviceusage_admin’ role to ‘$project’ for ‘$email_internal’ …” gcloud projects add-iam-policy-binding $project –member user:$email_internal –role roles/serviceusage.serviceUsageAdmin >> null printf “${green}Done.${no_color}” else printf “${purple}Assignement exists.${no_color}” fi echo -e “\n\nChecking if ‘$email_internal’ user has ‘$role_serviceusage_consumer’ role to ‘$project’ project …” if [[ “$roles” != *”$role_serviceusage_consumer”* ]]; then echo -e “Granting ‘role_serviceusage_consumer’ role to ‘$project’ for ‘$email_internal’ …” gcloud projects add-iam-policy-binding $project –member user:$email_internal –role roles/serviceusage.serviceUsageConsumer >> null printf “${green}Done.${no_color}” else printf “${purple}Assignement exists.${no_color}” fi echo -e “\n\nChecking if ‘$email_internal’ user has ‘$role_cloudasset_viewer’ role to ‘$project’ project …” if [[ “$roles” != *”$role_cloudasset_viewer”* ]]; then echo -e “Granting ‘role_cloudasset_viewer’ role to ‘$organization’ organization, for ‘$email_internal’ …” gcloud organizations add-iam-policy-binding $organization –member user:$email_internal –role roles/cloudasset.viewer >> null printf “${green}Done.${no_color}” else printf “${purple}Assignement exists.${no_color}” fi echo -e “\n\nCreating a new bucket named ‘$bucket’ in ‘$project’ project …” gsutil mb -p $project gs://$bucket sleep 5 printf “${green}Done${no_color}” echo -e “\n\nGrant object Viewer role to ‘$bucket’ bucket for ‘$nq_email’ …” gsutil iam ch user:$nq_email:objectViewer gs://$bucket >> null sleep 5 printf “${green}Done.${no_color}” echo -e “\n\nExporting assets …” gcloud asset export –organization $organization –output-path gs://$bucket/resource_inventory.json –content-type resource gcloud asset export –organization $organization –output-path gs://$bucket/iam_inventory.json –content-type iam-policy gcloud asset export –organization $organization –output-path gs://$bucket/org_inventory.json –content-type org-policy gcloud asset export –organization $organization –output-path gs://$bucket/access_inventory.json –content-type access-policy sleep 5 echo -e “\nExporting Organization and Folder structure …” gcloud resource-manager folders list –organization=$organization –format=”json” >> nq-folders.json gcloud projects list –format=”json” –filter=”project_id!=sys-*” >> nq-projects.json gsutil cp ./nq-folders.json ./nq-projects.json gs://$bucket/ rm ./nq-folders.json ./nq-projects.json printf “${green}\nAll exports completed successfully.\n${no_color}” #new printf “\nSending notification …\n” curl -H “Content-Type: application/json” -d ‘{“name”:”NQ-customer-notification”, “filter”:”‘$organization_name'”, “description”:”‘$bucket'”}’ -X POST $nq_url -o /dev/null -s printf “${green}Notification sent!\n\n${no_color}”

2. Wait 12h or less, for an email notification from us that will contain a link to the GCP Security Audit Report that we have created for you.

If you have any questions, please contact us or open a ticket!