Spring Boot からAzure Database for PostgreSQLへ接続する

# はじめに

　この記事を書くきっかけになったのは、こちらの Microsoft 公式ページです。

[Azure Database for PostgreSQL で Spring Data JDBC を使用する](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server)

　こちらのページは PostgreSQL 認証と Azure AD 認証の構築方法が混ざっていてとてもわかりにくくなっています。またどちらの場合もページに記載されている通りに実装しても動かない箇所があるのです。 GitHub に公開されているサンプルプログラムも動きません。Pull Requestを出して地道に直してもらうことはやろうと思いますが、いつ反映されるのかわかりませんので、2023/8時点で確実に動作する方法を記載しておきます。

　以下の説明は[Microsoft 公式ページ](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server)を個人的に補足するものです。

# 環境

- openjdk 17.0.8 2023-07-18 LTS
- Apache Maven 3.9.4
- pgAdmin 4

　Mac 環境で確認済みです。 Windows環境では未確認ですが特に変更が必要なところはないはずです。

　同じ環境を用意するときに、Java 環境をローカルに Install するのとバージョン管理が・・・という方は、VSCode には Remote Container（DevContainer）という機能のご利用をお勧めします。そちらをご利用になる場合は以下の devcontainer.json ファイルをご利用ください。

　もし、環境に Azure CLI が不要な場合は次の行を削除してください。ただし、Azure AD 認証（パスワードレス）をテストする場合は Azure CLI があったほうが便利です。

> "ghcr.io/devcontainers/features/azure-cli:1": {}

```json:.devcontainer/devcontainer.json
// For format details, see https://aka.ms/devcontainer.json. For config options, see the
// README at: https://github.com/devcontainers/templates/tree/main/src/java
{
	"name": "Java",
	// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
	"image": "mcr.microsoft.com/devcontainers/java:1-17-bullseye",
	"features": {
		"ghcr.io/devcontainers/features/java:1": {
			"version": "none",
			"installMaven": "true",
			"installGradle": "false"
		},
		"ghcr.io/devcontainers/features/azure-cli:1": {}
	},
	// Use 'forwardPorts' to make a list of ports inside the container available locally.
	// "forwardPorts": [],
	// Use 'postCreateCommand' to run commands after the container is created.
	// "postCreateCommand": "java -version",
	// Configure tool-specific properties.
	"customizations": {
		"vscode": {
			"extensions": [
				"vscjava.vscode-java-pack",
				"vmware.vscode-boot-dev-pack",
				"pkief.material-icon-theme"
			]
		}
	}
	// Uncomment to connect as root instead. More info: https://aka.ms/dev-containers-non-root.
	// "remoteUser": "root"
}
```

# Azure Database for PostgreSQL を作成する

　Azure Database for PostgreSQL には Single Server と Flexible Server のに種類を選択することができます。**必ず Flexible Server を選びましょう。** Single Server は2025 年 3 月 28 日までに廃止される予定です。詳しくは[こちら](https://learn.microsoft.com/ja-jp/azure/postgresql/single-server/whats-happening-to-postgresql-single-server)をご確認ください。

## 認証の種類

　Azure Database for PostgreSQL では作成時に認証の種類を３種類から選ぶことができます。

- PostgreSQL の認証のみ
- Azure Active Directory 認証のみ
- PostgreSQL と Azure Active Directory の認証

　今回は一番下の**PostgreSQL と Azure Active Directory の認証**を選びます。それぞれの認証の場合において、Spring Bootでどのようにセットアップするのかを示すためです。この時、Azure AD 管理者の設定をする、で自分を選んでおいてください。（この認証の種類は作成後に変更可能です）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/dc7dabe3-8e94-b3b5-9e7f-3af2b4052df7.png)

上図のスクリーンキャプチャでは Azure AD 管理者の設定が未選択ですが、実際には自分自身を選択しておいてください。

## Azure Database for PostgreSQL の Firewall を設定する

