Prerequisites
Overview
To successfully integrate your Google Cloud environment with Upwind, ensure the following prerequisites are met:
-
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.
-
Required Permissions:
- Organization/Folder onboarding: Administrator access to your Google Cloud organization
- Multiple Projects onboarding: Administrator access to the individual projects you want to onboard (reduced permissions - no organization admin needed)
-
gcloud CLI Setup. Ensure
gcloudis installed and authenticated with your Google Cloud environment. Ensuregcloudis updated to the latest version.gcloud auth login
gcloud auth application-default login -
Terraform Installed. All Upwind related infrastructure will be deployed via Terraform. The minimum required version of Terraform is
1.11.0.
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.
-
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.
Title Name Cloud Asset API cloudasset.googleapis.comCloud Resource Manager API cloudresourcemanager.googleapis.comCompute Engine API compute.googleapis.comIAM Service Account Credentials API iamcredentials.googleapis.comIdentity and Access Management API iam.googleapis.comKubernetes Engine API container.googleapis.comSecret Manager API secretmanager.googleapis.comSecurity Token Service API sts.googleapis.comService Usage API serviceusage.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.
Title Name Access Approval API accessapproval.googleapis.comAdmin SDK Directory API admin.googleapis.comAlloyDB Admin API alloydb.googleapis.comAPI Keys API apikeys.googleapis.comBigQuery API bigquery.googleapis.comCloud Dataproc API dataproc.googleapis.comCloud DNS API dns.googleapis.comCloud Functions API cloudfunctions.googleapis.comCloud Key Management Service API cloudkms.googleapis.comCloud Logging API logging.googleapis.comCloud Monitoring API monitoring.googleapis.comCloud Redis API redis.googleapis.comCloud SQL Admin API sqladmin.googleapis.comCloud Storage API storage.googleapis.comCloud Storage Insights API storageinsights.googleapis.comEssential Contacts API essentialcontacts.googleapis.com
Additional APIs for Cloud Scanners
These APIs are required for Cloud Scanner deployments, which use both Cloud Run and Cloud Scheduler.
Title Name Cloud Run Admin API run.googleapis.comCloud Scheduler API cloudscheduler.googleapis.com
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 -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 -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++))
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 -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 -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++))
printf " ${GREEN}✓${NC}\n"
else
printf " ${RED}✗${NC}\n"
fi
((completed++))
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.