はじめに
小ネタですが「gcloud auth application-default login
で生成したクレデンシャルにプロジェクトIDが無い問題」に対処する方法をまとめました。
gcloud auth application-default login
手元の環境から直接GCP(Google Cloud)上のサービスに繋ぎ込む際のクレデンシャルとして、サービスアカウントキーをコンソールからダウンロードする方法もありますが、セキュリティ上あまりオススメしません。管理もタイヘンです。
gcloud auth application-default login
を実行し、生成されたapplication_default_credentials.json
をクレデンシャルとして使うのが多いかなと思います。
ざっくりとしたフローとしては、コマンドを叩くとブラウザが立ち上がり、Googleアカウントでの認証を求められ、認証通過後、OAuthの仕組みでアクセストークンが発行される流れです。
User Account を使って Server Application が使うためのアクセストークンを取得する方法です。
ターミナル上で gcloud auth application-default login を実行することで行われます。
生成されたトークンは、
- Windowsの場合
%APPDATA%/gcloud/application_default_credentials.json
- macOS等の場合
$HOME/.config/gcloud/application_default_credentials.json
に配置されます。
Google CloudのSDKは、クレデンシャルを下記の順番で探します。
- 環境変数 GOOGLE_APPLICATION_CREDENTIALS が指定されていたら、そのファイルを service account の credentials として読んで使う
- gcloud auth application-default login を実行して well_known_file が作成済みであれば、それを authorized user の credentials として読んで使う
- GAE (Google App Engine) 上で実行されていれば、その built-in service account を使う
- GCE (Google Compute Engine) 上で実行されていれば、その build-in service account を使う ここまで該当がなければエラーとする
※well_known_fileは前述のapplication_default_credentials.jsonのこと
上記の「2」がgcloud auth application-default login
で発行したトークンに該当します。
つまり、gcloud auth application-default login
で生成されたクレデンシャルは、コード中で明示的に読み込まなくてもSDKが自動で見つけてくれます。
プロジェクトIDがない問題
ここまでは極めて一般的な話でした。ただし、この方法にも弱点があります。
生成されたapplication_default_credentials.json
にはproject_id
がありません。
❯ cat ~/.config/gcloud/application_default_credentials.json
{
"client_id": "...",
"client_secret": "...",
"quota_project_id": "...",
"refresh_token": "...",
"type": "authorized_user"
}
この状態でGCPのサービス、例えばFirestoreを呼び出してみます。
app, err := firebase.NewApp(ctx, nil)
if err != nil {
log.Fatal(err)
}
client, err := app.Firestore(ctx)
if err != nil {
log.Fatal(err)
}
iter := client.Collection("Foo").Documents(ctx)
snaps, err := iter.GetAll()
if err != nil {
log.Fatal(err)
}
プロジェクトIDの指定がない!と怒られます。
project id is required to access Firestore
解消する方法は主に3つあります。
まず1つ目はコード中でプロジェクトIDを明示的に与える方法です。
conf := &firebase.Config{ProjectID: "my-project"}
app, err := firebase.NewApp(ctx, conf)
2つ目(非推奨。クレデンシャルは弄るべきでない)がapplication_default_credentials.json
を直接編集するなりしてproject_id
を追加する方法です。
❯ vi ~/.config/gcloud/application_default_credentials.json
{
"client_id": "...",
"client_secret": "...",
"quota_project_id": "my-project",
"project_id": "my-project",
"refresh_token": "...",
"type": "authorized_user"
}
3つ目は、これが最も推奨なのですが、GOOGLE_CLOUD_PROJECT
環境変数にプロジェクトIDを設定する方法です。
これにより、SDKが対象とするプロジェクトIDとして自動で読み込んでくれます。
export GOOGLE_CLOUD_PROJECT="my-project"
おわりに
gcloud auth application-default login
を使いつつ、GOOGLE_CLOUD_PROJECT
環境変数にプロジェクトIDを指定する方法でローカル開発を進めるのが良さそうです。