Cloud RunからAzure OpenAIを呼び出す(Google Cloud→Azureの認証をIAMで通す)
以前書いた記事のAzure版になります。
はじめに
前回、Google CloudのCloud RunからAWSのBedrockを呼び出してアプリに組み込んだので、今回はAzure OpenAIを呼び出してGoogle Cloud上でGPT-4oを使います。
AWSの時と同様に、セキュリティを考慮してAPIキーなどという危険物には頼らずIAMで認証を通します。
IAMで、Google Cloud → Azureの認証を通す
方針
AzureとGoogle Cloudは別サービスですので、認証を突破しない限り利用する事はできません。
一番単純なのはAzure OpenAIのAPIキーを発行して使用することですが、セキュリティリスクが高いのでよろしくないですよね。アクセスキーお漏らしでセキュリティ事故になっている会社が毎月のように発生している昨今の状態を考えるとAPIキーの利用は大きなリスクを感じてしまいます。
ではどうするかですが、Google CloudのIAMに対してAzureのIAMを紐づければよいわけです。AWSでは出来たのだからAzureでもできるでしょう。と思ってやってみたら出来ました。
やってみた
Azure側でアプリを登録する
-
AzureのコンソールからEntraID(旧AzureAD)のページを開き、左のメニューから「アプリの登録」を選びます。
-
新規作成は、とりあえず適当に名前だけつけて登録すます。
-
登録されたアプリを開き、左のメニューから「証明書とシークレット」を選択します。証明書でもシークレットでもなく「フェデレーション資格情報」タブを選び「資格情報の追加」を選択します。
-
資格情報を以下のように入力して保存します。
- フェデレーション資格情報のシナリオ:「その他の発行者」
- 発行者:「https://accounts.google.com」
- サブジェクト識別子:Cloud Runに紐づけられているサービスアカウントの「一意のID」
- 名前: 好きな名前
- 説明: 任意(空でもよい)
- 対象ユーザー: 既定値のままが良さそうなので「api://AzureADTokenExchange」
-
EntraIDを離れてAzure OpenAIに移動します。GoogleCloudから呼び出したいOpenAIのサービスの「アクセス制御 (IAM)」を開き、先程作成したアプリに「Cognitive Service OpenAI User」の権限を付与します。
Azure側の設定は以上です。
認証用のコードを書く
続いて、認証情報を取得するためのコードを書いていきます。
Google CloudのメータデータサーバーからIDトークンを取得するまでは、AWSでやった時と同じです。一応参考用に公式ドキュメントを張っておきます。
その後、Azure SDKのClientAssertionCredential
クラスを使って認証情報を取得します。
必要なライブラリのインストール
azure-identity
とgoogle-auth
をインストールします。
rye add azure-identity google-auth
rye sync
Azureの認証情報を取得
Google CloudのメータデータサーバーからIDトークンを取得しそのIDトークンからAzure(EntraID)の認証情報を取得する関数を書きます。
from google.auth import compute_engine
import google.auth.transport.requests as grequests
from azure.identity import ClientAssertionCredential
def get_azure_creds(app_user_uri: str, tenant_id: str, client_id: str) -> ClientAssertionCredential | None:
'''
Google CloudのメタデータサーバーからIDトークンを取得するし、
Azure OpenAIへのaccess tokenを取得する
'''
def _get_google_token() -> str:
'''Google CloudのIDトークンを取得'''
request = grequests.Request()
g_credentials = compute_engine.IDTokenCredentials(
request=request,
target_audience=app_user_uri,
use_metadata_identity_endpoint=True
)
g_credentials.refresh(request)
return g_credentials.token
try:
# AzureのCrendetialを取得
az_creds = ClientAssertionCredential(
tenant_id=tenant_id,
client_id=client_id,
func=_get_google_token,
)
return az_creds
except Exception as e:
print(f"Error: {e}")
return None
実際に使う時は次のように呼び出します。AZURE_APP_USER_URI
には、先ほど作成したEntraIDのアプリの対象ユーザーつまり「api://AzureADTokenExchange」を設定してください。AZURE_TENANT_ID
とAZURE_CLIENT_ID
はそれぞれアプリのテナントIDとクライアントIDです。
from pydantic.v1 import SecretStr
from langchain_openai import AzureChatOpenAI
az_creds = get_azure_creds(
app_user_uri=AZURE_APP_USER_URI,
tenant_id=AZURE_TENANT_ID,
client_id=AZURE_CLIENT_ID,
)
az_token: SecretStr = SecretStr(az_creds.get_token(
"https://cognitiveservices.azure.com/.default"
).token if az_creds else "")
llm = AzureChatOpenAI(
azure_ad_token=az_token,
... # その他の引数を指定
)
azure_ad_token
はstr
で入れても動くのですが、何故かpydantic.v1.SecretStr
が型指定されているので従いました。なんで今どきv2でなくてv1なのでしょうね?
実行結果
ということで、なんとか無事にCloudRunからOpenAIを実行することが出来できたので、AzureとGoogle CloudとAWSの生成AIを同時に実行してみました。
同様の方法で、 CloudRun → OpenAI 以外のサービスでも Google Cloud → Azure の認証に応用出来るかと思われます。
ただし、Azureには何故かIAMで認証出来ないサービスもあるので注意が必要です。
NCDC株式会社( ncdc.co.jp/ )のエンジニアチームです。 募集中のポジションや、採用している技術スタックの紹介などはこちらをご覧ください! github.com/ncdcdev/recruitment
Discussion