尝试使用firebase-admin从Cloud Run服务访问FirestoreAdminClient.错误:7 PERMISSION_DENIED:呼叫者没有权限 [英] Trying to access FirestoreAdminClient from Cloud Run service using firebase-admin. ERROR: 7 PERMISSION_DENIED: The caller does not have permission

查看:74
本文介绍了尝试使用firebase-admin从Cloud Run服务访问FirestoreAdminClient.错误:7 PERMISSION_DENIED:呼叫者没有权限的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

对于API端点,我有以下代码,该端点应该使用 firebase-admin 触发Firestore备份.

这是我初始化 firebase-admin ;

的方式

 从"firebase-admin"以管理员身份导入*;admin.initializeApp({凭证:admin.credential.cert(SERVICE_ACCOUNT以admin.ServiceAccount的身份)}); 

服务帐户密钥是我使用默认的 firebase-admin 服务帐户下载的JSON:

这是 backup.ts API请求处理程序.

  export const backupData:RequestHandler =异步(req,res)=>{尝试 {const PROJECT_ID = process.env.PROJECT_ID;const client = new admin.firestore.v1.FirestoreAdminClient();const DB_NAME = client.databasePath(PROJECT_ID,``(默认)'');const BUCKET =`gs://$ {PROJECT_ID} .appspot.com`;const FOLDER =`firestore-backup`;const FULL_PATH =`$ {BUCKET}/$ {FOLDER}`;const响应=等待client.exportDocuments({名称:DB_NAME,outputUriPrefix:FULL_PATH,collectionIds:[]//可以列出特定的集合});const response =响应[0];返回res.sendStatus(200);} 别的返回res.sendStatus(403);}catch(err){console.error(err.message || DEFAULT_ERROR_MSG);返回res.sendStatus(500);}}; 

奇怪的是:

它可以在我的开发环境中完美运行.我的意思是,我运行本地服务器并点击 localhost:8080/api/backup (这是正确的端点),并且一切正常,并且备份被触发.

但是在将其部署到我的 cloud run 服务后,它不再起作用.

这是我在云运行服务上遇到的错误:

7 PERMISSION_DENIED:呼叫者没有权限

我需要为该服务帐户添加更多权限吗?但是,为什么它可以在我的本地开发环境中使用相同的服务帐户呢?在云运行服务上初始化服务帐户时,是否应该不使用服务帐户?不知道该怎么办.


更新1:

我只是试图像这样初始化它,但是得到了相同的结果:

  admin.initializeApp({凭证:admin.credential.cert(SERVICE_ACCOUNT),databaseURL:`https://$ {PROJECT_ID} .firebaseio.com`,storageBucket:`$ {PROJECT_ID} .appspot.com`}); 

此外,只需遵循

我从以下位置获得了所需的角色:

这是最终的配置:

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.

解决方案

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:

这篇关于尝试使用firebase-admin从Cloud Run服务访问FirestoreAdminClient.错误:7 PERMISSION_DENIED:呼叫者没有权限的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