Firebase-GCP relationship, IAM, monitoring, secrets, and GCP services.
- Firebase and GCP
- Service Accounts
- IAM Roles
- Secret Manager
- Cloud Logging
- Cloud Monitoring
- BigQuery Export
- Other GCP Services
Firebase projects are GCP projects with Firebase services enabled.
Shared resources:
- Project ID
- Billing account
- IAM permissions
- Service accounts
- APIs and services
- Cloud Console access
Access:
- Firebase Console: console.firebase.google.com
- GCP Console: console.cloud.google.com
- Same project, different views
| Service Account | Purpose |
|---|---|
PROJECT_ID@appspot.gserviceaccount.com |
App Engine, Cloud Functions default |
firebase-adminsdk-xxxxx@PROJECT_ID.iam.gserviceaccount.com |
Admin SDK operations |
PROJECT_NUMBER@cloudbuild.gserviceaccount.com |
Cloud Build |
PROJECT_NUMBER-compute@developer.gserviceaccount.com |
Compute Engine default |
# Create
gcloud iam service-accounts create my-service-account \
--display-name="My Service Account" \
--project=PROJECT_ID
# Grant roles
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="serviceAccount:my-service-account@PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/datastore.user"
# Create key (for local development)
gcloud iam service-accounts keys create key.json \
--iam-account=my-service-account@PROJECT_ID.iam.gserviceaccount.com// Local development with key file
import { initializeApp, cert } from "firebase-admin/app";
const serviceAccount = require("./key.json");
initializeApp({
credential: cert(serviceAccount)
});
// In Cloud Functions (automatic)
initializeApp(); // Uses default credentials# Local development
import firebase_admin
from firebase_admin import credentials
cred = credentials.Certificate("key.json")
firebase_admin.initialize_app(cred)
# In Cloud Functions (automatic)
firebase_admin.initialize_app()# Set for local development
export GOOGLE_APPLICATION_CREDENTIALS="/path/to/key.json"
# Or use gcloud
gcloud auth application-default login| Role | Description |
|---|---|
roles/firebase.admin |
Full Firebase access |
roles/firebase.viewer |
Read-only Firebase access |
roles/firebase.developAdmin |
Deploy and develop |
roles/firebase.analyticsViewer |
View Analytics |
roles/firebase.growthViewer |
View A/B Testing, Remote Config |
roles/firebase.qualityViewer |
View Crashlytics, Performance |
| Role | Description |
|---|---|
roles/cloudfunctions.admin |
Full functions access |
roles/cloudfunctions.developer |
Deploy and update |
roles/cloudfunctions.invoker |
Invoke HTTP functions |
roles/cloudfunctions.viewer |
View only |
| Role | Description |
|---|---|
roles/datastore.owner |
Full Firestore access |
roles/datastore.user |
Read/write data |
roles/datastore.viewer |
Read-only |
roles/datastore.indexAdmin |
Manage indexes |
| Role | Description |
|---|---|
roles/storage.admin |
Full Storage access |
roles/storage.objectAdmin |
Manage objects |
roles/storage.objectCreator |
Create objects |
roles/storage.objectViewer |
View objects |
# To user
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="user:email@example.com" \
--role="roles/firebase.admin"
# To service account
gcloud projects add-iam-policy-binding PROJECT_ID \
--member="serviceAccount:sa@PROJECT_ID.iam.gserviceaccount.com" \
--role="roles/datastore.user"
# View current bindings
gcloud projects get-iam-policy PROJECT_ID# Set secret
firebase functions:secrets:set API_KEY
# Get metadata
firebase functions:secrets:get API_KEY
# Access value
firebase functions:secrets:access API_KEY
# List all
firebase functions:secrets:list
# Delete
firebase functions:secrets:destroy API_KEY# Create secret
echo -n "secret-value" | gcloud secrets create API_KEY --data-file=-
# Add version
echo -n "new-value" | gcloud secrets versions add API_KEY --data-file=-
# Access latest version
gcloud secrets versions access latest --secret=API_KEY
# List secrets
gcloud secrets list
# Delete
gcloud secrets delete API_KEYimport { defineSecret } from "firebase-functions/params";
import { onRequest } from "firebase-functions/v2/https";
const apiKey = defineSecret("API_KEY");
const dbPassword = defineSecret("DB_PASSWORD");
export const secureEndpoint = onRequest(
{ secrets: [apiKey, dbPassword] },
(req, res) => {
const key = apiKey.value();
const password = dbPassword.value();
res.json({ status: "ok" });
}
);# Grant function's service account access
gcloud secrets add-iam-policy-binding API_KEY \
--member="serviceAccount:PROJECT_ID@appspot.gserviceaccount.com" \
--role="roles/secretmanager.secretAccessor"# Firebase CLI
firebase functions:log
firebase functions:log --only myFunction
firebase functions:log -n 100
# gcloud
gcloud logging read "resource.type=cloud_function" --limit=50
gcloud logging read "resource.type=cloud_function AND resource.labels.function_name=myFunction"import { logger } from "firebase-functions";
export const myFunction = onRequest((req, res) => {
// Log levels
logger.debug("Debug info");
logger.info("Info message");
logger.warn("Warning");
logger.error("Error occurred");
// Structured data
logger.info("Request received", {
method: req.method,
path: req.path,
userId: req.headers["x-user-id"]
});
res.send("OK");
});import logging
logging.info("Info message")
logging.warning("Warning")
logging.error("Error", extra={"userId": "123"})Create metrics from log entries in GCP Console:
- Logging > Logs-based Metrics
- Create Metric
- Define filter (e.g.,
severity>=ERROR) - Use in Cloud Monitoring dashboards/alerts
GCP Console: Monitoring > Metrics Explorer
Key metrics for Cloud Functions:
cloudfunctions.googleapis.com/function/execution_countcloudfunctions.googleapis.com/function/execution_timescloudfunctions.googleapis.com/function/active_instancescloudfunctions.googleapis.com/function/user_memory_bytes
Firestore metrics:
firestore.googleapis.com/document/read_countfirestore.googleapis.com/document/write_countfirestore.googleapis.com/document/delete_count
# Create notification channel first
gcloud beta monitoring channels create \
--display-name="Email Alerts" \
--type=email \
--channel-labels=email_address=alerts@example.com
# Create alert policy
gcloud alpha monitoring policies create \
--display-name="High Error Rate" \
--condition-display-name="Error rate > 5%" \
--condition-filter='resource.type="cloud_function" AND metric.type="cloudfunctions.googleapis.com/function/execution_count" AND metric.labels.status!="ok"'import { Monitoring } from "@google-cloud/monitoring";
const monitoring = new Monitoring.MetricServiceClient();
const projectId = process.env.GCLOUD_PROJECT;
async function writeCustomMetric(value: number) {
const dataPoint = {
interval: { endTime: { seconds: Date.now() / 1000 } },
value: { doubleValue: value }
};
const timeSeriesData = {
metric: { type: `custom.googleapis.com/my_metric` },
resource: { type: "global", labels: { project_id: projectId } },
points: [dataPoint]
};
await monitoring.createTimeSeries({
name: `projects/${projectId}`,
timeSeries: [timeSeriesData]
});
}Firebase Console:
- Project Settings > Integrations
- BigQuery > Link
- Select data to export:
- Analytics
- Crashlytics
- Cloud Messaging
- Performance Monitoring
-- Analytics events
SELECT
event_name,
COUNT(*) as event_count,
COUNT(DISTINCT user_pseudo_id) as unique_users
FROM `project_id.analytics_123456789.events_*`
WHERE _TABLE_SUFFIX BETWEEN '20240101' AND '20240131'
GROUP BY event_name
ORDER BY event_count DESC;
-- Crashlytics crashes
SELECT
issue_id,
COUNT(*) as crash_count,
ANY_VALUE(issue_title) as title
FROM `project_id.firebase_crashlytics.package_name_ANDROID`
WHERE event_timestamp >= TIMESTAMP_SUB(CURRENT_TIMESTAMP(), INTERVAL 7 DAY)
GROUP BY issue_id
ORDER BY crash_count DESC;Use Firestore Extension or Cloud Function:
import { onDocumentWritten } from "firebase-functions/v2/firestore";
import { BigQuery } from "@google-cloud/bigquery";
const bigquery = new BigQuery();
export const syncToBigQuery = onDocumentWritten(
"orders/{orderId}",
async (event) => {
const data = event.data?.after.data();
if (!data) return;
await bigquery
.dataset("firebase_sync")
.table("orders")
.insert([{
order_id: event.params.orderId,
...data,
synced_at: new Date().toISOString()
}]);
}
);import { CloudTasksClient } from "@google-cloud/tasks";
const client = new CloudTasksClient();
async function scheduleTask(payload: object, delaySeconds: number) {
const project = process.env.GCLOUD_PROJECT!;
const location = "us-central1";
const queue = "my-queue";
const task = {
httpRequest: {
httpMethod: "POST" as const,
url: `https://${location}-${project}.cloudfunctions.net/processTask`,
body: Buffer.from(JSON.stringify(payload)).toString("base64"),
headers: { "Content-Type": "application/json" }
},
scheduleTime: {
seconds: Math.floor(Date.now() / 1000) + delaySeconds
}
};
await client.createTask({
parent: client.queuePath(project, location, queue),
task
});
}import { PubSub } from "@google-cloud/pubsub";
const pubsub = new PubSub();
// Publish message
async function publishMessage(topicName: string, data: object) {
const topic = pubsub.topic(topicName);
const messageBuffer = Buffer.from(JSON.stringify(data));
await topic.publish(messageBuffer);
}
// Subscribe in Cloud Function
import { onMessagePublished } from "firebase-functions/v2/pubsub";
export const handleMessage = onMessagePublished("my-topic", (event) => {
const data = event.data.message.json;
console.log("Received:", data);
});Managed by Firebase for scheduled functions. View in GCP Console:
- Cloud Scheduler > Jobs
# List scheduled jobs
gcloud scheduler jobs list
# Manually trigger
gcloud scheduler jobs run my-scheduled-functionimport { Storage } from "@google-cloud/storage";
const storage = new Storage();
// Upload file
await storage.bucket("my-bucket").upload("local-file.txt", {
destination: "remote-path/file.txt"
});
// Download file
await storage.bucket("my-bucket")
.file("remote-path/file.txt")
.download({ destination: "local-file.txt" });
// Generate signed URL
const [url] = await storage.bucket("my-bucket")
.file("private-file.txt")
.getSignedUrl({
action: "read",
expires: Date.now() + 15 * 60 * 1000 // 15 minutes
});Connect Cloud Functions to VPC for private resources:
import { onRequest } from "firebase-functions/v2/https";
export const privateNetworkFunction = onRequest(
{
vpcConnector: "my-vpc-connector",
vpcConnectorEgressSettings: "ALL_TRAFFIC"
},
async (req, res) => {
// Can now access private IPs
res.send("Connected to VPC");
}
);# Create VPC connector
gcloud compute networks vpc-access connectors create my-vpc-connector \
--region=us-central1 \
--network=default \
--range=10.8.0.0/28