This Terraform configuration captures the existing infrastructure for the SF Beach App deployed on Google Cloud Platform.
- Cloud Storage: 2 buckets (beach-images, cloudbuild)
- Cloud Run: 1 service (sf-beach-ratings)
- Cloud SQL: 1 PostgreSQL 15 instance (sf-beach-db)
- Service Accounts: Vertex AI service account
- Networking: Default VPC with standard firewall rules
- APIs: 30+ enabled Google Cloud APIs
- Compute: Cloud Run for serverless backend
- Storage: Cloud Storage for images and build artifacts
- Database: Cloud SQL PostgreSQL for application data
- AI/ML: Vertex AI API for Gemini Flash model access
- Maps: Google Maps and Places APIs for location features
-
Terraform: Install Terraform >= 1.0
brew install terraform
-
Google Cloud SDK: Already configured with your project
gcloud auth application-default login gcloud config set project sf-beach-app -
Permissions: Ensure you have Owner or Editor role on the project
Since these resources already exist in GCP, you need to import them into Terraform state:
# Initialize Terraform
terraform init
# Import Cloud Storage buckets
terraform import google_storage_bucket.beach_images sf-beach-app-beach-images
terraform import google_storage_bucket.cloudbuild sf-beach-app_cloudbuild
# Import Cloud SQL instance
terraform import google_sql_database_instance.main sf-beach-db
# Import Cloud Run service
terraform import google_cloud_run_service.beach_ratings locations/us-west1/namespaces/sf-beach-app/services/sf-beach-ratings
# Import Service Account
terraform import google_service_account.vertex_ai projects/sf-beach-app/serviceAccounts/vertex-ai-sa@sf-beach-app.iam.gserviceaccount.com
# Import IAM bindings
terraform import google_cloud_run_service_iam_member.public_access "projects/sf-beach-app/locations/us-west1/services/sf-beach-ratings roles/run.invoker allUsers"
# Import firewall rules (these exist by default)
terraform import google_compute_firewall.default_allow_icmp projects/sf-beach-app/global/firewalls/default-allow-icmp
terraform import google_compute_firewall.default_allow_internal projects/sf-beach-app/global/firewalls/default-allow-internal
terraform import google_compute_firewall.default_allow_rdp projects/sf-beach-app/global/firewalls/default-allow-rdp
terraform import google_compute_firewall.default_allow_ssh projects/sf-beach-app/global/firewalls/default-allow-ssh
# Import APIs (repeat for each API in apis.tf)
terraform import google_project_service.compute sf-beach-app/compute.googleapis.com
terraform import google_project_service.cloud_run sf-beach-app/run.googleapis.com
# ... (continue for other APIs)# Check what Terraform plans to change
terraform plan
# If there are differences, review them carefully
# You may need to adjust the configuration to match existing resourcesIMPORTANT: Before running terraform apply, you need to update:
-
Cloud Run Image: In
main.tf, update the container image URL:image = "gcr.io/sf-beach-app/beach-ratings:latest"
Get the actual image with:
gcloud run services describe sf-beach-ratings --region=us-west1 --format="value(spec.template.spec.containers[0].image)" -
Environment Variables: Add your actual environment variables to the Cloud Run service configuration
-
Cloud SQL Connection: If Cloud Run connects to Cloud SQL, uncomment the annotation in
main.tf:"run.googleapis.com/cloudsql-instances" = google_sql_database_instance.main.connection_name
-
Database Users: You'll need to create separate resources for database users and databases
These items exist but aren't managed by this Terraform config:
- Database schemas and data: Only the instance is managed
- Database users: Need to be added separately
- Secrets: You have Secret Manager enabled but no secrets created yet
- Container images: Stored in Artifact Registry/Container Registry
- Vertex AI: Only API access is configured, no custom models/endpoints
You're using the Vertex AI API to call the Gemini Flash model. This doesn't require infrastructure configuration - it's just API calls. The service account has the necessary permissions.
Your Cloud Run service connects to Cloud SQL using:
- Public IP: 34.82.56.143 (currently configured)
- No VPC Connector: Direct public IP connection
For production, consider:
- Setting up Cloud SQL Proxy
- Using private IP with VPC connector
- Restricting authorized networks
Current configuration:
- Cloud SQL Backups: Enabled (7 days retention, daily at 3 AM)
- Cloud Storage: No lifecycle policies on cloudbuild bucket
- Cloud Run: Stateless, no backup needed
# Plan changes
terraform plan
# Apply changes
terraform apply
# Destroy resources (USE WITH CAUTION!)
terraform destroy# To update the Cloud Run service with a new image:
terraform apply -var="cloud_run_image=gcr.io/sf-beach-app/beach-ratings:v2.0".
├── main.tf # Core infrastructure (Cloud Run, SQL, Storage, IAM)
├── apis.tf # Enabled GCP APIs
├── variables.tf # Input variables
├── outputs.tf # Output values
└── README.md # This file
- Import all existing resources into Terraform state
- Verify the configuration matches your actual infrastructure
- Add missing pieces:
- Database users and databases
- Environment variables for Cloud Run
- Any secrets you need in Secret Manager
- Set up CI/CD to apply Terraform changes automatically
- Consider adding:
- Monitoring alerts
- VPC Connector for private Cloud SQL access
- Secret Manager for sensitive configuration
- Cloud Run service is publicly accessible (allUsers can invoke)
- Cloud SQL has public IP enabled
- Beach images bucket has public read access
- Consider implementing:
- Cloud Armor for DDoS protection
- Identity-Aware Proxy for admin access
- Private Service Connect for Cloud SQL
Current setup uses:
- Cloud SQL: db-f1-micro (free tier eligible)
- Cloud Run: Pay per use
- Cloud Storage: Pay per GB stored
Monitor usage and consider:
- Scaling down Cloud SQL during off-hours
- Setting up budget alerts
- Implementing Cloud Storage lifecycle policies
For questions about this infrastructure:
- Check the GCP Documentation
- Review Terraform Google Provider docs
- Use
gcloudCLI to inspect actual resource configurations