Last updated: Aug 4, 2025, 11:26 AM UTC

GCP Project Foundation Guide

Status: Complete Implementation Guide
Version: 1.0
Purpose: Complete guide for setting up Google Cloud Platform foundation for any project
Applicable To: All GCP deployments requiring automated, production-ready project setup


Overview

This guide provides comprehensive procedures for establishing a robust Google Cloud Platform foundation for any project. Based on proven deployment patterns from production SaaS systems, it covers everything from initial account setup to production-ready project configuration with proper billing, security, and resource management.

Key Benefits

  • Automated Setup: Scripts and templates for consistent project creation
  • Cost Control: Built-in billing safeguards and budget management
  • Security First: IAM best practices and resource isolation
  • Scalable Architecture: Foundation that grows with your project
  • Production Ready: Battle-tested configuration patterns

Prerequisites

Required Tools

# Google Cloud CLI (latest version)
curl https://sdk.cloud.google.com | bash
exec -l $SHELL
gcloud version

# Required for configuration management
brew install jq  # macOS
sudo apt-get install jq  # Ubuntu

Required Accounts & Access

  • Google Cloud Account with billing enabled
  • Billing Account ID (format: XXXXXX-XXXXXX-XXXXXX)
  • Project Owner or Editor permissions
  • Billing Account User role (if separate from owner)

Architecture Decision Points

Before starting, decide on:

Decision Options Recommendation
Project Structure Single project vs. multi-project Single for MVP, multi for production
Region Strategy Single region vs. multi-region Single region initially
Billing Approach Shared billing vs. dedicated Dedicated for production
Organization Under organization vs. standalone Organization for enterprise

Configuration Management System

Step 1: Project Configuration Template

Create a standardized configuration system that works for any project type:

# config-template.env - Universal GCP project template
# ===============================================
# PROJECT FOUNDATION (Required)
# ===============================================

# Unique GCP project ID (lowercase, hyphens allowed, 6-30 characters)
# Pattern: {company}-{service}-{environment}
# Examples: acme-api-prod, startup-web-staging, corp-ml-dev
PROJECT_ID=your-project-name-prod

# Human-readable project name (can contain spaces and special characters)
# Examples: "Acme API Production", "Startup Web Platform", "ML Training Environment"
PROJECT_NAME="Your Project Production"

# Your GCP billing account ID (format: XXXXXX-XXXXXX-XXXXXX)
# Find at: https://console.cloud.google.com/billing
BILLING_ACCOUNT_ID=

# Primary Google Cloud region for resources
# Common choices: us-central1, europe-west2, asia-southeast1
# Consider: data residency, latency, available services
REGION=us-central1

# Your Google account email (must have billing permissions)
ACCOUNT_EMAIL=

# ===============================================
# ORGANIZATIONAL STRUCTURE (Optional)
# ===============================================

# Organization ID (for enterprise deployments)
# Get with: gcloud organizations list
ORGANIZATION_ID=

# Folder ID (for project grouping within organization)
# Get with: gcloud resource-manager folders list
FOLDER_ID=

# Environment type (affects naming, policies, and resource allocation)
ENVIRONMENT=production  # Options: development, staging, production

# ===============================================
# RESOURCE LIMITS AND POLICIES
# ===============================================

# Default compute zone within region
ZONE=${REGION}-a

# Project labels for organization and billing
PROJECT_LABELS="environment=${ENVIRONMENT},team=platform,cost-center=engineering"

# Budget configuration (USD)
MONTHLY_BUDGET_LIMIT=100
BUDGET_ALERT_THRESHOLDS="50,75,90,100"  # Percentage thresholds

# Default resource quotas
DEFAULT_FUNCTION_MEMORY=512MB
DEFAULT_FUNCTION_TIMEOUT=60s
DEFAULT_MAX_INSTANCES=100

# ===============================================
# SECURITY CONFIGURATION
# ===============================================

# Service account naming pattern
SERVICE_ACCOUNT_PREFIX=${PROJECT_ID}

# Enable audit logging
ENABLE_AUDIT_LOGS=true

# Enable VPC firewall rules
ENABLE_VPC_SECURITY=true

# API key restrictions
ENABLE_API_KEY_RESTRICTIONS=true

Step 2: Configuration Setup Script

#!/bin/bash
# 00-setup-config.sh - Universal project configuration setup

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${SCRIPT_DIR}/deployment.env"
TEMPLATE_FILE="${SCRIPT_DIR}/config-template.env"

echo "==========================================="
echo "πŸ—οΈ  GCP Project Configuration Setup"
echo "==========================================="

# Function to validate project ID format
validate_project_id() {
    local project_id="$1"
    if [[ ! "$project_id" =~ ^[a-z][a-z0-9-]{4,28}[a-z0-9]$ ]]; then
        echo "❌ Invalid project ID format: $project_id"
        echo "Requirements:"
        echo "  β€’ 6-30 characters"
        echo "  β€’ Lowercase letters, numbers, and hyphens only"
        echo "  β€’ Must start with letter"
        echo "  β€’ Must end with letter or number"
        return 1
    fi
    return 0
}

