GCPのサービスアカウント経由でGoogle Driveにアクセスする
GASを使わず、自前のサーバーなどから直接Google APIを叩くorライブラリ経由でAPIアクセスする場合に、サービスアカウント+OAuth2認証で実行する方式の全体像を確認してみた。
# 全体像
関わっているプロジェクトがReact Router v7なので、RR7のaction()からGoogle Drive APIを直接叩く形の図。
https://scrapbox.io/files/67ea8b2de01ebd3c6e7e2640.png
【メリット】
コードが全てgit上に集約されているので、管理しやすい
【デメリット】
アップロード先フォルダに対しての読み取り・書き込み権限のあるサービスアカウントの秘密鍵がサーバー上やローカルに保存された状態
既存のGoogle Drive APIには「Uploadのみの権限」というのは存在しないため、読み取りもできてしまう
つまり、鍵情報の漏洩時にアップロード済みファイルが読み取られてしまうため、ファイルの内容によってはリスク高
GCPの設定が発生する
これはどの方式でも同じだが、サービスアカウントの設定有無が一番の差
# サンプルコード
code:ts
import { google } from "googleapis"
import { GoogleAuth } from "google-auth-library"
import { Readable } from "node:stream"
export const action = async ({ request }: Route.ActionArgs) => {
const formData = await request.formData()
const file = formData.get("file") as File
// サービスアカウントの鍵(サービスアカウントキー)をここで渡す
const credentials = process.env.VITE_SERVICE_ACCOUNT_KEY
const auth = new GoogleAuth({
credentials: credentials,
})
const blob = new Blob(file, { type: file.type }) const reader = blob.stream().getReader()
const out = new Readable()
reader.read().then(async ({ done, value }) => {
while (!done) {
out.push(value)
;({ done, value } = await reader.read())
}
out.push(null)
})
// ファイルの格納先フォルダのID(ブラウザ表示した際のURLから取得可)
const parentId = process.env.VITE_PARENT_FOLDER_ID
const drive = google.drive({ version: "v3", auth })
const response = await drive.files.create({
requestBody: {
name: file.name,
},
media: {
mimeType: file.type,
body: out,
},
})
return
}