3
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?

この記事誰得? 私しか得しないニッチな技術で記事投稿!

VercelにFirebaseのサービスアカウントJsonファイルをアップロードできない問題対応

Last updated at Posted at 2023-07-17

はじめに

NuxtやNextJsでFirebase Adminを利用したアプリを作成し、Vercel上で実行しようとした。

ところがVercelにはファイルをアップロードする手段がない、一般的なFirebaseの認証方法である、サービスアカウントのJsonファイル利用した認証が利用できなかった。

漏洩リスクなどを考慮したところ、こちらのサイトの暗号化して環境変数に設定するの手順が良さそうだったので、こちらの方法の実装パターンを試してみた。

実装

1. サービスアカウントJsonの暗号化

はじめにFirebaseコンソール画面の「プロジェクトの設定>サービスアカウント>新しい秘密鍵の生成」より、秘密鍵を生成する。

image.png

暗号化にはopensslコマンドを利用する。先ほどダウンロードしたJsonファイルの名称をservice-account-key.jsonとして、暗号化を下記のコマンドで実施する。

$ openssl enc -aes-256-cbc -a -in service-account-key.json -out encrypted.txt -k passphrase -p

salt=xxxxxxxxxxxxxxxx
key=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
iv=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

その後、出力された key と iv、 encrypted.txtの内容を、それぞれ .env に設定、またはVercelに環境変数として設定する。

.env
DECRYPT_KEY=${keyの値}
DECRYPT_IV=${ivの値}
ENCRYPTED_KEY=${encrypted.txtの中身}

2. 復号処理

opensslコマンドで暗号化した各種情報を利用し、サービスアカウントキーを復号化する処理を作成する。

decrypt.ts
import * as crypto from "crypto";
import * as fs from "fs";

/**
 * 暗号化キーを複合化する処理
 */
export function decryptGCPServiceAccount() {
  const algorithm = "aes-256-cbc";
  // 環境変数から読み込む
  const key = process.env.DECRYPT_KEY!;
  const iv = process.env.DECRYPT_IV!;
  const source = process.env.ENCRYPTED_KEY!;

  const decipher = crypto.createDecipheriv(
    algorithm,
    Buffer.from(key, "hex"),
    Buffer.from(iv, "hex")
  );
  const data = Buffer.from(source, "base64").slice(16);
  const start = decipher.update(data);
  const final = decipher.final();
  const result = Buffer.concat([start, final]).toString("utf8");

  // 複合化されたサービスアカウントのJson
  return JSON.parse(result);
}

3. Firebase Adminの認証処理

2で実装した復号化処理を用いてfirebase-adminの認証を行う。

Fire StoreとFire Storageを利用する場合の例を下記に示す。

firebase.ts
import { initializeApp, cert } from "firebase-admin/app";
import { getFirestore } from "firebase-admin/firestore";
import { getStorage } from "firebase-admin/storage";
import { decryptGCPServiceAccount } from "./decrypt";

// ServiceAccountKeyを複合化する
const serviceAccountJson = decryptGCPServiceAccount();

const app = initializeApp({
  // 文字列をJson形式に変換し初期化する。
  credential: cert(serviceAccountJson),
  // FireStorageのバケット名
  storageBucket: "${FIRE_STORAGE_BUCKET_NAME}",
});

// FireStoreとFriestoreStoregeのバケットを取得する。
export const firestore = getFirestore(app);
export const bucket = getStorage(app).bucket();

参考

  • メールアドレスとパスワード認証は、現在のバージョンでは利用できない様子

  • 最新の記事からもJsonの値をそのまま環境変数に設定する方法しかなさそう。

  • 暗号化した値を貼り付けるこちらのパターンを採用

3
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
3
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?