#!/usr/bin/env bash

# vamu-gcp-org-key-setup-script.sh takes a user-specified GCP organization name and
# provisions the necessary permissions for to Vamu to scan all projects under the organization.
#
# This script will:
# 1. Create a vamu-scanner project under your organization.
# 2. Enable the required APIs on the created vamu-scanner project.
# 3. Create a custom role, VamuOrganizationScanner, for listing IAM policies inherited by GCP projects
#    and for listing resources in GCP projects under this organization.
# 4. Create a new service account, vamu-scanner-service-account, in the created vamu-scanner project
# 5. Download a key for vamu-scanner-service-account as vamu-scanner-key.json.
# 6. Grant vamu-scanner-service-account the VamuOrganizationScanner role in the organization
#    enclosing the vamu-scanner project.
# 7. Grant vamu-scanner-service-account the roles/iam.securityReviewer standard role for the organization.
#
# NOTE: This script is idempotent so you may rerun this script to get the same desired permissions.
#
# USAGE:
#   bash vamu-gcp-org-key-setup-script.sh "specified organization name"
#
# OUTPUT: vamu-scanner-key.json.

# Service account and role identifiers
projectName=vamu-scanner
orgRoleID="VamuOrganizationScanner"
serviceAccountID="vamu-scanner-service-account"

set -e

# Logging utilities
purple='\033[0;35m'
nc='\033[0m'
prefix="${purple}[ Vamu ]${nc}"

# Check for gcloud.
if ! command -v gcloud &>/dev/null; then
  printf "${prefix} [ERROR] gcloud CLI unavailable.\nSee https://cloud.google.com/sdk/docs/quickstart for installation instructions.\n"
  exit
fi

arguments=("$@")

# Parse GCP organization id from arguments.
orgName="${arguments[0]}"
if [ -z "$orgName" ]; then
  printf "${prefix} [ERROR] no GCP organization name specified.\n"
  exit
fi

orgID=$(
  gcloud organizations describe "$orgName" --format=json | jq -r .name | sed -e "s/organizations\///"
)

if [ -z orgID ]; then
  printf "${prefix} [ERROR] organization (${orgName}) not found or missing required permissions.\n"
  exit
fi

findProjectJson=$(
  gcloud projects list --filter="name=${projectName} AND parent.id=${orgID} AND parent.type=organization" --format=json
)

secondProjectWithSameProjectName=$(
  echo "$findProjectJson" | jq -r '.[1] // empty'
)
if [ -n "$secondProjectWithSameProjectName" ]; then
  printf "${prefix} [ERROR] Multiple projects named ${projectName} exist in organization ${orgName}.\n"
  exit
fi

projectID=$(
  echo "$findProjectJson" | jq -r '.[0] | .projectId // empty'
)

if [ -z "$projectID" ]; then
  # Create vamu-scanner project under the specified organization if no existing project found
  printf "${prefix} Creating project ${projectName} under organization ${orgName}.\n"
  timestamp=$(perl -MTime::HiRes -e 'printf("%.0f\n", Time::HiRes::time() * 1000)')
  gcloud projects create ${projectName}-"${timestamp}" --name="${projectName}" --organization="${orgID}" --quiet
  projectID=$(
    gcloud projects list --filter="name=${projectName} AND parent.id=${orgID} AND parent.type=organization" --format=json | jq -r '.[0] | .projectId'
  )
else
  printf "${prefix} Project ${projectName} (${projectID}) already exists under organization ${orgName}, no need to create, continuing.\n"
fi

gcloud services enable --project="${projectID}" --quiet --no-user-output-enabled \
  cloudresourcemanager.googleapis.com \
  cloudkms.googleapis.com \
  iam.googleapis.com \
  serviceusage.googleapis.com \
  monitoring.googleapis.com \
  logging.googleapis.com \
  bigquery.googleapis.com \
  pubsub.googleapis.com \
  storage-api.googleapis.com \
  securitycentermanagement.googleapis.com \
  sqladmin.googleapis.com \
  containeranalysis.googleapis.com \
  firestore.googleapis.com \
  cloudasset.googleapis.com &&
  printf "${prefix} Enabled required APIs for project ${projectName}.\n" ||
  (printf "${prefix} [ERROR] Failed to enable required APIs for project ${projectName}.\n" && exit)

printf "${prefix} Creating custom role ${orgRoleID} for listing inherited IAM policies.\n"
gcloud iam roles create "$orgRoleID" --organization "$orgID" --no-user-output-enabled --verbosity=critical ||
  printf "${prefix} [ERROR] Failed to create custom role ${orgRoleID}. This is expected if ${orgRoleID} role already exists in organization ${orgName}.\n"

gcloud iam roles update "$orgRoleID" --organization "$orgID" --quiet --no-user-output-enabled --permissions "\
bigquery.datasets.get,\
cloudsql.instances.list,\
compute.firewalls.list,\
compute.instances.get,\
compute.instances.list,\
compute.instanceGroups.get,\
compute.regions.list,\
compute.subnetworks.list,\
iam.roles.get,\
iam.roles.list,\
logging.buckets.list,\
logging.sinks.list,\
monitoring.alertPolicies.list,\
monitoring.metricDescriptors.list,\
pubsub.topics.getIamPolicy,\
pubsub.topics.list,\
resourcemanager.organizations.get,\
resourcemanager.organizations.getIamPolicy,\
resourcemanager.projects.get,\
resourcemanager.projects.getIamPolicy,\
resourcemanager.projects.list,\
storage.buckets.get,\
storage.buckets.getIamPolicy,\
storage.buckets.list"

printf "${prefix} Creating service account ${serviceAccountID} in project ${projectName}.\n"
gcloud iam service-accounts create "$serviceAccountID" --project "$projectID" --verbosity=critical ||
  printf "${prefix} [ERROR] Failed to create service account. This is expected if service account ${serviceAccountID} already exists in project ${projectName}.\n"

printf "${prefix} Downloading service account key as vamu-scanner-key.json.\n"
gcloud iam service-accounts keys create ./vamu-scanner-key.json --no-user-output-enabled --iam-account "$serviceAccountID@${projectID}.iam.gserviceaccount.com" ||
  printf "${prefix} [ERROR] Failed to generate key for service account $serviceAccountID@${projectID}.iam.gserviceaccount.com. You may have too many keys for this account.\n"

printf "${prefix} Granting ${orgRoleID} to ${serviceAccountID} role in organization ${orgName}.\n"
gcloud organizations add-iam-policy-binding "${orgID}" \
  --member "serviceAccount:${serviceAccountID}@${projectID}.iam.gserviceaccount.com" \
  --role "organizations/${orgID}/roles/${orgRoleID}" --condition=None --format=none

printf "${prefix} Adding securityReviewer role in organization ${orgName}.\n"
gcloud organizations add-iam-policy-binding "${orgID}" \
  --member "serviceAccount:${serviceAccountID}@${projectID}.iam.gserviceaccount.com" \
  --role "roles/iam.securityReviewer" --condition=None --format=none

printf "${prefix} Configuration completed. Upload vamu-scanner-key.json to finish connecting GCP to Vamu.\n"
