前提
GCP内に作成されたProjectAとProjectBという2つのプロジェクトが登場します。
Cloud Firestoreへのアクセスは、ProjectAに「Firebase Admin SDK Service Agent」というサービスアカウントを作成し、ProjectBからもこのサービスアカウントを使用してFirestoreにアクセスします。
今回のサービスでは、Go言語で作成したAPIをApp Engineにデプロイした例を用いていますが、Cloud Functionsやその他のリソースを使用していても問題ないと思います。ざっくりとした構成図は下記のとおりです。
発生した現象
ProjectA内に作成されたFirestore内のデータにProjectBからアクセスしようとすると、rpc error: code = PermissionDenied desc = Missing or insufficient permissions.
というエラーが表示され、データを参照することができません。
考えられる原因と試したこと
①セキュリティルールをオープンアクセスに設定する。
Firestoreのセキュリティルールを全てのユーザーが読み取りと書き込みをできるアクセス権を付与しました。
Firestore関連でPermissionDeniedと検索するとこちらの解決方法が多くヒットしますが、この方法では解決しませんでした。
そもそもサーバーサイドからAdmin権限でアクセスしているため、セキュリティールールは無視されるので、セキュリティルールが原因ではないことはすぐにわかることでしたが、ここに数時間も時間をかけてしまいました。
// Allow read/write access to all users under any conditions
// Warning: **NEVER** use this rule set in production; it allows
// anyone to overwrite your entire database.
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
②ProjectBでも同様のサービスアカウントを作成する
こちらの方法は実現不可能でした。
理由はProjectBにはFirestoreが存在しないので物理的に作成することができません。
原因
①、②から原因はセキュリティルールではなく、ProjectBのApp EngineからProjectAのFirestoreにアクセスする際に使用しているサービスアカウントの権限が不足していることが原因ではないかとの予測が立ちました。
結論を述べるとこちらの予測は当たっていって、ProjectBのサービスアカウントに必要な権限を与えたところ無事アクセスできるようになりました。
解決方法については下記で説明します。
解決方法
解決方法から説明すると、ProjectAに作成した「Firebase Admin SDK Service Agent」というサービスアカウントに、ProjectBで使用しているサービスアカウントのアクセスを許可するという方法です。
ProjectBではApp Engineを使用しているため、デフォルトで作成されるProjectB@appspot.gserviceaccount.com
というサービスアカウントを使用して通信を行っています。
上記の作業を行うことでプロジェクトをまたいで、Firestore内のデータにアクセスできるようになります。
具体的な手順は、ProjectAの管理コンソールのメニューからIAMと管理 > サービスアカウント
と進むと下記のような画面が開き、アクセスと許可
というボタンをクリックすると、右側に「新しいメンバー」を追加するフォームが表示されます。
このフォームにProjectBのApp Engineで使用しているサービスアカウント(デフォルトではProjectB@appspot.gserviceaccount.com
)を指定すると、ProjectAに設置されたFirestoreへのアクセス権が付与されるようになります。
まとめ
今回はかなり初歩的な設定ミスにより、エラーの解決までかなり時間を要してしまいました。
Firestoreはエラーメッセージから具体的な原因を特定しにくいのがネックではありますが、この記事が一人でも多くの方の参考になれると幸いです。
今後は初心に戻り、再度IAM周りについて勉強し直してみます。
参照
セキュリティルール
https://firebase.google.com/docs/firestore/security/insecure-rules#open_access
Firebase - Admin SDK
https://firebase.google.com/docs/admin/setup