概要
Cloud Firestoreをサーバーから更新しようとしたんですが、ドキュメントの入り口間違えたのとGCPのIAMに軽く混乱したのでその辺まとめておきます。
読者対象
- 将来的にFunctionsやGCP以外のサーバーからCloud Firestoreを操作しようとしている方。
Road to 解決
半端に理解しているほど質の悪いものはない
クライアントサイドでは浅く利用済み。
書き込みのセキュリティを外していたので、書き込みはサーバーからのみ受け付けるように変更を決意。
公式ドキュメントのデータを保護するの概要を見てみる。
https://firebase.google.com/docs/firestore/security/overview?hl=ja
サーバー クライアント ライブラリの場合は、Cloud Identity and Access Management(IAM)を使用して、データベースへのアクセスを管理します。IAM を使用して Java、Python、Node.js、Go のクライアント ライブラリのデータを保護する方法を説明します。
たったこれだけ・・・
しばらく固まってしまったがどうやら左のツリーから、スタートガイドに行けということを理解する。
スタートガイドにはサーバー的な項目がないと思っていたら、注意書きが…
注: サーバー クライアント ライブラリはすべての Cloud Firestore セキュリティ ルールをバイパスし、代わりに Google アプリケーションのデフォルト認証情報を使って認証を行います。REST API または RPC API 用のサーバー クライアント ライブラリを使用している場合は、Cloud Firestore 用の Cloud Identity and Access Management を設定してください。
デフォルト認証情報のリンク先がGCPの認証の話なのだが、はっきり言ってここにリンクした意味が分からないorz
https://cloud.google.com/docs/authentication/production?hl=ja
つんだのでググってみると、FirebaseAdminSDKで難なく書き込みしている方を散見できた。
ということは、私はどうやら入り口を間違ったとわかり、Firestoreのドキュメントを最初から読んでみることに。
上から2番目のスタートガイドにばっちり書いてますがなorz
https://firebase.google.com/docs/firestore/quickstart?hl=ja
後はすんなりと思ったがGCPの大草原にいきなり放り出される
ドキュメントに従ってFirebase Admin SDKをインストール・・・OK!
以下の手順に従い適切な認証情報を利用して、Cloud Firestoreを初期化します・・・OK!
各自のサーバー(またはその他の Node.js 環境)で Firebase Admin SDK を使用するには、サービス アカウントを使用します。Cloud Platform Console で [IAM と管理] > [サービス アカウント] にアクセスします。新しい秘密鍵を生成し、JSON ファイルを保存します。次に、このファイルを使用して SDK を初期化します。
( ゚Д゚)はぁ?
いきなり投げやりになったのは気のせいだろうか?
「サービスアカウント」の部分はGCPドキュメントへのリンクになっており、どうもアカウント作れよということと理解。
https://cloud.google.com/compute/docs/access/create-enable-service-accounts-for-instances?hl=ja
firebaseが自動で作ったアカウントがいくつか出てくるので、ユニークな名前にしたほうがよさげ。
特にサービスアカウントの説明は、時間がたっても自分が作ったとわかるような説明が望ましいはず。
このアカウントへ権限を付与するが、GCPの中にFirebaseが潜んでいるため結構迷う。
分散しているのか、FirebaseのPrefixでまとまっているのか・・・正解としては、Firebaseの大項目一つにまとめられている。
私は最初「Cloud Filestore」という初見殺しにつかまって、1時間は無駄にしたm9(^Д^)プギャー
最後にオプションとなっているが、キーをもらうために作っているのでここでキーを作成しておく。
JSONファイルがDLされるが、これが漏れると大変なので、発行したなら厳重管理すること。
あとはFirebaseの公式ドキュメントにある通り、そのJSONを読み込んでやればOK。
ただし、権限付与、もしくは変更してすぐに反映された旨のメッセージが表示されるが、実際にFireStoreに書き込みできるようになるには1分程度の遅延があった。
時間がたっても書き込みできない場合は、キーの再作成すれば解消されるはず。
それでも解消されない場合は、権限の見直しを。
おまけ セキュリティルールも勘違いした
すべて許可するでFirestoreを作成するとこうなっている。
私はallow readでreadが無条件に解放されていて、writeは条件を書くと誤って解釈してしまい・・・
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if true;
}
}
}
クライアントからの書き込みはすべて拒否するためif false
に変更
するとクライアントからデータが全く読めない事態にΣ( ̄ロ ̄lll)ガーン
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read, write: if false;
}
}
}
公式ドキュメントのスタートアップの次に個別設定の例が記述されているが、allowは,で区切ったすべてにかかっており、ifもそれらすべての条件に対応する。
つまり、readとwriteの条件が異なるのであれば、別々に記述するのが正解。
以下が読み取り専用で書き込みが一切不可の条件。
service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if true;
allow write: if false;
}
}
}
設定後はシミュレータが用意されているので、少なくともあれで確認したほうがいい。
本番環境ではテストコード作ってしっかり対応すべきだが。
念のため言っとくと、このセキュリティ設定はクライアントSDK(RESTでもいいが)からの書き込みに対応するものでしかない。
AdminSDK(RESTでもいいが)を使った場合には、これらをバイパスするので問題なく書き込める。(IAMで操作権限付与していることが前提)
もし不正な書き込みがあった場合は、以下の可能性があるということになる。
- セキュリティルールを変更する前に書き込まれた。
- セキュリティルールの適用範囲を誤っていた。(matchの部分)
- AdminSDKで別の担当が書き込んでいた。(おいっ)
- AdminSDKで使用する鍵が漏洩した(゚Д゚;)
- クラウドベンダーのバグでGUI操作時に自動的にごみデータが書き込まれた。(Firebaseじゃないけど体験談(;^_^A)
まとめ
中途半端に知っていただけに、遠回りした挙句GCPにもてあそばれた話でした。
GCPとの連携が進んでできることが進んでいくのはいいけど、Firebaseのお手軽感からいきなりGCPに投げ出されるのはつらかった・・・。
一枚ドキュメントはさんだほうがよくないか?で締めようと思ったら、”各自のサーバーで初期化する”場合は面倒で、Functionsからならこんな面倒なことしなくていいのか・・・orz
Functionsからコールせずに愚痴ってすみませんでしてた(ノД`)・゜・。