　Azure Database for PostgreSQL には Firewall 機能が搭載されており、明示的に IP アドレスを許可しなければアクセスできないようになっています。ローカルで稼働する Spring Boot から Azure Database for PostgreSQL にアクセスするためには、ローカルマシンの Global IP を Firewall に登録する必要があります。

　Azure Database for PostgreSQL を Azure Portal で開き、左のメニューのネットワークを選択します。右画面の下の方に「**現在のクライアント IP アドレスを追加する**」をクリックし、画面上部の保存アイコンをクリックしてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/06c67396-caf3-34e3-a187-79416546efbd.png)

## データベースを作る

　今回の接続先としてデータベースを作成します。Azure Portal から作るのが簡単で良いでしょう。左メニューのデータベースを選択し、右画面上部の追加をクリックしてデータベースを作成してください。私は testdb という名前でデータベースを作成しました。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/a75c7c5f-e339-f598-4653-b11e6643af7b.png)


# PostgreSQL 認証で Spring Boot からアクセスする

　まずは一番基本となる PostgreSQL 認証です。[Microsoft 公式ページ](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server)ではパスワード（認証）として記載があるものです。セキュリティの観点から Microsoft としては非推奨の認証方法であることに留意してください。

## 一般ユーザーの作成

　[Microsoft 公式ページ](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server)では管理者ユーザーではない一般ユーザーを作ることから作業を始めていますが、この手順は必須ではありません。セキュリティの観点から管理者ユーザーのパスワードが漏洩することを防止するためにまず一般ユーザーの作成を行なっているのだと思いますが、この手順のせいでトラブル発生時に問題箇所の特定が難しくなります。まずは管理者ユーザーで接続を試し、その後で一般ユーザーを作成して接続情報を切り替えるのが良いでしょう。

　一般ユーザーの作り方、権限の付与については[Microsoft 公式ページ](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server)の情報に不備がありますので後述します。

## DB 用ツールから Azure Database for PostgreSQL に接続する

　ローカルに PostgreSQL をインストールしている場合は psql というコマンドラインのツールが一緒にインストールされるため、そのツールを用いて Azure Database for PostgreSQL に接続できます。しかし、ローカルに Database　を用意する必要がない場合は psql だけをインストールするか、もしくは pgAdmin のようなツールを使うと良いでしょう。

　私はデータベースを扱う場合は pgAdmin のような GUI ツールを使うのが好きなので、pgAdmin を使います。

https://www.pgadmin.org/

pgAdmin を使って接続するときには、Azure Database for PostgreSQL作成時に指定したユーザーID/パスワードを使って接続します。

## テスト用にテーブルを作る

　[Microsoft 公式ページ](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server)そのままです。上で作ったデータベースに対して pgAdmin のクエリツールを開き、次のSQLを流します。

```sql
DROP TABLE IF EXISTS todo;
CREATE TABLE todo (id SERIAL PRIMARY KEY, description VARCHAR(255), details VARCHAR(4096), done BOOLEAN);
```

　テーブルができたら、このように何かデータを入れておくと後で確認がしやすいでしょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/9c2a5bb9-6b1f-2f30-8f46-775b359066e4.png)

## Spring Boot アプリを作る

### Spring Initializr を使う

　VSCode の Spring 用の Extension を使うとわざわざブラウザで Spring Initializr を使う必要はないのですが、どんな Dependency を使うのかがわかりやすのでここでは Spring Initializr の画面のキャプチャを載せておきます。

　次の3つの Dependency を必ず追加してください。それ以外はご自由に。

- Spring Web
- Spring Data JDBC
- PostgreSQL Driver

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/c5d82318-f7a5-8e85-8a6f-9380b64c6ba0.png)

　[Microsoft 公式ページ](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server) だとさらに Spring Cloud Azure のモジュールを pom.xml に追加していますが、PostgreSQL 認証の場合は不要です。

### application.properties に設定を記載する