# Check if config already exists
if [ -f "$CONFIG_FILE" ]; then
    echo "⚠️  Configuration file already exists: $CONFIG_FILE"
    echo
    read -p "Recreate configuration? (y/n) " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Yy]$ ]]; then
        echo "Using existing configuration."
        echo "To modify, edit $CONFIG_FILE manually."
        exit 0
    fi
fi

# Copy template
if [ ! -f "$TEMPLATE_FILE" ]; then
    echo "❌ Template not found: $TEMPLATE_FILE"
    echo "Please ensure you have the config-template.env file."
    exit 1
fi

echo "Creating configuration from template..."
cp "$TEMPLATE_FILE" "$CONFIG_FILE"

echo "βœ… Configuration template created: $CONFIG_FILE"
echo
echo "πŸ“ Please fill in the required values:"

# Interactive configuration
echo
echo "=== PROJECT CONFIGURATION ==="
read -p "Project ID (e.g., mycompany-api-prod): " PROJECT_ID
while ! validate_project_id "$PROJECT_ID"; do
    read -p "Project ID (e.g., mycompany-api-prod): " PROJECT_ID
done

read -p "Project Name (e.g., \"My Company API Production\"): " PROJECT_NAME
read -p "Billing Account ID (XXXXXX-XXXXXX-XXXXXX): " BILLING_ACCOUNT_ID
read -p "Account Email: " ACCOUNT_EMAIL

echo
echo "=== REGION SELECTION ==="
echo "Common regions:"
echo "  us-central1     - Iowa, USA (lowest cost)"
echo "  us-east1        - South Carolina, USA"
echo "  europe-west2    - London, UK"
echo "  asia-southeast1 - Singapore"
read -p "Region [us-central1]: " REGION
REGION=${REGION:-us-central1}

echo
echo "=== ENVIRONMENT ==="
read -p "Environment [production]: " ENVIRONMENT
ENVIRONMENT=${ENVIRONMENT:-production}

# Update configuration file
update_config() {
    local key="$1"
    local value="$2"
    if [[ "$OSTYPE" == "darwin"* ]]; then
        sed -i "" "s|^${key}=.*|${key}=${value}|g" "$CONFIG_FILE"
    else
        sed -i "s|^${key}=.*|${key}=${value}|g" "$CONFIG_FILE"
    fi
}

update_config "PROJECT_ID" "$PROJECT_ID"
update_config "PROJECT_NAME" "\"$PROJECT_NAME\""
update_config "BILLING_ACCOUNT_ID" "$BILLING_ACCOUNT_ID"
update_config "ACCOUNT_EMAIL" "$ACCOUNT_EMAIL"
update_config "REGION" "$REGION"
update_config "ENVIRONMENT" "$ENVIRONMENT"

echo
echo "βœ… Configuration saved to: $CONFIG_FILE"
echo
echo "πŸ“‹ Configuration Summary:"
echo "  Project ID: $PROJECT_ID"
echo "  Project Name: $PROJECT_NAME"
echo "  Region: $REGION"
echo "  Environment: $ENVIRONMENT"
echo
echo "πŸ”’ Security Notice:"
echo "  β€’ Configuration contains sensitive information"
echo "  β€’ Add deployment.env to .gitignore"
echo "  β€’ Store backups securely"
echo
echo "Next: Run ./01-setup-gcp-account.sh"

GCP Account Setup & Authentication

Step 1: Account Authentication Script

#!/bin/bash
# 01-setup-gcp-account.sh - Comprehensive GCP account setup

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${SCRIPT_DIR}/deployment.env"

# Load and validate configuration
load_config() {
    if [ -f "$CONFIG_FILE" ]; then
        if source "$CONFIG_FILE" 2>/dev/null; then
            echo "βœ… Configuration loaded successfully"
        else
            echo "❌ Invalid configuration syntax in $CONFIG_FILE"
            echo "Run ./00-setup-config.sh to fix configuration issues"
            exit 1
        fi
    else
        echo "❌ Configuration not found: $CONFIG_FILE"
        echo "Run ./00-setup-config.sh first"
        exit 1
    fi
}

