Skip to main content

Prerequisites

Overview

To successfully integrate your Google Cloud environment with Upwind, ensure the following prerequisites are met.

Prerequisites

1. Google Cloud Environment Structure

  • For Organization/Folder onboarding: Ensure you have a Google Cloud environment structured under an organization node. This is required for centralized visibility and access control across projects and folders. If you need to create one, refer to the Creating and managing organizations documentation.
  • For Multiple Project onboarding: Ensure you have access to the specific project(s) you want to onboard.

2. Required Permissions

Initial Deployment Roles

To perform the onboarding and deploy the Terraform module, the user or service account executing the deployment needs the following roles:

  • For Organization/Folder onboarding: Organization Role Admin and IAM Workload Identity Pool Admin.
  • For Multiple Projects onboarding: Administrator access to the individual projects.

Why are these needed? These elevated roles are required to create IAM roles at the organization/folder level, configure Workload Identity Federation (WIF), and discover projects.

Good to know

These permissions are only required for the initial deployment. Once the deployment is complete, you can safely revoke these elevated "god mode" roles from the deployer account.

Persistent Service Account Permissions

During deployment, the Terraform module provisions a dedicated Upwind Service Account. This service account is assigned a scoped, tailored set of permissions required for continuous operation and scanning. For the complete, up-to-date list of permissions granted to this service account, please refer to the Shared IAM Module Documentation in our public repository .

3. Gcloud CLI Setup

Ensure gcloud is installed and authenticated with your Google Cloud environment. Ensure gcloud is updated to the latest version.

gcloud auth login
gcloud auth application-default login

4. Terraform Installed

All Upwind related infrastructure will be deployed via Terraform. The minimum required version of Terraform is 1.11.0.

MacOS

If you are a Mac user who has installed Terraform using Brew note that this is an older, unsupported version. Please update your Terraform installation using the Hashicorp provided tap.

5. Google Cloud APIs & Services

Ensure the following APIs are enabled in the Google Cloud projects you would like to be covered by Upwind. For more information on how to do this, refer to the Enable and Disable APIs guide.


Mandatory APIs


These are required for basic Upwind functionality.

TitleName
Cloud Asset APIcloudasset.googleapis.com
Cloud Resource Manager APIcloudresourcemanager.googleapis.com
Compute Engine APIcompute.googleapis.com
IAM Service Account Credentials APIiamcredentials.googleapis.com
Identity and Access Management APIiam.googleapis.com
Kubernetes Engine APIcontainer.googleapis.com
Secret Manager APIsecretmanager.googleapis.com
Security Token Service APIsts.googleapis.com
Service Usage APIserviceusage.googleapis.com

Additional APIs for Operation and Posture


These enable additional functionality in the Upwind Platform by allowing access to a wider variety of Google Cloud services.

TitleName
Access Approval APIaccessapproval.googleapis.com
Admin SDK Directory APIadmin.googleapis.com
AlloyDB Admin APIalloydb.googleapis.com
API Keys APIapikeys.googleapis.com
BigQuery APIbigquery.googleapis.com
Cloud Dataproc APIdataproc.googleapis.com
Cloud DNS APIdns.googleapis.com
Cloud Functions APIcloudfunctions.googleapis.com
Cloud Key Management Service APIcloudkms.googleapis.com
Cloud Logging APIlogging.googleapis.com
Cloud Monitoring APImonitoring.googleapis.com
Cloud Redis APIredis.googleapis.com
Cloud SQL Admin APIsqladmin.googleapis.com
Cloud Storage APIstorage.googleapis.com
Cloud Storage Insights APIstorageinsights.googleapis.com
Essential Contacts APIessentialcontacts.googleapis.com

Additional APIs for Cloud Scanners


These APIs are required for Cloud Scanner deployments, which use both Cloud Run and Cloud Scheduler.

TitleName
Cloud Run Admin APIrun.googleapis.com
Cloud Scheduler APIcloudscheduler.googleapis.com
Enable Google Cloud APIs Automatically

The required APIs can be enabled using the following bash script as a Google Cloud admin:

google-cloud-enable-apis.sh
#!/bin/bash

set -euo pipefail

# Colors
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m'

# API Lists
REQUIRED_APIS=(
"cloudasset.googleapis.com"
"cloudresourcemanager.googleapis.com"
"compute.googleapis.com"
"iamcredentials.googleapis.com"
"iam.googleapis.com"
"container.googleapis.com"
"secretmanager.googleapis.com"
"sts.googleapis.com"
"serviceusage.googleapis.com"
)

