サービスアカウントの資格情報をダウンロードせずに、Google ComputeEngineからローカルでGoogleAPI(Google Drive API)を認証するにはどうすればよいですか?
当社は、Google CloudPlatformのGoogleSheets(Googleドライブ内)からのデータの処理に取り組んでおり、認証に問題があります。
GoogleドライブへのAPI呼び出しを行うコードを実行する必要がある場所は、Google Compute Engineの本番環境内と、開発環境内、つまり開発者のラップトップ上でローカルに2つあります。
当社は資格情報について非常に厳格であり、サービスアカウントの資格情報JSONキーのダウンロードを許可していません(これはより良い方法であり、より高いセキュリティを提供します)。GCPのすべてのドキュメントは、サービスアカウントのJSONキーをダウンロードして使用するように言っているようです。または、Google API / Developersのドキュメントでは、OAuth2クライアントIDを作成し、ここのようにそのキーをダウンロードすると述べています。
彼らはしばしばこのようなコードを使用します:
from google.oauth2 import service_account
SCOPES = ['https://www.googleapis.com/auth/sqlservice.admin']
SERVICE_ACCOUNT_FILE = '/path/to/service.json'
credentials = service_account.Credentials.from_service_account_file(
SERVICE_ACCOUNT_FILE, scopes=SCOPES)
ただし、サービスアカウントのJSONキーをダウンロードできない(またはダウンロードしたくない)ため、ドキュメントに従うだけでは行き詰まります。
Google Compute Engine環境では、GCPアプリケーションのデフォルト認証情報(ADC)を使用して認証できます。つまり、コードで使用する認証情報を明示的に指定せず、クライアントライブラリを「正常に機能させる」ことができます。これは、次のことを保証する限り、うまく機能します。 VMは正しいスコープhttps://www.googleapis.com/auth/drive
で作成され、デフォルトのCompute Serviceアカウントのメールには、アクセスする必要のあるシートへのアクセス許可が付与されます。これについては、こちらのドキュメントで説明されています。あなたはそのようにこれを行うことができます。
from googleapiclient.discovery import build
service = build('sheets', 'v4')
SPREADSHEET_ID="<sheet_id>"
RANGE_NAME="A1:A2"
s = service.spreadsheets().values().get(
spreadsheetId=SPREADSHEET_ID,
range=RANGE_NAME, majorDimension="COLUMNS"
).execute()
しかし、これを開発のために、つまり開発者のラップトップでローカルに行うにはどうすればよいでしょうか。繰り返しますが、JSONキーをダウンロードせずに、できれば可能な限り「正しく機能する」アプローチを使用しますか?
通常gcloud auth application-default login
、Googleストレージなど、Googleクライアントライブラリが使用する「正常に機能する」デフォルトのアプリケーション認証情報を作成するために使用します。ただし、これはGCP以外のGoogle APIでは機能しません。たとえば、service = build('sheets', 'v4')
「リクエストの認証スコープが不十分でした」というエラーで失敗するGoogleドライブAPIなどです。次に、次のようなあらゆる種類のソリューションを試しました。
credentials, project_id = google.auth.default(scopes=["https://www.googleapis.com/auth/drive"])
そして
credentials, project_id = google.auth.default()
credentials = google_auth_oauthlib.get_user_credentials(
["https://www.googleapis.com/auth/drive"], credentials._client_id, credentials._client_secret)
)
など...これらはすべて、GoogleドライブAPIへの認証を実行しようとしたときに回避できない無数のエラー/問題をもたらします:(
何かご意見は?
回答
開発環境からの認証を簡単にする1つの方法は、サービスアカウントの偽装を使用することです。
これは、サービスアカウントの偽装の使用に関するブログであり、これを行うことの利点も含まれています。@johnhanley(ブログ投稿を書いた)は素晴らしい人で、SOについても非常に有益な回答がたくさんあります!
ローカルマシンでGoogleドライブAPIを認証できるようにするには、サービスアカウントを偽装するデフォルトのアプリケーション認証情報をローカルマシンで作成し、アクセスするAPIに必要なスコープを適用する必要があります。
サービスアカウントになりすますことができるようにするには、ユーザーにロールが必要roles/iam.serviceAccountTokenCreator
です。この役割は、プロジェクト全体または個々のサービスアカウントに適用できます。
gcloudこれを行うには、を使用できます。
gcloud iam service-accounts add-iam-policy-binding [COMPUTE_SERVICE_ACCOUNT_FULL_EMAIL] \
--member user:[USER_EMAIL] \
--role roles/iam.serviceAccountTokenCreator
これが完了したら、ローカル資格情報を作成します。
gcloud auth application-default login \
--scopes=https://www.googleapis.com/auth/drive,https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/cloud-platform,https://www.googleapis.com/auth/accounts.reauth \
--impersonate-service-account=[COMPUTE_SERVICE_ACCOUNT_FULL_EMAIL]
これにより、発生したスコープエラーが解決されます。Drive APIスコープ以外に追加された3つの追加スコープは、gcloud auth application-default login
適用され、必要とされるデフォルトのスコープです。
偽装せずにスコープを適用すると、認証しようとしたときに次のようなエラーが発生します。
HttpError: <HttpError 403 when requesting https://sheets.googleapis.com/v4/spreadsheets?fields=spreadsheetId&alt=json returned "Your application has authenticated using end user credentials from the Google Cloud SDK or Google Cloud Shell which are not supported by the sheets.googleapis.com. We recommend configuring the billing/quota_project setting in gcloud or using a service account through the auth/impersonate_service_account setting. For more information about service accounts and how to use them in your application, see https://cloud.google.com/docs/authentication/.">
認証情報を設定すると、ローカルマシンのGoogle ComputeEngineで実行されるのと同じコードを使用できます:)
注:すべてのgcloudコマンドに偽装を設定することもできます。
gcloud config set auth/impersonate_service_account [COMPUTE_SERVICE_ACCOUNT_FULL_EMAIL]
サービスアカウントになりすましてローカルマシンにデフォルトのアプリケーション資格情報を作成することは、開発コードを認証する巧妙な方法です。これは、コードが偽装しているサービスアカウントとまったく同じ権限を持つことを意味します。これが本番環境でコードを実行するのと同じサービスアカウントである場合、開発中のコードは本番環境と同じように実行されることがわかります。また、サービスアカウントキーを作成またはダウンロードする必要がないことも意味します。