PythonでGCPの認証を行う

GCPの認証ってたまにどうやるんだっけ?って忘れてしまうので備忘録として残しておこうと思います。 今回はCloud Pub/Subを例に認証を行います。

今回使用する言語

予備知識

サービスアカウントとユーザーアカウントの認証の仕組みに関しては下記の記事が参考になります。

medium.com

Cloud Pub/Subのlibraryの使い方に関しては下記になります。

googleapis.dev

サービスアカウントを用いて認証

環境変数を用いる

export GOOGLE_APPLICATION_CREDENTIALS="[PATH]"

上記のようにサービスアカウントが含まれるパスを指定してあげるとclient libraryが使えるようになります こちらの方法だとCloud Pub/SubにPublishする際は下記のように扱うことができます。

from google.cloud import pubsub_v1
import os

project_id = os.getenv("PROJECT_ID", "")
topic_id = os.getenv("TOPIC_ID", "")
publisher = pubsub_v1.PublisherClient()
topic_path = publisher.topic_path(project_id, topic_id)
publisher.publish(topic_path, b"Hello World")

ファイルパスを指定して認証

google.oauth2.service_account moduleを使って認証するやり方です。SERVICE_ACCOUNT_FILE_PATH環境変数にファイルのパスを指定している感じです。

from google.cloud import pubsub_v1
from google.oauth2 import service_account
import os
project_id = os.getenv("PROJECT_ID", "")
topic_id = os.getenv("TOPIC_ID", "")
service_account_file_path = os.getenv("SERVICE_ACCOUNT_FILE_PATH", "")
credentials = service_account.Credentials.from_service_account_file(service_account_file_path)
publisher = pubsub_v1.PublisherClient(credentials=credentials)
topic_path = publisher.topic_path(project_id, topic_id)

publisher.publish(topic_path, b"Hello World")

データを直接読み込んで認証

同じように先ほどのgoogle.oauth2.service_account moduleを使います。 Credentialsクラスで定義されているfrom_service_account_infoメソッドを使うことでファイルパスを指定することなくサービスアカウントの情報を直接渡して認証できます。 特にコンテナなど、jsonファイルを中に置きたくない場合に有効なのかなと思います。SERVICE_ACCOUNT_FILE環境変数にサービスアカウントの情報が入ってます。

from google.cloud import pubsub_v1
from google.oauth2 import service_account
import json
import os
project_id = os.getenv("PROJECT_ID", "")
topic_id = os.getenv("TOPIC_ID", "")
service_account_file = os.getenv("SERVICE_ACCOUNT_FILE", "")
credentials = service_account.Credentials.from_service_account_info(json.loads(service_account_file))
publisher = pubsub_v1.PublisherClient(credentials=credentials)
topic_path = publisher.topic_path(project_id, topic_id)

publisher.publish(topic_path, b"Hello World")

JWTを使って認証

google.auth.jwt.Credentialsを使って認証する方法です。
先ほどのgoogle.oauth2.service_account moduleの認証でもJWTを内部で扱っているのですが、アクセストークンの扱い方がそれぞれ違うみたいです。簡単にまとめると

使用ライブラリ 認証方法
google.oauth2.service_account module JWTを用いてoauth2.0のアクセストークンを獲得して、GCPの認証はoauth2.0のアクセストークンをBearerトークンとして行う
google.auth.jwt.Credentials JWTで生成したBearerトークンを使ってGCPの認証を行う

のような違いがあるみたいです。

from google.cloud import pubsub_v1
from google.auth import jwt
import json
import os
project_id = os.getenv("PROJECT_ID", "")
topic_id = os.getenv("TOPIC_ID", "")
service_account_file = os.getenv("GOOGLE_APPLICATION_CREDENTIALS", "")
publisher_audience = "https://pubsub.googleapis.com/google.pubsub.v1.Publisher"
credentials =  jwt.Credentials.from_service_account_info(json.loads(service_account_file), audience=publisher_audience)
publisher = pubsub_v1.PublisherClient(credentials=credentials)
topic_path = publisher.topic_path(project_id, topic_id)

publisher.publish(topic_path, b"Hello World")

ユーザーアカウントを用いて認証

環境変数を用いて認証

サービスアカウントを用いた方法と変わらないです。GOOGLE_APPLICATION_CREDENTIALSに使いたいユーザーアカウントのファイルパスを指定します。

ファイルパスを指定して認証

google.oauth2.credentials moduleを使って認証します。

from google.cloud import pubsub_v1
from google.oauth2 import credentials 
import os
project_id = os.getenv("PROJECT_ID", "")
topic_id = os.getenv("TOPIC_ID", "")
user_account_path = os.getenv("GOOGLE_APPLICATION_CREDENTIALS", "")
credentials = credentials.Credentials.from_authorized_user_file(user_account_path)
publisher = pubsub_v1.PublisherClient(credentials=credentials)
topic_path = publisher.topic_path(project_id, topic_id)

publisher.publish(topic_path, b"Hello World")

データを直接読み込んで認証

こちらも同じようにgoogle.oauth2.credentials moduleを使います。

from google.cloud import pubsub_v1
from google.oauth2 import credentials 
import json
import os

project_id = os.getenv("PROJECT_ID", "")
topic_id = os.getenv("TOPIC_ID", "")
user_account_file = os.getenv("GOOGLE_APPLICATION_CREDENTIALS", "")
credentials = credentials.Credentials.from_authorized_user_info(json.loads(user_account_file))
publisher = pubsub_v1.PublisherClient(credentials=credentials)
topic_path = publisher.topic_path(project_id, topic_id)

publisher.publish(topic_path, b"Hello World")

まとめ

google-authを眺めていると、まだ挙げていない認証方法もあるのかなと思います。最近は色々なクラウド環境を使う機会が増えてきたので、どのような認証方法が提供されているのか把握できてるとスムーズに開発が行えると思います。
とりあえずGCPの認証に関してはある程度理解できたので今後困ることはなさそうです。