问题
I've got the following code for a an API endpoint that is supposed to trigger a Firestore backup using firebase-admin
.
This is how I'm initializing firebase-admin
;
import * as admin from "firebase-admin";
admin.initializeApp({
credential: admin.credential.cert(
SERVICE_ACCOUNT as admin.ServiceAccount
)});
The service account key is a JSON I've downloaded using the default firebase-admin
service account:
This is the backup.ts
API request handler.
export const backupData: RequestHandler = async (req, res) => {
try {
const PROJECT_ID = process.env.PROJECT_ID;
const client = new admin.firestore.v1.FirestoreAdminClient();
const DB_NAME = client.databasePath(PROJECT_ID, "(default)");
const BUCKET = `gs://${PROJECT_ID}.appspot.com`;
const FOLDER = `firestore-backup`;
const FULL_PATH = `${BUCKET}/${FOLDER}`;
const responses = await client.exportDocuments({
name: DB_NAME,
outputUriPrefix: FULL_PATH,
collectionIds: [] // CAN LIST SPECIFIC COLLECTIONS
});
const response = responses[0];
return res.sendStatus(200);
} else
return res.sendStatus(403);
}
catch(err) {
console.error(err.message || DEFAULT_ERROR_MSG);
return res.sendStatus(500);
}
};
The weird thing is:
It works perfectly on my dev environment. I mean, I run my local server and hit localhost:8080/api/backup
(which is the correct endpoint) and everything works correctly and the backup is triggered.
But after I deploy it to my cloud run
service, it no longer works.
This is the error I'm getting on my cloud run service:
7 PERMISSION_DENIED: The caller does not have permission
Do I need to add more permissions to that service account? But why does it work with that very same service account on my local dev environment? Should I not use a service account when I'm initializing it on my cloud run service? Don't know what to do here.
UPDATE 1:
I've just tried to initialize it like this, but got the same results:
admin.initializeApp({
credential: admin.credential.cert(SERVICE_ACCOUNT),
databaseURL: `https://${PROJECT_ID}.firebaseio.com`,
storageBucket: `${PROJECT_ID}.appspot.com`
});
Also, just followed this doc tutorial and added these roles both to my firebase-admin
and PROJECT_ID@appspot.gserviceaccount.com
. Still not working:
Cloud Datastore Import Export Admin
Storage Admin
UPDATE 2:
Following this doc, I've just tried to initialize the firebase-admin
without any parameters. Still same result:
admin.initializeApp();
UPDATE 3:
Following the previous docs and this doc, I've added the IAM roles of Cloud Datastore Import Export Admin
and Storage Admin
to my PROJECT_NUMBER-compute@developer.gserviceaccount.com
service account. Still same results.
CONCLUSION
It just worked. But I've done so many attempts that I'm not really sure of what made it work. I'm guessing it was what I did on UPDATE 3. Will check that out and answer tomorrow.
回答1:
I can confirm that UPDATE 3
that I described on the question did the trick. Because I've reverted the changes I made on UPDATE 1 and 2
and it's still working fine.
It seems that while on my local environment, firebase-admin
is using the firebase-adminsdk@PROJECT_ID.iam.gserviceaccount.com
service account to call the FirestoreAdminClient
API. That's why it works I guess. Or maybe it's using my gcloud
logged account which is my owner
email. I'm not really sure.
But once you are in Cloud Run environment, even though firebase-admin
is being initialized with that very same service account, it seems that it kind of overrides that and uses the xxxxxxxxx-compute@developer.gserviceaccount.com
. So that's the one that needs the permissions.
I got that idea from Cloud Run Service Identity and Cloud Run IAM roles, that says:
And the roles needed I got from: Firebase DOCS - Scheduled exports:
This is the final config:
来源:https://stackoverflow.com/questions/66032943/trying-to-access-firestoreadminclient-from-cloud-run-service-using-firebase-admi