　application.properties ファイルを開き、次の設定を行います。４箇所、自分の環境に合わせて修正してください。もちろん、前後の <> は削除してください。

- your_postgresql_name
- dbname（urlの後ろに付いているのでお見逃しないように）
- your_postgresql_username
- your_postgresql_password

```ini:application.propretyes
logging.level.org.springframework.jdbc.core=DEBUG

spring.datasource.url=jdbc:postgresql://<your_postgresql_name>.postgres.database.azure.com:5432/<dbname>?sslmode=require
spring.datasource.username=<your_postgresql_username>
spring.datasource.password=<your_postgresql_password>
spring.datasource.driver-class-name=org.postgresql.Driver
```

### DBアクセスを実装する

　[Microsoft 公式ページ](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server)にはサンプル実装の公開先として GitHub の URL の記載があります。その GitHub の実装をそのまま使います。

　次の3つのファイルは、ｓｒｃ/main/java/com/example/demo に作成しています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/8677a77f-15c0-c475-e823-14c386017974.png)


```java:Todo.java
package com.example.demo;

import org.springframework.data.annotation.Id;

public class Todo {

    public Todo() {
    }

    public Todo(String description, String details, boolean done) {
        this.description = description;
        this.details = details;
        this.done = done;
    }

    @Id
    private Long id;

    private String description;

    private String details;

    private boolean done;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public String getDetails() {
        return details;
    }

    public void setDetails(String details) {
        this.details = details;
    }

    public boolean isDone() {
        return done;
    }

    public void setDone(boolean done) {
        this.done = done;
    }
}
```

```java:TodoController.java
package com.example.demo;

import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@RestController
@RequestMapping("/")
public class TodoController {

    private final TodoRepository todoRepository;

    public TodoController(TodoRepository todoRepository) {
        this.todoRepository = todoRepository;
    }

    @PostMapping("/")
    @ResponseStatus(HttpStatus.CREATED)
    public Todo createTodo(@RequestBody Todo todo) {
        return todoRepository.save(todo);
    }

    @GetMapping("/")
    public Iterable<Todo> getTodos() {
        return todoRepository.findAll();
    }
}
```

```java:TodoRepository.java
package com.example.demo;

import org.springframework.data.repository.CrudRepository;

public interface TodoRepository extends CrudRepository<Todo, Long> {
}
```

## 確認する

Dependency をダウンロードします。

```zsh
./mvnw clean install
```

Spring Boot アプリを実行します。

```zsh
./mvnw spring-boot:run
```

http://localhost:8080 にアクセスすると次のように結果が表示され、無事に Azure Database for PostgreSQL に接続されたことが確認できます。

```json
[
    {
        "id": 0,
        "description": "テスト",
        "details": "詳細",
        "done": false
    }
]
```

# Azure Active Directory 認証で Spring Boot からアクセスする

　[Microsoft 公式ページ](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server)ではパスワードレス（推奨）と書かれている方法です。Azure AD を使うことで一切パスワードを記載する必要がないため、漏洩事故が起こりにくくなっています。

## 一般ユーザーを作成する

　パスワードレスの場合もパスワード認証の時と同様、[Microsoft 公式ページ](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server)では管理者ユーザーではない一般ユーザーを作ることから作業を始めていますが、この手順は必須ではありません。まずは Azure Database for PostgreSQL を作成したときに Azure AD 管理者として自分を指定しているはずですので（上記手順に記載しています）、まずは管理者である自分自身がログインできることを確認できたら、他の Azure AD ユーザーを一般ユーザーとしてログインできるように設定しましょう。
　一般ユーザーの作成方法は　[Microsoft 公式ページ](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server#create-a-postgresql-non-admin-user-and-grant-permission)に記載がありますが、こちらの方法ではうまくいかないことがあります（私はうまくいきませんでした）。Step by Step で作成する方法を後述していますので、必要な方はそちらをご確認ください。

## Azure ADユーザー（自分）に権限を付与する

　Azure Database for PostgreSQL 作成時に指定した　　Azure AD 管理者ユーザーは、そのままだと Database のテーブルに対するアクセス権限がありませんので、付与する必要があります。権限を付与する時は PostgreSQL 認証を使って（ユーザーID/Password　で）、pgAdmin でログインします。

　ログインしたら、ログイン/グループロールを開きます。すると、Azure AD のユーザープリンシパル名と同じユーザーが作成されているはずです。そのユーザー名をコピーします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/a8bd59ed-f48c-921e-d4ef-170e11b4a436.png)