POSTURE_APIS=(
"accessapproval.googleapis.com"
"admin.googleapis.com"
"alloydb.googleapis.com"
"apikeys.googleapis.com"
"bigquery.googleapis.com"
"dataproc.googleapis.com"
"dns.googleapis.com"
"cloudfunctions.googleapis.com"
"cloudkms.googleapis.com"
"logging.googleapis.com"
"monitoring.googleapis.com"
"redis.googleapis.com"
"sqladmin.googleapis.com"
"storage.googleapis.com"
"storageinsights.googleapis.com"
"essentialcontacts.googleapis.com"
)

CLOUDSCANNER_APIS=(
"run.googleapis.com"
"cloudscheduler.googleapis.com"
)

# Check gcloud is available and authenticated
check_gcloud() {
if ! command -v gcloud &>/dev/null; then
echo -e "${RED}Error: gcloud CLI not found. Please install it first.${NC}"
exit 1
fi

if ! gcloud auth list --filter=status:ACTIVE --format="value(account)" &>/dev/null; then
echo -e "${RED}Error: Not authenticated. Run: gcloud auth login${NC}"
exit 1
fi

echo -e "${GREEN}✓ gcloud authenticated${NC}"
}

# Get all projects
get_projects() {
echo -e "${BLUE}Fetching projects...${NC}"

# Get active projects only
PROJECTS=$(gcloud projects list --filter="lifecycleState:ACTIVE" --format="value(projectId)" 2>/dev/null)

if [ -z "$PROJECTS" ]; then
echo -e "${RED}No active projects found${NC}"
exit 1
fi

# Convert to array
PROJECT_LIST=()
while IFS= read -r line; do
PROJECT_LIST+=("$line")
done <<<"$PROJECTS"
echo -e "${GREEN}Found ${#PROJECT_LIST[@]} projects${NC}"
}

# Display projects for selection
select_projects() {
echo -e "\n${BLUE}Available projects:${NC}"
for i in "${!PROJECT_LIST[@]}"; do
echo " $((i + 1)). ${PROJECT_LIST[i]}"
done

echo -e "\n${YELLOW}Select projects:${NC}"
echo "1. All projects"
echo "2. Specific projects"

while true; do
read -r -p "Choice [1-2]: " choice
case $choice in
1)
SELECTED_PROJECTS=("${PROJECT_LIST[@]}")
echo -e "${GREEN}Selected all ${#SELECTED_PROJECTS[@]} projects${NC}"
break
;;
2)
select_specific_projects
break
;;
*)
echo -e "${RED}Invalid choice${NC}"
;;
esac
done
}

