0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Cloud FunctionsにSecretを環境変数として渡したが、デプロイ時に環境変数がなぜか取得できずデプロイエラーとなった件の解決

Last updated at Posted at 2022-02-18

前提

  • Cloud Functions(Node.js) + Express.js + TypeScript
  • 異なるプロジェクトのFirestoreにアクセスする必要がある
  • Service Account Keyのclient_email, private_keyを用いてinitializeApp()する
  • Secret Managerにclient_email, private_keyを保存
  • Cloud FunctionsにSecretを環境変数として渡している

最初作った構成

下記のソースだと、firebase deploy --only functions時にエラーを吐いた
client_emailをハードコードすると、private_keyで同様のエラー。
private_keyもハードコードするとうまく動いた。

Error: Error occurred while parsing your function triggers.
Error: Service account object must contain a string "client_email" property.

index.ts

Express.jsを用いてAPIを作成
ルーティングを行う

import * as functions from "firebase-functions";
import express from "express";
import create from "./create";

const app = express();
app.post("/create", create);

export const api = functions
  .region("asia-northeast1")
  .https
  .onRequest(app);

create.ts

import {primaryFirebase, secondaryFirebase} from "./firebaseInitialize";

const primaryFirestore = primaryFirebase.firestore();
const secondaryFirestore = secondaryFirebase.firestore();

const create = async (req, res) => {
  const doc = await primaryFirestore.
    .collection("collectionName")
    .add({
      key: "value",
    });

  await secondaryFirestore
    .collection("collectionName")
    .doc(doc.id) // primary and secondary are same id
    .set({
      key: "value",
    });

  res.send("OK");
};

export default create;

firebaseInitialize.ts

process.env.CLIENT_EMAILが、直前のlogには出力されているのに、certにわたすService Account ObjectのclientEmailは文字列になっていないらしい。なぜ…?

import admin from "firebase-admin";
import * as functions from "firebase-functions";

functions.logger.log("env: ", process.env); // ちゃんとログに出力されているのに……

export const primaryFirebase = admin.initializeApp();
export const secondaryFirebase = admin.initializeApp(
  {
    credential: admin.credential.cert({
      projectId: process.env.PROJECT_ID,
      clientEmail: process.env.CLIENT_EMAIL,
      privateKey: process.env.PRIVATE_KEY,
    }),
  },
  "secondary",
);

対策

ハードコードすると動くが、環境変数だと動かない。
Secret Manager経由で環境変数を渡す場合は、デプロイ時には環境変数は空のまま解釈されるとか…?
なぜだかわからないが、process.env.CLIENT_EMAIL, process.env.PRIVATE_KEYの読み込みを遅らせてみた。

create.ts

dynamic importを使って解釈のタイミングをズラしてみたら、うまくデプロイされた。
APIもうまく動いている。

const create = async (req, res) => {
  const {primaryFirebase, secondaryFirebase} = await import("./firebaseInitialize");

  const doc = await primaryFirebase.
    .firestore()
    .collection("collectionName")
    .add({
      key: "value",
    });

  await secondaryFirebase
    .firestore()
    .collection("collectionName")
    .doc(doc.id) // primary and secondary are same id
    .set({
      key: "value",
    });

  res.send("OK");
};

export default create;

なぜ最初のソースだとうまくいかなかったのか、、、分かる方ぜひご教授ください

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?