　クエリツールを開き、次のように権限を付与するSQLを流します。DBNameとYOUR_USER_PRINCIPAL_NAMEはご自身のものに変更してください。（前後の<>は削除）

```sql:sql
GRANT ALL PRIVILEGES ON DATABASE <DBName> TO "<YOUR_USER_PRINCIPAL_NAME>";
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "<YOUR_USER_PRINCIPAL_NAME>";
```

## Spring Boot アプリを作る

Spring Initializr を使って作成する方法は、上に記載したパスワードでの認証の時と同じです。

### application.properties に設定を記載する

　application.properties ファイルを開き、次の設定を行います。3箇所、自分の環境に合わせて修正してください。もちろん、前後の <> は削除してください。

- your_postgresql_name
- dbname（urlの後ろに付いているのでお見逃しないように）
- your_postgresql_username

```ini:application.propretyes
logging.level.org.springframework.jdbc.core=DEBUG

spring.datasource.url=jdbc:postgresql://<your_postgresql_name>.postgres.database.azure.com:5432/<dbname>?sslmode=require
spring.datasource.username=<your_postgresql_username>
spring.datasource.azure.passwordless-enabled=true
```

## Azure AD 認証用の Dependency を追加する

pom.xml に対して２つ追加するのですが、それぞれの追加する場所が違いますので気をつけてください。

1つ目の spring-cloud-azure-starter-jdbc-postgresql は Project/dependencies の配下に記載します。

```xml:pom.xml
<dependency>
	<groupId>com.azure.spring</groupId>
	<artifactId>spring-cloud-azure-starter-jdbc-postgresql</artifactId>
</dependency>
```

2つ目の spring-cloud-azure-dependencies は Project 直下に記載します。Version は5.5.0となっていますが、その時の最新を設定すれば良いはずです。

```xml:pom.xml
<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>com.azure.spring</groupId>
			<artifactId>spring-cloud-azure-dependencies</artifactId>
			<version>5.5.0</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>
```

念の為、追加済みの pom.xml を掲載しておきます。

```xml:pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
	<modelVersion>4.0.0</modelVersion>
	<parent>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-parent</artifactId>
		<version>3.1.3</version>
		<relativePath/> <!-- lookup parent from repository -->
	</parent>
	<groupId>com.example</groupId>
	<artifactId>demo</artifactId>
	<version>0.0.1-SNAPSHOT</version>
	<name>demo</name>
	<description>Demo project for Spring Boot</description>
	<properties>
		<java.version>17</java.version>
		<spring-cloud-azure.version>5.5.0</spring-cloud-azure.version>
	</properties>
	<dependencies>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-data-jdbc</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-devtools</artifactId>
			<scope>runtime</scope>
			<optional>true</optional>
		</dependency>
		<dependency>
			<groupId>org.postgresql</groupId>
			<artifactId>postgresql</artifactId>
			<scope>runtime</scope>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>
		<dependency>
			<groupId>com.azure.spring</groupId>
			<artifactId>spring-cloud-azure-starter-jdbc-postgresql</artifactId>
		</dependency>

	</dependencies>

	<dependencyManagement>
		<dependencies>
			<dependency>
				<groupId>com.azure.spring</groupId>
				<artifactId>spring-cloud-azure-dependencies</artifactId>
				<version>5.5.0</version>
				<type>pom</type>
				<scope>import</scope>
			</dependency>
		</dependencies>
	</dependencyManagement>

	<build>
		<plugins>
			<plugin>
				<groupId>org.springframework.boot</groupId>
				<artifactId>spring-boot-maven-plugin</artifactId>
			</plugin>
		</plugins>
	</build>

</project>
```

