勇者だって最初はひのきの棒とナベのふた

技術を中心に発信。時々SFの読書感想も。

ManagedID でAzure PostgreSqlにアクセスする

はじめに

masamoriです。今年はもうちょっと記事書きたいです。

Azure FunctionsからDBに接続したい場合(クエリを発行したい場合)、シークレットの扱いが面倒だったりします。Key Vault使うのか環境変数ファイル用意するか。
ファイルを用意するのは正直面倒なので、Functionsの構成にシークレットを埋め込んで、それを呼び出すのもアリです。 しかし、それも面倒だったりするので、特に外部のDBを使う必要がなければ、Azure でDBを立ててマネージドIDを使うとシークレットの呼び出しする必要ないので、手間が減ります。(ただし、マネージドIDについて理解するには時間がかかる。) マネージドIDの説明はこちらが詳しいです。

tech-lab.sios.jp

Azure Functions とAzure PostgrSqlを接続することにしたので、マネージドIDを使うことにしました。 しかし、これが意外に上手くいかず少しハマりました。
なので、そのエラーと解決法の共有をします。

準備

まずは、FunctionsのマネージドIDをONにします。 そして、IAMでFunctionsに対して「共同作成者」のロールを付与しました。 次にコードを書きます。 参考にしたコード例は以下のサイトから得られたこちら learn.microsoft.com

import { DefaultAzureCredential, ClientSecretCredential } from "@azure/identity";
const { Client } = require('pg');

// Uncomment the following lines according to the authentication type.  
// For system-assigned identity.
// const credential = new DefaultAzureCredential();

// For user-assigned identity.
// const clientId = process.env.AZURE_POSTGRESQL_CLIENTID;
// const credential = new DefaultAzureCredential({
//     managedIdentityClientId: clientId
// });

// Acquire the access token.
var accessToken = await credential.getToken('https://ossrdbms-aad.database.windows.net/.default');

// Use the token and the connection information from the environment variables added by Service Connector to establish the connection.
(async () => {
const client = new Client({
    host: process.env.AZURE_POSTGRESQL_HOST,
    user: process.env.AZURE_POSTGRESQL_USER,
    password: accesstoken.token,
    database: process.env.AZURE_POSTGRESQL_DATABASE,
    port: Number(process.env.AZURE_POSTGRESQL_PORT) ,
    ssl: process.env.AZURE_POSTGRESQL_SSL
});
await client.connect();

await client.end();
})();

こちらはApp Serviceのチュートリアルですが、Functionでも基本的には同じです。 マネージドIDを使用してDBに接続を試みる場合、上記の「AZURE_POSTGRESQL_USER」は最初にDBを作成した際に設定したユーザーじゃないです。マネージドIDのオブジェクト名にします。今回は、Functionsの名前です。

実行とエラー

さて、とりあえずローカルの環境で接続テストをしてみました。すると、以下のエラーが発生。

error: password authentication failed for user "<ユーザー名>" at Parser.parseErrorMessage.
どうやら認証に失敗した様子。おかしいな。マネージドIDを設定したはずなのに、IAMのロール割り当てが間違っていたか? ところが、「管理者」権限を割り当てても解決しません。

解決法

ということは、他の認証が必要ということですね。ググってみたら、解決に役立ちそうな記事がありました。 qiita.com

なるほど、この認証が必要なんですね。 そして、この画面下にある「Microsoft Entra 管理者の追加」でFunctinosのマネージドIDを設定したら、接続に成功しました。

まとめ

DBと接続したい場合は、「認証」をRBACとは別に設定する必要があります。ということは、この「認証」はDB特有の設定なのでしょうか?
ちなみに、「管理者」「共同作成者」を外してもDBに接続できました。この「認証」を次の記事あたりで深掘りしてみたいですね。

また、踏み台サーバーなどからDBに通常アクセスしたい場合は、最初に設定したユーザー名とパスワードでアクセスしましょう。