# Validate required configuration
validate_config() {
    local missing_vars=()
    
    [ -z "$PROJECT_ID" ] && missing_vars+=("PROJECT_ID")
    [ -z "$ACCOUNT_EMAIL" ] && missing_vars+=("ACCOUNT_EMAIL")
    [ -z "$BILLING_ACCOUNT_ID" ] && missing_vars+=("BILLING_ACCOUNT_ID")
    [ -z "$REGION" ] && missing_vars+=("REGION")
    
    if [ ${#missing_vars[@]} -gt 0 ]; then
        echo "❌ Missing required configuration:"
        printf "  β€’ %s\n" "${missing_vars[@]}"
        echo
        echo "Edit $CONFIG_FILE and set these values"
        exit 1
    fi
}

# Check GCP CLI installation and version
check_gcp_cli() {
    if ! command -v gcloud &> /dev/null; then
        echo "❌ Google Cloud CLI not found"
        echo
        echo "Install with:"
        echo "  curl https://sdk.cloud.google.com | bash"
        echo "  exec -l \$SHELL"
        exit 1
    fi
    
    echo "βœ… Google Cloud CLI version: $(gcloud version --format='value(Google Cloud SDK)')"
}

# Authenticate user account
authenticate_account() {
    echo
    echo "Current authenticated accounts:"
    gcloud auth list
    
    # Check if target account is already authenticated
    if gcloud auth list --filter="account:$ACCOUNT_EMAIL" --format="value(account)" | grep -q "$ACCOUNT_EMAIL"; then
        echo "βœ… Account $ACCOUNT_EMAIL is already authenticated"
        gcloud config set account "$ACCOUNT_EMAIL"
    else
        echo
        echo "Authenticating account: $ACCOUNT_EMAIL"
        gcloud auth login "$ACCOUNT_EMAIL"
    fi
    
    # Verify authentication
    current_account=$(gcloud config get-value account 2>/dev/null)
    if [ "$current_account" = "$ACCOUNT_EMAIL" ]; then
        echo "βœ… Active account: $current_account"
    else
        echo "❌ Authentication failed for $ACCOUNT_EMAIL"
        exit 1
    fi
}

# Verify billing account access
verify_billing_access() {
    echo
    echo "Verifying billing account access..."
    
    if gcloud billing accounts list --format="value(name)" | grep -q "$BILLING_ACCOUNT_ID"; then
        echo "βœ… Billing account accessible: $BILLING_ACCOUNT_ID"
        
        # Get billing account details
        local billing_info=$(gcloud billing accounts describe "$BILLING_ACCOUNT_ID" --format="value(displayName,open)")
        echo "πŸ“‹ Billing account: $billing_info"
    else
        echo "❌ Cannot access billing account: $BILLING_ACCOUNT_ID"
        echo
        echo "Available billing accounts:"
        gcloud billing accounts list --format="table(name,displayName,open)"
        echo
        echo "Please verify:"
        echo "1. Billing account ID is correct"
        echo "2. You have 'Billing Account User' role"
        echo "3. Billing account is active"
        exit 1
    fi
}

# Setup organization context (if applicable)
setup_organization_context() {
    if [ -n "$ORGANIZATION_ID" ]; then
        echo
        echo "Setting up organization context..."
        
        if gcloud organizations describe "$ORGANIZATION_ID" &>/dev/null; then
            echo "βœ… Organization accessible: $ORGANIZATION_ID"
            
            # List available folders if folder ID specified
            if [ -n "$FOLDER_ID" ]; then
                if gcloud resource-manager folders describe "$FOLDER_ID" &>/dev/null; then
                    echo "βœ… Folder accessible: $FOLDER_ID"
                else
                    echo "❌ Cannot access folder: $FOLDER_ID"
                    echo "Available folders:"
                    gcloud resource-manager folders list --organization="$ORGANIZATION_ID" --format="table(name,displayName)"
                    exit 1
                fi
            fi
        else
            echo "❌ Cannot access organization: $ORGANIZATION_ID"
            echo "Available organizations:"
            gcloud organizations list --format="table(name,displayName)"
            exit 1
        fi
    fi
}

# Main execution
main() {
    echo "==========================================="
    echo "πŸ” GCP Account Setup & Authentication"
    echo "==========================================="
    
    load_config
    validate_config
    check_gcp_cli
    authenticate_account
    verify_billing_access
    setup_organization_context
    
    # Save authentication state
    cat > "${SCRIPT_DIR}/.deployment-state" << EOF
# Deployment state - automatically generated
GCP_AUTHENTICATED=true
ACCOUNT_VERIFIED=true
BILLING_VERIFIED=true
ORGANIZATION_VERIFIED=${ORGANIZATION_ID:+true}
TIMESTAMP=$(date -u +"%Y-%m-%d %H:%M:%S UTC")
GCLOUD_VERSION=$(gcloud version --format='value(Google Cloud SDK)')
EOF
    
    echo
    echo "βœ… GCP account setup complete!"
    echo
    echo "πŸ“‹ Summary:"
    echo "  Account: $ACCOUNT_EMAIL"
    echo "  Project: $PROJECT_ID"
    echo "  Region: $REGION"
    echo "  Billing: $BILLING_ACCOUNT_ID"
    [ -n "$ORGANIZATION_ID" ] && echo "  Organization: $ORGANIZATION_ID"
    [ -n "$FOLDER_ID" ] && echo "  Folder: $FOLDER_ID"
    echo
    echo "Next: Run ./02-create-project.sh"
}

main "$@"

Project Creation & Configuration

Step 1: Project Creation Script

#!/bin/bash
# 02-create-project.sh - Create and configure GCP project

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${SCRIPT_DIR}/deployment.env"

# Load configuration
source "$CONFIG_FILE"

# Project creation with comprehensive setup
create_project() {
    echo
    echo "Creating GCP project: $PROJECT_ID"
    
    # Check if project already exists
    if gcloud projects describe "$PROJECT_ID" &>/dev/null; then
        echo "⚠️  Project $PROJECT_ID already exists"
        
        local current_name=$(gcloud projects describe "$PROJECT_ID" --format="value(name)")
        echo "Current name: $current_name"
        
        read -p "Continue with existing project? (y/n) " -n 1 -r
        echo
        if [[ ! $REPLY =~ ^[Yy]$ ]]; then
            echo "Project creation cancelled"
            exit 1
        fi
    else
        # Create new project
        local create_cmd="gcloud projects create '$PROJECT_ID' --name='$PROJECT_NAME'"
        
        # Add organization/folder context if specified
        if [ -n "$ORGANIZATION_ID" ]; then
            create_cmd="$create_cmd --organization='$ORGANIZATION_ID'"
        elif [ -n "$FOLDER_ID" ]; then
            create_cmd="$create_cmd --folder='$FOLDER_ID'"
        fi
        
        echo "Creating project with command:"
        echo "$create_cmd"
        eval "$create_cmd"
        
        echo "βœ… Project created: $PROJECT_ID"
    fi
}

# Link billing account
setup_billing() {
    echo
    echo "Linking billing account..."
    
    # Check current billing account
    current_billing=$(gcloud billing projects describe "$PROJECT_ID" --format="value(billingAccountName)" 2>/dev/null || echo "")
    
    if [[ "$current_billing" == *"$BILLING_ACCOUNT_ID" ]]; then
        echo "βœ… Billing already linked: $BILLING_ACCOUNT_ID"
    else
        echo "Linking billing account: $BILLING_ACCOUNT_ID"
        gcloud billing projects link "$PROJECT_ID" --billing-account="$BILLING_ACCOUNT_ID"
        echo "βœ… Billing account linked successfully"
    fi
}

# Set default project configuration
configure_defaults() {
    echo
    echo "Configuring project defaults..."
    
    # Set project as default
    gcloud config set project "$PROJECT_ID"
    echo "βœ… Default project: $PROJECT_ID"
    
    # Set default region and zone
    gcloud config set compute/region "$REGION"
    gcloud config set compute/zone "${ZONE:-${REGION}-a}"
    echo "βœ… Default region: $REGION"
    echo "βœ… Default zone: ${ZONE:-${REGION}-a}"
    
    # Set default function region
    gcloud config set functions/region "$REGION"
    echo "βœ… Default functions region: $REGION"
}

# Apply project labels
apply_project_labels() {
    if [ -n "$PROJECT_LABELS" ]; then
        echo
        echo "Applying project labels..."
        
        # Convert comma-separated labels to gcloud format
        local labels_array=()
        IFS=',' read -ra ADDR <<< "$PROJECT_LABELS"
        for label in "${ADDR[@]}"; do
            labels_array+=("$label")
        done
        
        local labels_string=$(IFS=','; echo "${labels_array[*]}")
        gcloud projects update "$PROJECT_ID" --update-labels="$labels_string"
        echo "βœ… Project labels applied: $labels_string"
    fi
}

# Setup IAM policies
setup_basic_iam() {
    echo
    echo "Setting up basic IAM policies..."
    
    # Grant current user necessary roles
    gcloud projects add-iam-policy-binding "$PROJECT_ID" \
        --member="user:$ACCOUNT_EMAIL" \
        --role="roles/owner" \
        --quiet
    
    echo "βœ… IAM policies configured"
}

# Main execution
main() {
    echo "==========================================="
    echo "🏒 GCP Project Creation & Setup"
    echo "Project: $PROJECT_ID"
    echo "Name: $PROJECT_NAME"
    echo "==========================================="
    
    create_project
    setup_billing
    configure_defaults
    apply_project_labels
    setup_basic_iam
    
    # Save project state
    cat >> "${SCRIPT_DIR}/.deployment-state" << EOF
PROJECT_CREATED=true
PROJECT_CONFIGURED=true
BILLING_LINKED=true
PROJECT_CREATION_TIMESTAMP=$(date -u +"%Y-%m-%d %H:%M:%S UTC")
EOF
    
    echo
    echo "βœ… Project setup complete!"
    echo
    echo "πŸ“‹ Project Details:"
    gcloud projects describe "$PROJECT_ID" --format="table(projectId,name,projectNumber,lifecycleState)"
    echo
    echo "πŸ’° Billing Status:"
    gcloud billing projects describe "$PROJECT_ID" --format="table(projectId,billingAccountName,billingEnabled)"
    echo
    echo "Next: Run ./03-enable-apis.sh"
}

main "$@"

API Enablement & Service Configuration

Step 1: Comprehensive API Enablement

#!/bin/bash
# 03-enable-apis.sh - Enable required Google Cloud APIs

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${SCRIPT_DIR}/deployment.env"

# Load configuration
source "$CONFIG_FILE"

# Define API sets for different project types
declare -A API_SETS

# Core APIs (always required)
API_SETS[core]="
cloudresourcemanager.googleapis.com
iam.googleapis.com
serviceusage.googleapis.com
cloudbilling.googleapis.com
logging.googleapis.com
monitoring.googleapis.com
"

# Compute APIs
API_SETS[compute]="
compute.googleapis.com
container.googleapis.com
"

# Serverless APIs
API_SETS[serverless]="
cloudfunctions.googleapis.com
run.googleapis.com
cloudbuild.googleapis.com
artifactregistry.googleapis.com
eventarc.googleapis.com
pubsub.googleapis.com
"

# Database APIs
API_SETS[database]="
firestore.googleapis.com
firebase.googleapis.com
sqladmin.googleapis.com
redis.googleapis.com
"

# Storage APIs
API_SETS[storage]="
storage-api.googleapis.com
storage-component.googleapis.com
"

# Security APIs
API_SETS[security]="
secretmanager.googleapis.com
cloudkms.googleapis.com
securitycenter.googleapis.com
"

# Additional service APIs
API_SETS[services]="
gmail.googleapis.com
calendar-json.googleapis.com
drive.googleapis.com
sheets.googleapis.com
docs.googleapis.com
translate.googleapis.com
vision.googleapis.com
"

# Function to enable APIs with retry logic
enable_apis_batch() {
    local api_list="$1"
    local batch_name="$2"
    
    echo
    echo "Enabling $batch_name APIs..."
    
    # Convert newline-separated list to space-separated
    local apis=$(echo "$api_list" | tr '\n' ' ' | xargs)
    
    if [ -n "$apis" ]; then
        echo "APIs to enable: $apis"
        
        # Enable APIs with retry
        local max_retries=3
        local retry_count=0
        
        while [ $retry_count -lt $max_retries ]; do
            if gcloud services enable $apis --project="$PROJECT_ID"; then
                echo "βœ… $batch_name APIs enabled successfully"
                break
            else
                retry_count=$((retry_count + 1))
                echo "⚠️  Retry $retry_count/$max_retries for $batch_name APIs"
                sleep 5
            fi
        done
        
        if [ $retry_count -eq $max_retries ]; then
            echo "❌ Failed to enable $batch_name APIs after $max_retries attempts"
            return 1
        fi
    fi
}

# Check if API is enabled
check_api_status() {
    local api="$1"
    gcloud services list --enabled --project="$PROJECT_ID" --format="value(name)" | grep -q "^$apiCODE_BLOCK_5quot;
}

# Interactive API selection
select_api_sets() {
    echo "Select which API sets to enable for your project:"
    echo
    
    local selected_sets=("core")  # Core is always included
    
    echo "βœ… core - Always included (Resource Manager, IAM, Billing, Logging)"
    
    # Serverless/Functions
    echo
    read -p "Enable serverless APIs? (Cloud Functions, Cloud Run, Pub/Sub) [Y/n] " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Nn]$ ]]; then
        selected_sets+=("serverless")
        echo "βœ… serverless - Cloud Functions, Cloud Run, Cloud Build"
    fi
    
    # Database
    echo
    read -p "Enable database APIs? (Firestore, Cloud SQL, Redis) [Y/n] " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Nn]$ ]]; then
        selected_sets+=("database")
        echo "βœ… database - Firestore, Cloud SQL, Redis"
    fi
    
    # Storage
    echo
    read -p "Enable storage APIs? (Cloud Storage) [Y/n] " -n 1 -r
    echo
    if [[ ! $REPLY =~ ^[Nn]$ ]]; then
        selected_sets+=("storage")
        echo "βœ… storage - Cloud Storage"
    fi
    
    # Compute
    echo
    read -p "Enable compute APIs? (Compute Engine, GKE) [y/N] " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        selected_sets+=("compute")
        echo "βœ… compute - Compute Engine, GKE"
    fi
    
    # Security
    echo
    read -p "Enable security APIs? (Secret Manager, Cloud KMS) [y/N] " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        selected_sets+=("security")
        echo "βœ… security - Secret Manager, Cloud KMS"
    fi
    
    # Additional services
    echo
    read -p "Enable Google Workspace APIs? (Gmail, Drive, Sheets) [y/N] " -n 1 -r
    echo
    if [[ $REPLY =~ ^[Yy]$ ]]; then
        selected_sets+=("services")
        echo "βœ… services - Gmail, Drive, Sheets, Translate, Vision"
    fi
    
    echo "${selected_sets[@]}"
}