# Select specific projects
select_specific_projects() {
SELECTED_PROJECTS=()
echo -e "\n${YELLOW}Enter project numbers (space-separated, e.g., '1 3 5'):${NC}"

while true; do
read -r -p "Project numbers (or 'done'): " input

if [ "$input" = "done" ]; then
if [ ${#SELECTED_PROJECTS[@]} -eq 0 ]; then
echo -e "${RED}Please select at least one project${NC}"
continue
fi
break
fi

for num in $input; do
if [[ "$num" =~ ^[0-9]+$ ]] && [ "$num" -ge 1 ] && [ "$num" -le ${#PROJECT_LIST[@]} ]; then
project="${PROJECT_LIST[$((num - 1))]}"
# Add if not already selected
if [[ ${#SELECTED_PROJECTS[@]} -eq 0 ]] || [[ ! " ${SELECTED_PROJECTS[@]} " =~ " ${project} " ]]; then
SELECTED_PROJECTS+=("$project")
fi
else
echo -e "${RED}Invalid number: $num${NC}"
fi
done

if [ ${#SELECTED_PROJECTS[@]} -gt 0 ]; then
echo -e "${GREEN}Selected projects:${NC}"
for project in "${SELECTED_PROJECTS[@]}"; do
echo " - $project"
done
fi
done
}

# Check required APIs and warn user
check_required_apis() {
echo -e "\n${BLUE}Checking required APIs...${NC}"

local missing_required=()
local total_checked=0

for project in "${SELECTED_PROJECTS[@]}"; do
echo -n " Checking $project... "

local enabled_apis
enabled_apis=$(get_enabled_apis "$project")

local project_missing=()
for api in "${REQUIRED_APIS[@]}"; do
total_checked=$((total_checked + 1))
if [[ ! "$enabled_apis" =~ $api ]]; then
project_missing+=("$api")
missing_required+=("$project:$api")
fi
done

if [[ ${#project_missing[@]} -eq 0 ]]; then
echo -e "${GREEN}all required APIs enabled${NC}"
else
echo -e "${YELLOW}${#project_missing[@]} required APIs missing${NC}"
fi
done

if [[ ${#missing_required[@]} -gt 0 ]]; then
echo -e "\n${RED}WARNING: Required APIs are missing!${NC}"
echo -e "${YELLOW}The following required APIs are not enabled:${NC}"

# Group by project for better readability
local current_project=""
for item in "${missing_required[@]}"; do
IFS=':' read -r project api <<< "$item"
if [[ "$project" != "$current_project" ]]; then
current_project="$project"
echo -e "\n${BLUE}Project: $project${NC}"
fi
echo " - $api"
done

echo -e "\n${YELLOW}These APIs will be automatically added to your selection.${NC}"
echo -e "${BLUE}You may also want to consider adding APIs from these categories:${NC}"
echo -e " • ${GREEN}Posture APIs${NC} (${#POSTURE_APIS[@]} APIs): Security posture and compliance monitoring"
echo -e " • ${GREEN}Cloud Scanner APIs${NC} (${#CLOUDSCANNER_APIS[@]} APIs): Cloud resource scanning and analysis"
echo -e "\n${YELLOW}Press Enter to continue with required APIs, or Ctrl+C to exit and enable them manually.${NC}"
read -r

# Set flag to indicate required APIs need to be included
INCLUDE_REQUIRED_APIS=true
else
echo -e "${GREEN}✓ All required APIs are enabled${NC}"
INCLUDE_REQUIRED_APIS=false
fi
}

# Select API set
select_api_set() {
echo -e "\n${BLUE}Select API set:${NC}"
echo "1. Upwind Required APIs (${#REQUIRED_APIS[@]} APIs)"
echo "2. Upwind Posture APIs (${#POSTURE_APIS[@]} APIs)"
echo "3. Upwind Cloud Scanner APIs (${#CLOUDSCANNER_APIS[@]} APIs)"
echo "4. All APIs (combined)"

while true; do
read -r -p "Choice [1-4]: " choice
case $choice in
1)
SELECTED_APIS=("${REQUIRED_APIS[@]}")
API_SET_NAME="Required APIs"
break
;;
2)
SELECTED_APIS=("${POSTURE_APIS[@]}")
API_SET_NAME="Posture APIs"
break
;;
3)
SELECTED_APIS=("${CLOUDSCANNER_APIS[@]}")
API_SET_NAME="Cloud Scanner APIs"
break
;;
4)
# Combine all APIs and remove duplicates
ALL_APIS=("${REQUIRED_APIS[@]}" "${POSTURE_APIS[@]}" "${CLOUDSCANNER_APIS[@]}")
SELECTED_APIS=($(printf "%s\n" "${ALL_APIS[@]}" | sort -u))
API_SET_NAME="All APIs"
break
;;
*)
echo -e "${RED}Invalid choice${NC}"
;;
esac
done

# If required APIs are missing, automatically include them
if [[ "$INCLUDE_REQUIRED_APIS" == "true" ]]; then
echo -e "\n${YELLOW}Adding missing required APIs to selection...${NC}"

# Combine selected APIs with required APIs and remove duplicates
COMBINED_APIS=("${SELECTED_APIS[@]}" "${REQUIRED_APIS[@]}")
SELECTED_APIS=($(printf "%s\n" "${COMBINED_APIS[@]}" | sort -u))

if [[ "$API_SET_NAME" == "Required APIs" ]]; then
API_SET_NAME="Required APIs (all)"
else
API_SET_NAME="$API_SET_NAME + Required APIs"
fi
fi

echo -e "${GREEN}Selected: $API_SET_NAME (${#SELECTED_APIS[@]} APIs)${NC}"
}

# Confirm before proceeding
confirm() {
echo -e "\n${YELLOW}Summary:${NC}"
echo "Projects: ${#SELECTED_PROJECTS[@]}"
echo "APIs: $API_SET_NAME (${#SELECTED_APIS[@]})"
echo "Total operations: $((${#SELECTED_PROJECTS[@]} * ${#SELECTED_APIS[@]}))"

while true; do
read -r -p "Proceed? [y/N]: " confirm
case $confirm in
[Yy]*)
break
;;
[Nn]* | "")
echo -e "${YELLOW}Cancelled${NC}"
exit 0
;;
esac
done
}

# Get enabled APIs for a project
get_enabled_apis() {
local project=$1
gcloud services list --enabled --project="$project" --format="value(name)" 2>/dev/null || echo ""
}

# Get missing APIs for a project
get_missing_apis() {
local project=$1
local enabled_apis
enabled_apis=$(get_enabled_apis "$project")

local missing_apis=()
for api in "${SELECTED_APIS[@]}"; do
if [[ ! "$enabled_apis" =~ $api ]]; then
missing_apis+=("$api")
fi
done

# Return missing APIs or empty string if none
if [[ ${#missing_apis[@]} -gt 0 ]]; then
printf '%s\n' "${missing_apis[@]}"
fi
}

enable_apis() {
echo -e "\n${BLUE}Analyzing current API status...${NC}"

# Build list of operations needed
local operations=()
local skipped_count=0

for project in "${SELECTED_PROJECTS[@]}"; do
echo -n " Checking $project... "

local missing_apis
missing_apis=$(get_missing_apis "$project")

if [[ -z "$missing_apis" ]]; then
skipped_count=$((skipped_count + ${#SELECTED_APIS[@]}))
echo -e "${GREEN}all APIs already enabled${NC}"
else
local missing_count
missing_count=$(echo "$missing_apis" | wc -l | tr -d ' ')
local already_enabled=$((${#SELECTED_APIS[@]} - missing_count))
skipped_count=$((skipped_count + already_enabled))
echo -e "${YELLOW}$missing_count APIs needed${NC}"

# Add each missing API as an operation
while IFS= read -r api; do
[[ -n "$api" ]] && operations+=("$project:$api")
done <<<"$missing_apis"
fi
done

local total_ops=${#operations[@]}

if [[ $total_ops -eq 0 ]]; then
echo -e "\n${GREEN}All APIs are already enabled! Nothing to do.${NC}"
return
fi

echo -e "\n${BLUE}Operations needed: $total_ops (skipping $skipped_count already enabled)${NC}"
echo -e "${BLUE}Starting API enablement...${NC}"

local completed=0
local successful=0

echo -e "${BLUE}Project: ${NC}Starting..."

local current_project=""

for operation in "${operations[@]}"; do
IFS=':' read -r project api <<<"$operation"

if [[ "$project" != "$current_project" ]]; then
if [[ -n "$current_project" ]]; then
printf "\033[2A\033[K${BLUE}Project: ${NC}%s ${GREEN}✓ Complete${NC}\n" "$current_project"
printf "\033[1B"
fi
current_project="$project"
printf "\033[1A\033[K${BLUE}Project: ${NC}%s\n" "$project"
echo "Operation: Initializing..."
fi

printf "\033[1A\033[K${YELLOW}Operation: ${NC}Enabling %s..." "$api"

# Enable the API
if gcloud services enable "$api" --project="$project" &>/dev/null; then
successful=$((successful + 1))
printf " ${GREEN}${NC}\n"
else
printf " ${RED}${NC}\n"
fi

completed=$((completed + 1))

echo
done

# Mark final project as complete
if [[ -n "$current_project" ]]; then
printf "\033[2A\033[K${BLUE}Project: ${NC}%s ${GREEN}✓ Complete${NC}\n" "$current_project"
printf "\033[1B" # Move down past the operation line
fi

# Final summary
echo -e "\n${BLUE}=== Results ===${NC}"
echo -e "${GREEN}Successfully enabled: $successful/$total_ops${NC}"
echo -e "${BLUE}Already enabled (skipped): $skipped_count${NC}"

local total_checked=$((total_ops + skipped_count))
if [ $successful -eq $total_ops ]; then
echo -e "${GREEN}All required APIs are now enabled! ($successful enabled, $skipped_count were already active)${NC}"
else
local failed=$((total_ops - successful))
echo -e "${YELLOW}Failed to enable: $failed APIs${NC}"
echo -e "${GREEN}Total APIs now active: $((successful + skipped_count))/$total_checked${NC}"
fi
}

# Main execution
main() {
echo -e "${BLUE}=== Google Cloud API Enabler ===${NC}"

check_gcloud
get_projects
select_projects
check_required_apis
select_api_set
confirm
enable_apis

echo -e "${GREEN}Complete!${NC}"
}

main "$@"

Troubleshooting

If you encounter issues during deployment or operation, consult the Troubleshooting guide for solutions and best practices.