Google Cloud Platform (GCP) Security auditing: technical details
Just two simple steps to follow:
- 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 Role | IAM Permissions Used | IAM Member | Target Resource | Remarks |
---|
roles/serviceusage.serviceUsageAdmin | serviceusage.services.enable | User or SA who enables the Cloud Asset API | Project to run Cloud Asset API | Our script will check for this permission and then enable the API |
roles/storage.admin | storage.buckets.create | The same user as above | Project to host GCS bucket | Our script will create this bucket in the same project as above |
roles/cloudasset.viewer | cloudasset.assets.exportResourcecloudasset.assets.exportIamPolicy | The same user as above | Organization | Our script will check for this permission and perform the exports |
roles/serviceusage.serviceUsageConsumer | serviceusage.services.use | The same user as above | Project to run Cloud Asset API | Our script will check for this permission |
roles/storage.objectViewer | storage.objects.get storage.objects.list | [email protected] | GCS bucket created by the script | Our 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!