# Main execution
main() {
    echo "==========================================="
    echo "πŸ”Œ Google Cloud APIs Enablement"
    echo "Project: $PROJECT_ID"
    echo "==========================================="
    
    # Get selected API sets
    local api_sets=($(select_api_sets))
    
    echo
    echo "Enabling APIs for: ${api_sets[*]}"
    echo
    
    # Enable each selected API set
    for set_name in "${api_sets[@]}"; do
        if [ -n "${API_SETS[$set_name]}" ]; then
            enable_apis_batch "${API_SETS[$set_name]}" "$set_name"
        fi
    done
    
    echo
    echo "Waiting for APIs to be fully enabled..."
    sleep 10
    
    # Verify API enablement
    echo
    echo "Verifying enabled APIs..."
    local enabled_apis=$(gcloud services list --enabled --project="$PROJECT_ID" --format="value(name)" | wc -l)
    echo "βœ… Total enabled APIs: $enabled_apis"
    
    # List enabled APIs
    echo
    echo "πŸ“‹ Enabled APIs:"
    gcloud services list --enabled --project="$PROJECT_ID" --format="table(name,title)" --sort-by="name"
    
    # Save API state
    cat >> "${SCRIPT_DIR}/.deployment-state" << EOF
APIS_ENABLED=true
ENABLED_API_SETS="${api_sets[*]}"
API_ENABLEMENT_TIMESTAMP=$(date -u +"%Y-%m-%d %H:%M:%S UTC")
TOTAL_ENABLED_APIS=$enabled_apis
EOF
    
    echo
    echo "βœ… API enablement complete!"
    echo
    echo "⚠️  Note: Some APIs may take a few minutes to be fully available"
    echo "If you encounter API-related errors, wait a few minutes and retry"
    echo
    echo "Next: Run ./04-configure-project.sh"
}

