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.