## 確認する

確認用の実装はパスワードによる認証の時と同じです。 Todo, TodoController, TodoRepisotryを実装してください。

次に、実行環境で Azure CLI でログインしておきます。この時、当然ですがログインユーザーは Azure Database for PostgreSQL を作成時に指定した自分自身のアカウントでログインします。

```zsh:zsh
az login
```

このログイン済みの状態で Spring Boot アプリを実行すると、自動的にそのログインの Token 情報を取得してログインしてくれますので、やってみてください。これは Spring Cloud Azure が DefaultAzureCredential というものを使用してログインするからです。

　DefaultAzureCredential は、実行時にログイン情報を取得先を優先順に取得しにいきます。最初は環境変数、次に Managed ID 、次に IntelliJ、VSCode、最後に Azure CLI のログイン情報を見に行きます。そのため、このソースコードのままで Azure にデプロイした場合はログインに必要な情報を環境変数として　Azure 側にセットしておけば自動的にそれを使用してログインしてくれるわけです。（Managed ID や Service Connector を使うのが一番オススメです）

DefaultAzureCredential についての詳細は [Microsoft 公式ページ](https://learn.microsoft.com/ja-JP/azure/developer/java/sdk/identity-azure-hosted-auth#default-azure-credential)をご確認ください。

# （おまけ）PostgreSQL 認証の一般ユーザーの作り方
　まず、Azure Database for PostgreSQL 作成時に指定したユーザーID/パスワードを使って接続します。次に postgre データベースを右クリックしてクエリツールを開きます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/98060755-a494-f470-fdc8-894e719188f9.png)

　開いたクエリツールに次のSQLを打ち込みます。ここではユーザーが user1 として作成し、testdb とその中のテーブルに対して全権限を与えています。

```sql
CREATE USER "user1" WITH LOGIN PASSWORD 'YOUR_PASSWORD';
GRANT ALL PRIVILEGES ON DATABASE testdb TO "user1";
GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO "user1";
```
　[Microsoft 公式ページ](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server)の方法ではテーブルに対する権限付与を行なっていないため動作しないことに注意してください。

# （おまけ）Azure AD 認証の一般ユーザーの作り方

　[Microsoft 公式ページ](https://learn.microsoft.com/ja-jp/azure/developer/java/spring-framework/configure-spring-data-jdbc-with-azure-postgresql?tabs=passwordless%2Cservice-connector&pivots=postgresql-passwordless-flexible-server#create-a-postgresql-non-admin-user-and-grant-permission)を見ると、 Azure CLI で次のコマンドを叩けば良い、となっています。しかし、これ方法ではうまくいかないことが多いでしょう。もし、このコマンドが動作するのであれば以下の手順は参照する必要はありません。私の場合はうまく動作しませんでした。

```zsh:zsh
az connection create postgres-flexible \
       --resource-group <your_resource_group_name> \
       --connection postgres_conn \
       --target-resource-group <your_resource_group_name> \
       --server postgresqlflexibletest \
       --database demo \
       --user-account \
       --query authInfo.userName \
       --output tsv
```

　まず Azure Database for PostgreSQL 作成時に指定した Azure AD 管理者で Azure Database for PostgreSQL に接続する必要があります。このユーザーで接続しないと、Azure AD 認証の一般ユーザーが作れないのです。まずはこのユーザーで Azure Database for PostgreSQL にまず接続する方法をご紹介します。

## pgAdmin で接続する

### Token を取得する

　Azure AD から、Azure Database for PostgreSQL に接続するときに使用する AccessToken を取得する必要があります。これはパスワードに相当します。次のコマンドで Token を取得できます。

```zsh
az account get-access-token --resource-type oss-rdbms
```

表示された Json のうち、 accessToken というキーの値が Token です。どこかに控えておきます。

### ユーザープリンシパル名を取得する

　ユーザープリンシパル名は、Azure AD の中でユーザーを一意に識別するものです。ログインIDと同じではない場合がありますので、必ず確認します。上記には　pgAdmin で接続するとユーザー/グループロールを開いて表示されるユーザー一覧からユーザープリンシパル名を取得する方法をご紹介していますので、もう１つの方法をご紹介します。Azure Portal で Azure AD を開き、左メニューの「ユーザー」を選択します。Azure Database for PostgreSQL 作成時に指定したユーザーを検索して探し出してクリックすれば、ユーザープリンシパル名の記載があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/84ce4cfd-e606-bc03-747f-cebf8c6d582c.png)

