feat: harden Cloud Run security with Secret Manager, VPC connector, and private backend#32
Conversation
…nd private backend - Secret Manager: move all sensitive env vars (Azure credentials, Gemini key, DB credentials) out of GitHub Secrets and into GCP Secret Manager; Cloud Run reads them at runtime via --set-secrets, so secrets are never exposed in workflow logs or build args. - VPC Connector: add Serverless VPC Access connector (terraform/network.tf) so Cloud Run services can reach Cloud SQL and each other over the private VPC network. - Private backend: set backend Cloud Run ingress to 'internal', blocking all public internet access. Frontend nginx now proxies /api/* to the backend's internal URL (with BACKEND_URL injected as a runtime env var), so the browser never needs a direct connection to the backend. - Terraform IaC: terraform/ directory manages the VPC connector, Secret Manager secrets, Cloud Run service account, and Cloud SQL (importable via import.sh). CI continues to own image builds and Cloud Run deployments. - Data migration script: scripts/migrate_db.sh migrates PostgreSQL data between Cloud SQL instances via Cloud SQL Auth Proxy if the database ever needs to be rebuilt. https://claude.ai/code/session_01SRRzCWrpwgMpdYFurMVn7m
…ITE_API_BASE_URL
GitHub Actions does not interpolate ${{ env.X }} inside the top-level env:
block, so the full SA email could not reference PROJECT_ID there. Replaced
CLOUD_RUN_SA with CLOUD_RUN_SA_NAME and build the email inline in the flags
blocks where expression context is available.
Added a comment explaining VITE_API_BASE_URL=/api — it is the nginx location
prefix, not a full URL, because the browser calls the frontend's own origin
and nginx proxies /api/* to the internal backend.
https://claude.ai/code/session_01SRRzCWrpwgMpdYFurMVn7m
Migration Guide: Moving to Full IaC-managed InfrastructureBefore merging this to What Terraform manages vs what CI still owns
Step 1 — Check that
|
3a55fe4 to
cdb3ddb
Compare
|
@claude review this pr, and check if the step described in this comment #32 (comment) is legit |
|
Claude finished @ChingEnLin's task in 2m 30s —— View job PR Review + Migration Guide ValidationTasks:
PR Code ReviewOverall this is a solid, well-structured security hardening PR. The architecture — public frontend nginx proxy → internal backend via VPC connector → Cloud SQL — is the right pattern for Cloud Run. The code is clean and well-commented. Below are specific findings by file.
|
…README - Add production architecture Mermaid diagram showing Cloud Run services, VPC connector, Secret Manager, Cloud SQL, and external dependencies - Add network security model table (frontend public / backend internal) - Add secret management table listing all Secret Manager secrets - Add IaC ownership table (Terraform vs CI pipeline) - Add CI/CD pipeline Mermaid flowchart showing Workload Identity auth, image build/push, and deploy steps with secret injection - Add Terraform to technology stack table Also remove overly broad github_actions_secret_accessor IAM binding from terraform/iam.tf — the GitHub Actions SA never reads secret values directly; Cloud Run reads them at startup using the Cloud Run SA identity. https://claude.ai/code/session_01SRRzCWrpwgMpdYFurMVn7m
$(cat <<'EOF'
Summary
Secret Manager: All sensitive runtime secrets (Azure credentials, Gemini API key, DB credentials) are removed from GitHub Secrets and moved into GCP Secret Manager. Cloud Run reads them natively at startup via
--set-secrets— they never appear in workflow logs, build args, or env var dumps.VPC Connector: A Serverless VPC Access connector is provisioned by Terraform (
terraform/network.tf), connecting both Cloud Run services to the project's default VPC. This is the foundation for private Cloud SQL access and internal service-to-service routing.Private backend: The backend Cloud Run service now runs with
--ingress=internal— it is completely unreachable from the public internet. The frontend nginx container proxies all/api/*requests to the backend's internal URL (injected at runtime asBACKEND_URL). Browsers call/api/...on the frontend, which routes internally.Terraform IaC (
terraform/): Manages the VPC connector, Secret Manager secret structures, a dedicated Cloud Run service account (least-privilege vs default Compute SA), and Cloud SQL (importable viaterraform/import.sh— no data migration needed for the existing instance). The CI pipeline continues to own image builds and Cloud Run deployments.Data migration script (
scripts/migrate_db.sh): Ready-to-use script to migrate PostgreSQL data between Cloud SQL instances via Cloud SQL Auth Proxy, in case the database ever needs to be rebuilt.Architecture after this PR
Pre-deploy checklist (one-time infrastructure setup)
Before merging to
production, a GCP admin must run Terraform once:Then populate Secret Manager with actual values:
Test plan
/api/healthresponds through the nginx proxyhttps://claude.ai/code/session_01SRRzCWrpwgMpdYFurMVn7m
EOF
)
Generated by Claude Code