4
0

More than 1 year has passed since last update.

gcloud auth application-default loginのプロジェクトID無い問題

Last updated at Posted at 2022-01-31

はじめに

小ネタですが「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は、クレデンシャルを下記の順番で探します。

  1. 環境変数 GOOGLE_APPLICATION_CREDENTIALS が指定されていたら、そのファイルを service account の credentials として読んで使う
  2. gcloud auth application-default login を実行して well_known_file が作成済みであれば、それを authorized user の credentials として読んで使う
  3. GAE (Google App Engine) 上で実行されていれば、その built-in service account を使う
  4. 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を指定する方法でローカル開発を進めるのが良さそうです。

4
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
4
0