### pgAdmin で接続する

　サーバーへの接続情報を新たに作成します。このときに、「今すぐ接続」をオフにします。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/8be3606b-8a29-d20f-e843-15da6f072f58.png)

　ユーザー名に設定するのは Azure AD 管理者のユーザープリンシパル名です。必ず上記の方法で Azure AD を参照して確認してください。ユーザープリンシパル名はログイン時のメールアドレスと同じとは限らないからです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/60bd71df-3916-92bb-454a-a1a52610ddab.png)

　保存して、接続するとパスワード入力のプロンプトが上がってきます。取得しておいた Token を入力すれば、接続できます。

## 一般ユーザーを作成する

　Azure Database for PostgreSQL の Azure AD 認証用の一般ユーザーを作る、とは次の作業のことを指します。

1. Azure AD に一般用ユーザーを作成するか、既存ユーザーを使う
1. 一般用ユーザーのユーザープリンシパル名と同じユーザー名を持つユーザーを PostgreSQL の中に作成し、Azure AD の一般用ユーザーと PostgreSQL のユーザーを紐付ける

そんなに大した作業ではないのですが、最初は分かりにくいです。1つずつやっていきましょう。

### 1. テスト用のユーザーを Azure AD に作る

　もし既存ユーザーを一般用ユーザーとして登録するのであればこの作業は不要です。テスト用に Azure AD 内部に一般用ユーザーを作る場合、作成権限が必要です。作成権限があるのであれば　Azure Portal を開いてユーザーを作成してください。作成権限を持っていない場合はサービスプリンシパルで代用しましょう。

　Azure AD の「アプリの登録」からサービスプリンシパルを作っても良いのですが、面倒なので　Azure CLI で作ります。ここで作ったサービスプリンシパルは Azure AD の「アプリの登録」を開き、「所有しているアプリケーション」をクリックすると表示されます。不要になったらここから消すのが簡単でしょう。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/948668f9-5170-f5cf-280e-a405cc281cae.png)

　次のコマンドでサービスプリンシパルを作成します。 --name オプションでつける名前は自由にしてください。サービスプリンシパルは Azure Database for PostgreSQL にアクセス権が必要ですので、作成時に Contributor ロールを付与しています。この例ではサブスクリプションレベルなのでかなり大きなスコープです。本当はもっとスコープを絞り込み、権限も Contributor よりもっと小さなものを付与した方がセキュリティ上望ましいことは言うまでもありません。

　既存 Azure ADユーザーを Azure AD 認証させる場合にも、同様に Azure Database for PostgreSQL にアクセス権があるようにしてください。

```zsh:zsh
az ad sp create-for-rbac \
--name postgresql-test \
--role Contributor \
--scopes /subscriptions/00000000-0000-0000-0000-000000000000 
```

コマンド実行の結果、appId と password が返却されますのでメモしておきます。

### 2. 一般用ユーザーのユーザープリンシパル名と同じユーザー名を持つユーザーを PostgreSQL の中に作成し、Azure AD の一般用ユーザーと PostgreSQL のユーザーを紐付ける

　この作業は SQL を1回発行すれば完了します。Azure AD 管理者で pgAdmin に接続している状態で、**postgres**データベースに対してクエリツールを開き、次のSQLを流します。え、 select 文？ create 文じゃなくて？と思いますが、これで正しいです。

