Skip to main content
Glama
northernvariables

FedMCP - Federal Parliamentary Information

main.tf8.5 kB
/** * CanadaGPT - Google Cloud Platform Infrastructure * * This Terraform configuration provisions all GCP resources for CanadaGPT: * - VPC networking with Serverless VPC Access Connector * - Cloud NAT for outbound traffic * - Service Accounts with IAM permissions * - Secret Manager for credentials * - Artifact Registry for Docker images * - Cloud Run services (frontend, API) * - Cloud Run Jobs (data pipeline) * - Cloud Scheduler (nightly sync) * * Prerequisites: * 1. GCP project created * 2. Billing enabled * 3. gcloud CLI authenticated: gcloud auth application-default login * 4. APIs enabled (see README.md) */ terraform { required_version = ">= 1.6" required_providers { google = { source = "hashicorp/google" version = "~> 5.10" } } # Optional: Use GCS backend for state management (recommended for production) # backend "gcs" { # bucket = "canadagpt-terraform-state" # prefix = "terraform/state" # } } provider "google" { project = var.project_id region = var.region } # Enable required APIs resource "google_project_service" "required_apis" { for_each = toset([ "run.googleapis.com", # Cloud Run "vpcaccess.googleapis.com", # Serverless VPC Access "compute.googleapis.com", # Compute Engine (for NAT, VPC) "artifactregistry.googleapis.com", # Artifact Registry "secretmanager.googleapis.com", # Secret Manager "cloudbuild.googleapis.com", # Cloud Build "cloudscheduler.googleapis.com", # Cloud Scheduler "logging.googleapis.com", # Cloud Logging "monitoring.googleapis.com", # Cloud Monitoring ]) service = each.key disable_on_destroy = false } # ============================================ # VPC Network # ============================================ resource "google_compute_network" "canadagpt_vpc" { name = "canadagpt-vpc" auto_create_subnetworks = false depends_on = [google_project_service.required_apis] } # Subnet for VPC Connector (required for Cloud Run to access VPC) resource "google_compute_subnetwork" "vpc_connector_subnet" { name = "canadagpt-connector-subnet" ip_cidr_range = "10.8.0.0/28" # /28 is required for VPC Connector region = var.region network = google_compute_network.canadagpt_vpc.id private_ip_google_access = true } # Serverless VPC Access Connector # Required for Cloud Run services to connect to Neo4j via Private Service Connect resource "google_vpc_access_connector" "canadagpt_connector" { name = "canadagpt-vpc-connector" region = var.region network = google_compute_network.canadagpt_vpc.name ip_cidr_range = "10.8.0.0/28" min_instances = 2 max_instances = 3 machine_type = "e2-micro" depends_on = [ google_compute_subnetwork.vpc_connector_subnet, google_project_service.required_apis ] } # Cloud Router (required for Cloud NAT) resource "google_compute_router" "canadagpt_router" { name = "canadagpt-router" region = var.region network = google_compute_network.canadagpt_vpc.id } # Cloud NAT # Provides outbound internet access for Cloud Run services (for government API calls) resource "google_compute_router_nat" "canadagpt_nat" { name = "canadagpt-nat" router = google_compute_router.canadagpt_router.name region = var.region nat_ip_allocate_option = "AUTO_ONLY" source_subnetwork_ip_ranges_to_nat = "ALL_SUBNETWORKS_ALL_IP_RANGES" log_config { enable = true filter = "ERRORS_ONLY" } } # ============================================ # Service Accounts # ============================================ # Frontend Service Account resource "google_service_account" "frontend_sa" { account_id = "canadagpt-frontend" display_name = "CanadaGPT Frontend Service Account" description = "Service account for Next.js frontend Cloud Run service" } # API Service Account resource "google_service_account" "api_sa" { account_id = "canadagpt-api" display_name = "CanadaGPT API Service Account" description = "Service account for GraphQL API Cloud Run service" } # Data Pipeline Service Account resource "google_service_account" "pipeline_sa" { account_id = "canadagpt-pipeline" display_name = "CanadaGPT Data Pipeline Service Account" description = "Service account for data pipeline Cloud Run Job" } # ============================================ # Secret Manager # ============================================ # Neo4j Password resource "google_secret_manager_secret" "neo4j_password" { secret_id = "neo4j-password" replication { auto {} } depends_on = [google_project_service.required_apis] } # CanLII API Key (optional - user provides) resource "google_secret_manager_secret" "canlii_api_key" { secret_id = "canlii-api-key" replication { auto {} } depends_on = [google_project_service.required_apis] } # IAM bindings for secrets # API service account needs access to Neo4j password resource "google_secret_manager_secret_iam_member" "api_neo4j_access" { secret_id = google_secret_manager_secret.neo4j_password.secret_id role = "roles/secretmanager.secretAccessor" member = "serviceAccount:${google_service_account.api_sa.email}" } # Pipeline service account needs access to both secrets resource "google_secret_manager_secret_iam_member" "pipeline_neo4j_access" { secret_id = google_secret_manager_secret.neo4j_password.secret_id role = "roles/secretmanager.secretAccessor" member = "serviceAccount:${google_service_account.pipeline_sa.email}" } resource "google_secret_manager_secret_iam_member" "pipeline_canlii_access" { secret_id = google_secret_manager_secret.canlii_api_key.secret_id role = "roles/secretmanager.secretAccessor" member = "serviceAccount:${google_service_account.pipeline_sa.email}" } # ============================================ # Artifact Registry # ============================================ resource "google_artifact_registry_repository" "canadagpt_repo" { location = var.region repository_id = "canadagpt" description = "Docker images for CanadaGPT services" format = "DOCKER" depends_on = [google_project_service.required_apis] } # Grant service accounts access to pull images resource "google_artifact_registry_repository_iam_member" "frontend_pull" { location = google_artifact_registry_repository.canadagpt_repo.location repository = google_artifact_registry_repository.canadagpt_repo.name role = "roles/artifactregistry.reader" member = "serviceAccount:${google_service_account.frontend_sa.email}" } resource "google_artifact_registry_repository_iam_member" "api_pull" { location = google_artifact_registry_repository.canadagpt_repo.location repository = google_artifact_registry_repository.canadagpt_repo.name role = "roles/artifactregistry.reader" member = "serviceAccount:${google_service_account.api_sa.email}" } resource "google_artifact_registry_repository_iam_member" "pipeline_pull" { location = google_artifact_registry_repository.canadagpt_repo.location repository = google_artifact_registry_repository.canadagpt_repo.name role = "roles/artifactregistry.reader" member = "serviceAccount:${google_service_account.pipeline_sa.email}" } # ============================================ # Outputs # ============================================ output "project_id" { description = "GCP Project ID" value = var.project_id } output "region" { description = "GCP Region" value = var.region } output "vpc_connector_id" { description = "VPC Connector ID (use in Cloud Run services)" value = google_vpc_access_connector.canadagpt_connector.id } output "artifact_registry_url" { description = "Artifact Registry repository URL" value = "${var.region}-docker.pkg.dev/${var.project_id}/${google_artifact_registry_repository.canadagpt_repo.repository_id}" } output "service_accounts" { description = "Service account emails" value = { frontend = google_service_account.frontend_sa.email api = google_service_account.api_sa.email pipeline = google_service_account.pipeline_sa.email } } output "secrets" { description = "Secret Manager secret names" value = { neo4j_password = google_secret_manager_secret.neo4j_password.secret_id canlii_api_key = google_secret_manager_secret.canlii_api_key.secret_id } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/northernvariables/FedMCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server