main "$@"

Project Configuration & Security

Step 1: Advanced Project Configuration

#!/bin/bash
# 04-configure-project.sh - Advanced project configuration and security

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${SCRIPT_DIR}/deployment.env"

# Load configuration
source "$CONFIG_FILE"

# Setup budget alerts
setup_budget_alerts() {
    if [ -n "$MONTHLY_BUDGET_LIMIT" ]; then
        echo
        echo "Setting up budget alerts..."
        
        # Check if budget already exists
        local existing_budget=$(gcloud billing budgets list --billing-account="$BILLING_ACCOUNT_ID" \
            --format="value(name)" --filter="displayName:$PROJECT_ID-budget" 2>/dev/null || echo "")
        
        if [ -n "$existing_budget" ]; then
            echo "βœ… Budget already exists: $existing_budget"
        else
            # Create budget configuration
            cat > "${SCRIPT_DIR}/budget-config.json" << EOF
{
  "displayName": "$PROJECT_ID-budget",
  "budgetFilter": {
    "projects": ["projects/$PROJECT_ID"]
  },
  "amount": {
    "specifiedAmount": {
      "currencyCode": "USD",
      "units": "$MONTHLY_BUDGET_LIMIT"
    }
  },
  "thresholdRules": [
EOF
            
            # Add threshold rules
            local thresholds=(${BUDGET_ALERT_THRESHOLDS//,/ })
            for i in "${!thresholds[@]}"; do
                local threshold="${thresholds[$i]}"
                cat >> "${SCRIPT_DIR}/budget-config.json" << EOF
    {
      "thresholdPercent": $(echo "scale=2; $threshold / 100" | bc),
      "spendBasis": "CURRENT_SPEND"
    }$([ $i -lt $((${#thresholds[@]} - 1)) ] && echo ",")
EOF
            done
            
            cat >> "${SCRIPT_DIR}/budget-config.json" << EOF
  ]
}
EOF
            
            # Create budget
            gcloud billing budgets create --billing-account="$BILLING_ACCOUNT_ID" \
                --budget-file="${SCRIPT_DIR}/budget-config.json"
            
            # Clean up temp file
            rm "${SCRIPT_DIR}/budget-config.json"
            
            echo "βœ… Budget created: $MONTHLY_BUDGET_LIMIT USD/month"
            echo "πŸ“§ Alert thresholds: $BUDGET_ALERT_THRESHOLDS%"
        fi
    fi
}

# Configure audit logging
setup_audit_logging() {
    if [ "$ENABLE_AUDIT_LOGS" = "true" ]; then
        echo
        echo "Configuring audit logging..."
        
        # Create audit config
        cat > "${SCRIPT_DIR}/audit-config.yaml" << EOF
auditConfigs:
- service: allServices
  auditLogConfigs:
  - logType: ADMIN_READ
  - logType: DATA_READ
  - logType: DATA_WRITE
EOF
        
        # Apply audit configuration
        gcloud projects set-iam-policy "$PROJECT_ID" "${SCRIPT_DIR}/audit-config.yaml" \
            --format="none" || echo "⚠️  Audit logging may already be configured"
        
        # Clean up temp file
        rm "${SCRIPT_DIR}/audit-config.yaml"
        
        echo "βœ… Audit logging configured"
    fi
}

# Setup service accounts
setup_service_accounts() {
    echo
    echo "Setting up service accounts..."
    
    # Main service account for application
    local app_sa="${SERVICE_ACCOUNT_PREFIX}-app"
    local app_sa_email="${app_sa}@${PROJECT_ID}.iam.gserviceaccount.com"
    
    if gcloud iam service-accounts describe "$app_sa_email" &>/dev/null; then
        echo "βœ… Application service account exists: $app_sa_email"
    else
        gcloud iam service-accounts create "$app_sa" \
            --display-name="$PROJECT_NAME Application Service Account" \
            --description="Main service account for $PROJECT_NAME application components"
        echo "βœ… Created application service account: $app_sa_email"
    fi
    
    # Deployment service account
    local deploy_sa="${SERVICE_ACCOUNT_PREFIX}-deploy"
    local deploy_sa_email="${deploy_sa}@${PROJECT_ID}.iam.gserviceaccount.com"
    
    if gcloud iam service-accounts describe "$deploy_sa_email" &>/dev/null; then
        echo "βœ… Deployment service account exists: $deploy_sa_email"
    else
        gcloud iam service-accounts create "$deploy_sa" \
            --display-name="$PROJECT_NAME Deployment Service Account" \
            --description="Service account for CI/CD and deployment operations"
        echo "βœ… Created deployment service account: $deploy_sa_email"
    fi
    
    # Save service account emails
    cat >> "${SCRIPT_DIR}/.deployment-state" << EOF
APP_SERVICE_ACCOUNT=$app_sa_email
DEPLOY_SERVICE_ACCOUNT=$deploy_sa_email
EOF
}

# Configure resource quotas
configure_quotas() {
    echo
    echo "Configuring resource quotas..."
    
    # Set Cloud Functions quotas
    if gcloud services list --enabled --format="value(name)" | grep -q "cloudfunctions.googleapis.com"; then
        # Note: Quotas are typically managed through Cloud Console or support tickets
        echo "βœ… Cloud Functions quotas: Using default limits"
        echo "   β€’ Concurrent executions: 1000 per region"
        echo "   β€’ Memory: Up to 8GB per function"
        echo "   β€’ Timeout: Up to 540 seconds"
    fi
    
    # Set Firestore quotas
    if gcloud services list --enabled --format="value(name)" | grep -q "firestore.googleapis.com"; then
        echo "βœ… Firestore quotas: Using default limits"
        echo "   β€’ Reads: 50,000 per day (free tier)"
        echo "   β€’ Writes: 20,000 per day (free tier)"
        echo "   β€’ Storage: 1GB (free tier)"
    fi
}

# Setup networking (if VPC security enabled)
setup_networking() {
    if [ "$ENABLE_VPC_SECURITY" = "true" ]; then
        echo
        echo "Setting up VPC security..."
        
        # Create custom VPC network
        local vpc_name="${PROJECT_ID}-vpc"
        
        if gcloud compute networks describe "$vpc_name" --format="value(name)" &>/dev/null; then
            echo "βœ… VPC network exists: $vpc_name"
        else
            gcloud compute networks create "$vpc_name" \
                --subnet-mode=custom \
                --description="Custom VPC for $PROJECT_NAME"
            
            # Create subnet
            gcloud compute networks subnets create "${vpc_name}-subnet" \
                --network="$vpc_name" \
                --range="10.0.0.0/24" \
                --region="$REGION"
            
            echo "βœ… Created VPC network: $vpc_name"
        fi
        
        # Setup firewall rules
        local fw_rule_name="${vpc_name}-allow-internal"
        if ! gcloud compute firewall-rules describe "$fw_rule_name" &>/dev/null; then
            gcloud compute firewall-rules create "$fw_rule_name" \
                --network="$vpc_name" \
                --allow="tcp,udp,icmp" \
                --source-ranges="10.0.0.0/24" \
                --description="Allow internal communication within VPC"
            echo "βœ… Created firewall rule: $fw_rule_name"
        fi
    fi
}

# Generate project summary
generate_project_summary() {
    echo
    echo "Generating project summary..."
    
    cat > "${SCRIPT_DIR}/project-summary.md" << EOF
# $PROJECT_NAME - Project Summary

**Generated**: $(date -u +"%Y-%m-%d %H:%M:%S UTC")

## Project Details
- **Project ID**: $PROJECT_ID
- **Project Name**: $PROJECT_NAME
- **Environment**: $ENVIRONMENT
- **Region**: $REGION
- **Zone**: ${ZONE:-${REGION}-a}

## Billing & Budget
- **Billing Account**: $BILLING_ACCOUNT_ID
- **Monthly Budget**: \${MONTHLY_BUDGET_LIMIT:-Not set}
- **Alert Thresholds**: ${BUDGET_ALERT_THRESHOLDS:-Not set}%

## Service Accounts
$(gcloud iam service-accounts list --format="table(email,displayName)" --filter="email:*@$PROJECT_ID.iam.gserviceaccount.com")

## Enabled APIs
$(gcloud services list --enabled --format="table(name,title)" --sort-by="name")

## Configuration
- **Audit Logging**: ${ENABLE_AUDIT_LOGS:-false}
- **VPC Security**: ${ENABLE_VPC_SECURITY:-false}
- **API Key Restrictions**: ${ENABLE_API_KEY_RESTRICTIONS:-false}

## Default Resource Limits
- **Function Memory**: ${DEFAULT_FUNCTION_MEMORY:-512MB}
- **Function Timeout**: ${DEFAULT_FUNCTION_TIMEOUT:-60s}
- **Max Instances**: ${DEFAULT_MAX_INSTANCES:-100}

## Next Steps
1. Deploy your application components
2. Configure monitoring and alerting
3. Set up CI/CD pipelines
4. Implement security scanning
5. Create backup and disaster recovery plans
EOF
    
    echo "βœ… Project summary saved: ${SCRIPT_DIR}/project-summary.md"
}

# Main execution
main() {
    echo "==========================================="
    echo "βš™οΈ  Advanced Project Configuration"
    echo "Project: $PROJECT_ID"
    echo "==========================================="
    
    setup_budget_alerts
    setup_audit_logging
    setup_service_accounts
    configure_quotas
    setup_networking
    generate_project_summary
    
    # Update deployment state
    cat >> "${SCRIPT_DIR}/.deployment-state" << EOF
ADVANCED_CONFIG_COMPLETE=true
BUDGET_CONFIGURED=${MONTHLY_BUDGET_LIMIT:+true}
AUDIT_LOGGING_ENABLED=$ENABLE_AUDIT_LOGS
VPC_SECURITY_ENABLED=$ENABLE_VPC_SECURITY
CONFIGURATION_TIMESTAMP=$(date -u +"%Y-%m-%d %H:%M:%S UTC")
EOF
    
    echo
    echo "βœ… Project configuration complete!"
    echo
    echo "πŸ“‹ Configuration Summary:"
    echo "  β€’ Budget alerts: ${MONTHLY_BUDGET_LIMIT:+$MONTHLY_BUDGET_LIMIT USD/month}"
    echo "  β€’ Audit logging: $ENABLE_AUDIT_LOGS"
    echo "  β€’ VPC security: $ENABLE_VPC_SECURITY"
    echo "  β€’ Service accounts: Created"
    echo
    echo "πŸ“„ Project summary: ${SCRIPT_DIR}/project-summary.md"
    echo
    echo "βœ… Foundation setup complete!"
    echo "Your GCP project is ready for application deployment."
}

main "$@"

Testing & Validation

Comprehensive Validation Script

#!/bin/bash
# validate-foundation.sh - Validate GCP foundation setup

set -e

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
CONFIG_FILE="${SCRIPT_DIR}/deployment.env"
STATE_FILE="${SCRIPT_DIR}/.deployment-state"

# Load configuration and state
source "$CONFIG_FILE"
[ -f "$STATE_FILE" ] && source "$STATE_FILE"

# Validation functions
validate_project_access() {
    echo "πŸ” Validating project access..."
    
    if gcloud projects describe "$PROJECT_ID" &>/dev/null; then
        echo "βœ… Project accessible: $PROJECT_ID"
        return 0
    else
        echo "❌ Cannot access project: $PROJECT_ID"
        return 1
    fi
}

validate_billing() {
    echo "πŸ” Validating billing configuration..."
    
    local billing_status=$(gcloud billing projects describe "$PROJECT_ID" --format="value(billingEnabled)" 2>/dev/null)
    if [ "$billing_status" = "True" ]; then
        echo "βœ… Billing enabled"
        return 0
    else
        echo "❌ Billing not enabled"
        return 1
    fi
}

validate_apis() {
    echo "πŸ” Validating required APIs..."
    
    local required_apis=("cloudresourcemanager.googleapis.com" "iam.googleapis.com")
    local missing_apis=()
    
    for api in "${required_apis[@]}"; do
        if gcloud services list --enabled --project="$PROJECT_ID" --format="value(name)" | grep -q "^$apiCODE_BLOCK_7quot;; then
            echo "βœ… API enabled: $api"
        else
            echo "❌ API missing: $api"
            missing_apis+=("$api")
        fi
    done
    
    [ ${#missing_apis[@]} -eq 0 ]
}

validate_permissions() {
    echo "πŸ” Validating IAM permissions..."
    
    # Check if current user has owner/editor role
    local user_roles=$(gcloud projects get-iam-policy "$PROJECT_ID" \
        --format="value(bindings[].members)" \
        --filter="bindings.role:roles/owner OR bindings.role:roles/editor" \
        | grep "user:$ACCOUNT_EMAIL" || echo "")
    
    if [ -n "$user_roles" ]; then
        echo "βœ… User has necessary permissions"
        return 0
    else
        echo "❌ User lacks necessary permissions"
        return 1
    fi
}

# Run all validations
main() {
    echo "==========================================="
    echo "πŸ§ͺ GCP Foundation Validation"
    echo "Project: $PROJECT_ID"
    echo "==========================================="
    
    local validation_errors=0
    
    validate_project_access || ((validation_errors++))
    validate_billing || ((validation_errors++))
    validate_apis || ((validation_errors++))
    validate_permissions || ((validation_errors++))
    
    echo
    if [ $validation_errors -eq 0 ]; then
        echo "βœ… All validations passed!"
        echo "Your GCP foundation is properly configured."
    else
        echo "❌ $validation_errors validation(s) failed"
        echo "Please review and fix the issues above."
        exit 1
    fi
}

main "$@"

Templates & Examples

Multi-Environment Configuration

# Example configurations for different environments

# Development Environment
PROJECT_ID=mycompany-api-dev
PROJECT_NAME="My Company API Development"
ENVIRONMENT=development
MONTHLY_BUDGET_LIMIT=50
ENABLE_AUDIT_LOGS=false
ENABLE_VPC_SECURITY=false

# Staging Environment  
PROJECT_ID=mycompany-api-staging
PROJECT_NAME="My Company API Staging"
ENVIRONMENT=staging
MONTHLY_BUDGET_LIMIT=100
ENABLE_AUDIT_LOGS=true
ENABLE_VPC_SECURITY=true

# Production Environment
PROJECT_ID=mycompany-api-prod
PROJECT_NAME="My Company API Production"
ENVIRONMENT=production
MONTHLY_BUDGET_LIMIT=500
ENABLE_AUDIT_LOGS=true
ENABLE_VPC_SECURITY=true

This comprehensive GCP Project Foundation Guide provides everything needed to establish a robust, secure, and cost-controlled foundation for any Google Cloud Platform project. The modular approach allows customization for different project types while maintaining production-ready standards.