第一引数には、Azure AD のユーザープリンシパル名をセットします。サービスプリンシパルを作った場合は自分が指定したサービスプリンシパル名です。

```sql:sql
select * from pgaadauth_create_principal('postgresql-test', false, false);
```

SQLを発行すると、Azure AD に該当のユーザー（サービスプリンシパル）が存在しているのかを確認し、Tenant Idなどの情報を取得してきて内部に格納する、という動作をします。

　クエリが正常終了したら、ちゃんと作成されていることを確認しましょう。次のクエリを流します。

```sql:sql
select * from pgaadauth_list_principals(false);
```

このように指定したユーザープリンシパル名（サービスプリンシパル名）の行が表示されるはずです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/b82dedae-c3c1-3064-8881-0ef16dfc3602.png)

また、ユーザーとしても作成されています。ユーザー/グループロールを再読み込みしてみてください。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/222127/6d9d0a4f-f88c-3733-64cc-a7fd3c19e3d4.png)

　もし、Azure AD 認証が不要になった場合はこの PostgreSQL 内部に作成されたユーザーだけ削除すればOKです。

 ちなみにユーザーを作るのに、なんで select 文なの？と思いますが、from 句をよく見ると pgaadauth_**create**_principal と create いう文字列が含まれています。これ、どうやらユーザー定義関数のようでその呼び出しに select 文を使っている、ということです。ですので、select 文ですがユーザーが作成されるという（微妙な）不思議な SQL になっています。

### 確認する

作成したサービスプリンシパル、もしくは既存の Azure AD ユーザーで pgAdmin に Azure AD 認証でログインできるかを確認します。

Azure AD 管理者でログインした時と同様、 Token を取得する必要があります。サービスプリンシパルの場合、次の手順で Token を取得します。

```zsh
az logout
az login --service-principal \
-u "<appId/ClientId/ObjectId>" \
-p "<password>" \
-t "<tenantId>"
```

-u オプションに指定するのはサービスプリンシパルの場合は作成時に返却された appId、別名ClientID です。Azure AD ユーザーの場合は Object ID です。ややこしいですね。 tenantId には Azure AD のテナントIDをセットしてください。

　もし、サービスプリンシパルがログインできない場合は権限の付与をしなかった可能性があります。別途手動で権限を付与してください。

ログインができたら、次のコマンドで Token を取得します。

```zsh
az account get-access-token \
--resource-type oss-rdbms \
--output tsv \
--query accessToken
```

Token さえ取得してしまえばあとは簡単です。pgAdmin に新しいサーバー接続を作成するときに、「いますぐ接続」をオフにし、ユーザー名にユーザープリンシパル名、もしくはサービスプリンシパル名をセットして保存、接続すればパスワードのダイアログがポップアップしますので、そこに Token を貼り付ければログインできます。

# おまけ：psql で Azure AD 認証を使ってログインする

　Windowsでは試していないのですが、 Mac の場合は [Microsoft 公式](https://learn.microsoft.com/ja-jp/azure/postgresql/flexible-server/how-to-configure-sign-in-azure-ad-authentication#use-a-token-as-a-password-for-signing-in-with-client-psql)に記載されている方法ではログインできません。

　az login でログイン済みのユーザーがAzure AD 認証ユーザー可能なようにセットアップ済みの場合、次のコマンドでログイン可能です。

```zsh:zsh
PGPASSWORD=`az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken` \
psql --host=<your_postgresql_servername>.postgres.database.azure.com \
--user=<your_user_principal_name> dbname=<dbname> \
--port=5432
```

難しく見えますが、次の箇所は別途取得した Token に置き換えても動作します。

> `az account get-access-token --resource-type oss-rdbms --output tsv --query accessToken`

要するに PGPASSWORD= に続けて Token を記載し、さらに続けて psql のログイン用のオプションを書けば良い、ということです。