IAM 認証を使用して Java アプリケーションを AlloyDB for PostgreSQL に接続する

1. 始める前に

Java と AlloyDB: シンプルで安全な接続

AlloyDB for PostgreSQL は、要求の厳しいエンタープライズ ワークロード向けに構築された、Google Cloud の PostgreSQL 互換のフルマネージド データベース サービスです。Java アプリケーションを AlloyDB に安全かつ効率的に接続するには、標準の JDBC ドライバを超えるクライアント ライブラリである AlloyDB Java コネクタ(alloydb-jdbc-connector)を使用します。

AlloyDB Java コネクタの魔法

alloydb-jdbc-connector は、標準の PostgreSQL JDBC ドライバ(org.postgresql:postgresql)のスマート SocketFactory として機能します。安全なデータベース接続の確立を抽象化するため、ネットワーク セキュリティや認証情報のローテーションではなく、アプリケーション ロジックに集中できます。

  • mTLS 1.3 暗号化: SSL/TLS クライアント証明書を手動で管理することなく、JVM と AlloyDB インスタンスの間に相互認証された TLS 1.3 接続を自動的に確立します。
  • IAM ベースの認可: 静的なデータベース パスワードに依存するのではなく、Google Cloud IAM とアプリケーションのデフォルト認証情報(ADC)を活用して、有効期間の短い OAuth2 アクセス トークンを自動的に取得します。
  • 動的 IP 解決: AlloyDB Admin API にクエリを実行して、データベース インスタンスの現在の IP アドレス(PRIVATE、PUBLIC、または Private Service Connect PSC)を動的に解決します。ホスト名や IP アドレスをハードコードする必要がないため、フェイルオーバーとメンテナンスを透過的に行うことができます。

AlloyDB Java コネクタの仕組み

前提条件

  • Java、Maven、基本的な SQL / JDBC のコンセプトに精通していること。
  • Google Cloud CLI(gcloud)と IAM ロールに関する基本的な知識。

演習内容

  • パスワードレスの IAM データベース認証用に AlloyDB インスタンスとサービス アカウントを構成する。
  • IAM プリンシパルに最小権限の PostgreSQL スキーマとテーブルの権限を付与します。
  • AlloyDB SocketFactory を使用して、Plain JDBC と HikariCP で本番環境グレードの DataSource を構成します。
  • AlloyDB Java コネクタを Spring Boot、Quarkus、Micronaut アプリケーションに統合する。
  • GraalVM Native Image のコンパイル用に AlloyDB SocketFactory を登録し、一般的な IAM 認証の落とし穴をトラブルシューティングします。

必要なもの

  • 課金が有効になっている Google Cloud プロジェクトと、アクティブな AlloyDB クラスタおよびプライマリ インスタンス(AlloyDB クラスタ作成ガイドを参照するか、2 秒未満で AlloyDB Express クラスタを起動します)。
  • プロジェクトに対する roles/alloydb.admin と roles/resourcemanager.projectIamAdmin の IAM ロール。
  • Java 17 以降(Java 17 または 21 LTS を推奨)と Apache Maven がインストールされている。
  • gcloud CLI と psql クライアントがインストールされている(または Google Cloud Shell にアクセスできる)。

2. AlloyDB で IAM データベース認証を設定する

Java コードを記述する前に、IAM トークンを受け入れるように AlloyDB インスタンスを構成し、アプリケーションが Google Cloud IAM、AlloyDB コントロール プレーン、PostgreSQL エンジンの 3 つのレイヤで使用する IAM ID を作成する必要があります。

AlloyDB IAM データベース認証の 3 層設定

環境変数の設定

ターミナルで、Google Cloud プロジェクトと AlloyDB インスタンスに対応する変数をエクスポートします( プレースホルダを実際の値に置き換えます)。

export PROJECT_ID="<PROJECT_ID>"
export REGION="europe-west1"
export CLUSTER_ID="<CLUSTER_ID>"
export INSTANCE_ID="<INSTANCE_ID>"
export DB_NAME="dvdrental"

必要な API の有効化

プロジェクトで AlloyDB、Compute Engine、Cloud Resource Manager、IAM、Service Usage API を有効にします。

gcloud services enable \
    alloydb.googleapis.com \
    compute.googleapis.com \
    cloudresourcemanager.googleapis.com \
    iam.googleapis.com \
    serviceusage.googleapis.com \
    --project="${PROJECT_ID}"

サービス アカウントを作成して IAM ロールを付与する

Java アプリケーションの ID として機能する専用のサービス アカウントを作成します。

gcloud iam service-accounts create java-alloydb-connector \
    --project="${PROJECT_ID}" \
    --display-name="Java Application DB Connector"

AlloyDB Java コネクタに必要な 2 つの IAM ロールをサービス アカウントに付与します。

  1. roles/alloydb.client: インスタンス メタデータを取得し、AlloyDB Admin API からエフェメラル mTLS 証明書をリクエストするために必要です。
  2. roles/serviceusage.serviceUsageConsumer: IAM データベース認証に必要です。
gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
    --member="serviceAccount:java-alloydb-connector@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/alloydb.client"

gcloud projects add-iam-policy-binding "${PROJECT_ID}" \
    --member="serviceAccount:java-alloydb-connector@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/serviceusage.serviceUsageConsumer"

AlloyDB インスタンスで IAM 認証を有効にする

AlloyDB インスタンス フラグを更新して alloydb.iam_authentication=on を設定します。これは動的フラグであり、インスタンスを再起動しなくてもすぐに有効になります。

gcloud alloydb instances update "${INSTANCE_ID}" \
    --cluster="${CLUSTER_ID}" \
    --region="${REGION}" \
    --project="${PROJECT_ID}" \
    --database-flags=alloydb.iam_authentication=on

IAM データベース ユーザーを登録する

gcloud を使用して、サービス アカウントを AlloyDB クラスタの IAM_BASED データベース ユーザーとして登録します。

gcloud alloydb users create "java-alloydb-connector@${PROJECT_ID}.iam" \
    --cluster="${CLUSTER_ID}" \
    --region="${REGION}" \
    --project="${PROJECT_ID}" \
    --type=IAM_BASED

PostgreSQL のスキーマとテーブルの権限を付与する

新しく作成された IAM データベース ユーザーには、デフォルトではテーブル権限が付与されません。postgres 管理者ユーザーとして AlloyDB インスタンスに接続し(psql または Cloud コンソールの AlloyDB Studio を使用)、ターゲット データベースとテーブル(DVD レンタルのサンプル データベースなど)へのアクセス権を付与します。

-- Connect to your target database first
\c dvdrental

-- (Optional) Create a sample film table if your database is empty
CREATE TABLE IF NOT EXISTS public.film (
    film_id SERIAL PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    release_year INTEGER DEFAULT 2006,
    rating VARCHAR(10) DEFAULT 'PG',
    rental_rate NUMERIC(4,2) DEFAULT 2.99
);

INSERT INTO public.film (film_id, title, release_year, rating, rental_rate) VALUES
    (1, 'Academy Dinosaur', 2006, 'PG', 0.99),
    (2, 'Ace Goldfinger', 2006, 'G', 4.99),
    (3, 'Adaptation Holes', 2006, 'NC-17', 2.99),
    (4, 'Affair Prejudice', 2006, 'G', 2.99),
    (5, 'African Egg', 2006, 'G', 2.99)
ON CONFLICT (film_id) DO NOTHING;

-- Grant permissions to the IAM user (double quotes are required because of '@' and '.')
GRANT CONNECT ON DATABASE "dvdrental" TO "java-alloydb-connector@<PROJECT_ID>.iam";
GRANT USAGE ON SCHEMA public TO "java-alloydb-connector@<PROJECT_ID>.iam";
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "java-alloydb-connector@<PROJECT_ID>.iam";

AlloyDB Studio(または psql)でこれらのステートメントを実行すると、public.film スキーマを検査してサンプル行を確認できます。

IAM 権限を付与して AlloyDB Studio で public.film を検査する

ローカルのアプリケーションのデフォルト認証情報(ADC)を構成する

Cloud Run、Google Kubernetes Engine(GKE)、Compute Engine で実行する場合は、java-alloydb-connector サービス アカウントをワークロードに直接アタッチします。ワークステーションでローカルに実行する場合は、サービス アカウントの権限を借用して、ADC がその ID のトークンを生成するようにします。

gcloud auth application-default login \
    --impersonate-service-account="java-alloydb-connector@${PROJECT_ID}.iam.gserviceaccount.com"

3. Plain JDBC と HikariCP を使用して接続する

本番環境レベルの Java アプリケーションには接続プールが不可欠であり、HikariCP は業界標準です。このステップでは、ソケットの作成を com.google.cloud.alloydb.SocketFactory に委任する、プレーンな JDBC + HikariCP アプリケーションをビルドします。

Maven プロジェクト(pom.xml)を作成する

PostgreSQL JDBC ドライバ(42.7.14)、AlloyDB Java コネクタ(1.4.0)、HikariCP(7.1.0)を含む pom.xml ファイルを使用して、新しいディレクトリ jdbc-app を作成します。

mkdir -p jdbc-app/src/main/java
cd jdbc-app

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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.example.alloydb</groupId>
    <artifactId>alloydb-jdbc-sample</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <exec.mainClass>AlloyDBConnectivity</exec.mainClass>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.7.14</version>
        </dependency>

        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>alloydb-jdbc-connector</artifactId>
            <version>1.4.0</version>
        </dependency>

        <dependency>
            <groupId>com.zaxxer</groupId>
            <artifactId>HikariCP</artifactId>
            <version>7.1.0</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>2.0.16</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.codehaus.mojo</groupId>
                <artifactId>exec-maven-plugin</artifactId>
                <version>3.5.0</version>
                <configuration>
                    <cleanupDaemonThreads>false</cleanupDaemonThreads>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

AlloyDBConnectivity.java を作成します

src/main/java/AlloyDBConnectivity.java を作成します(GitHub Gist で表示)。

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

public class AlloyDBConnectivity {
    // Retrieve configuration from environment variables
    private static final String ALLOYDB_INSTANCE_URI = System.getenv("ALLOYDB_INSTANCE_NAME"); // e.g., projects/<PROJECT_ID>/locations/<REGION>/clusters/<CLUSTER_ID>/instances/<INSTANCE_ID>
    private static final String ALLOYDB_DB_NAME = System.getenv("ALLOYDB_DB"); // e.g., "dvdrental"
    private static final String ALLOYDB_USER = System.getenv("ALLOYDB_USER"); // e.g., "java-alloydb-connector@<PROJECT_ID>.iam"
    private static final String ALLOYDB_PASS = System.getenv("ALLOYDB_PASS"); // Database password if not using IAM auth

    public static HikariDataSource createDataSource() {
        HikariConfig config = new HikariConfig();

        // The JDBC URL does not need a host or port. The SocketFactory will resolve the IP address.
        config.setJdbcUrl(String.format("jdbc:postgresql:///%s", ALLOYDB_DB_NAME));
        config.setUsername(ALLOYDB_USER);

        // Only set the password if you are NOT using IAM authentication.
        if (System.getenv("ALLOYDB_ENABLE_IAM_AUTH") == null || !System.getenv("ALLOYDB_ENABLE_IAM_AUTH").equalsIgnoreCase("true")) {
            config.setPassword(ALLOYDB_PASS);
        }

        // 1. Set the SocketFactory to the AlloyDB Connector's implementation.
        config.addDataSourceProperty("socketFactory", "com.google.cloud.alloydb.SocketFactory");

        // 2. Tell the connector which AlloyDB instance to connect to.
        config.addDataSourceProperty("alloydbInstanceName", ALLOYDB_INSTANCE_URI);

        // 3. (Recommended) Enable IAM database authentication.
        if (System.getenv("ALLOYDB_ENABLE_IAM_AUTH") != null && System.getenv("ALLOYDB_ENABLE_IAM_AUTH").equalsIgnoreCase("true")) {
            config.addDataSourceProperty("alloydbEnableIAMAuth", "true");
        }

        // 4. (Optional) Specify IP type (e.g., "PRIVATE", "PUBLIC", "PSC"). Defaults to PRIVATE.
        String ipType = System.getenv("ALLOYDB_IP_TYPE");
        if (ipType != null) {
            config.addDataSourceProperty("alloydbIpType", ipType);
        }

        // Baseline HikariCP settings
        config.setMaximumPoolSize(10);
        config.setMinimumIdle(2);
        config.setConnectionTimeout(30000); // 30 seconds
        config.setIdleTimeout(600000);      // 10 minutes
        config.setMaxLifetime(1800000);     // 30 minutes

        return new HikariDataSource(config);
    }

    public static void main(String[] args) {
        String sql = "SELECT title, release_year FROM public.film ORDER BY film_id LIMIT 5";

        try (HikariDataSource pool = createDataSource();
             Connection conn = pool.getConnection();
             PreparedStatement stmt = conn.prepareStatement(sql);
             ResultSet rs = stmt.executeQuery()) {
            System.out.println("Successfully connected to AlloyDB via IAM! Sample films:");
            while (rs.next()) {
                System.out.printf(" - %s (%d)%n", rs.getString("title"), rs.getInt("release_year"));
            }
        } catch (SQLException e) {
            System.err.println("Database connection failed: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

AlloyDB JDBC URL と HikariCP 構成の構造

プレーン JDBC アプリケーションを実行する

AlloyDB インスタンスの環境変数をエクスポートし(VPC の外部からパブリック IP 経由で接続する場合は ALLOYDB_IP_TYPE="PUBLIC" を設定し、VPC 内の場合は "PRIVATE" / "PSC" を設定)、アプリケーションを実行します。

export ALLOYDB_INSTANCE_NAME="projects/${PROJECT_ID}/locations/${REGION}/clusters/${CLUSTER_ID}/instances/${INSTANCE_ID}"
export ALLOYDB_DB="${DB_NAME}"
export ALLOYDB_USER="java-alloydb-connector@${PROJECT_ID}.iam"
export ALLOYDB_ENABLE_IAM_AUTH="true"
export ALLOYDB_IP_TYPE="PRIVATE" # Set to PUBLIC if connecting over Public IP from a local laptop

mvn compile exec:java

次のような出力が表示されます。

[AlloyDBConnectivity.main()] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
[AlloyDBConnectivity.main()] INFO com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@1998bf07
[AlloyDBConnectivity.main()] INFO com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
Successfully connected to AlloyDB via IAM! Sample films:
 - Academy Dinosaur (2006)
 - Ace Goldfinger (2006)
 - Adaptation Holes (2006)
 - Affair Prejudice (2006)
 - African Egg (2006)

プレーン JDBC と HikariCP のサンプルのターミナル出力

4. Spring Boot と接続する

Spring Boot は、アプリケーション プロパティから HikariCP 接続プールを自動的に構成することで、データベース接続を簡素化します。AlloyDB Java コネクタを統合する際に、カスタムの DataSource Bean コードは必要ありません。

Spring Boot プロジェクト(pom.xml)を作成する

新しいディレクトリ spring-boot-app を作成します。

cd ..
mkdir -p spring-boot-app/src/main/java/com/example/alloydb
mkdir -p spring-boot-app/src/main/resources
cd spring-boot-app

spring-boot-starter-jdbc(HikariCP を含む)、org.postgresql:postgresql、com.google.cloud:alloydb-jdbc-connector を使用して 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>4.0.5</version>
        <relativePath/>
    </parent>

    <groupId>com.example.alloydb</groupId>
    <artifactId>alloydb-spring-boot-sample</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>17</java.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <dependency>
            <groupId>org.postgresql</groupId>
            <artifactId>postgresql</artifactId>
            <version>42.7.14</version>
        </dependency>

        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>alloydb-jdbc-connector</artifactId>
            <version>1.4.0</version>
        </dependency>
    </dependencies>

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

application.properties または環境変数を構成する

接続 URL は src/main/resources/application.properties で構成できます。

# No host or port is needed; the SocketFactory handles it.
spring.datasource.url=jdbc:postgresql:///dvdrental?socketFactory=com.google.cloud.alloydb.SocketFactory&alloydbInstanceName=projects/<PROJECT_ID>/locations/<REGION>/clusters/<CLUSTER_ID>/instances/<INSTANCE_ID>&alloydbEnableIAMAuth=true
spring.datasource.username=java-alloydb-connector@<PROJECT_ID>.iam
# No password required when alloydbEnableIAMAuth is true

ソースファイルにプロジェクト ID やインスタンス名がまったく含まれないようにするには、application.properties を空のままにして、実行時に次の標準の Spring Boot 環境変数を指定します。

環境変数

値

SPRING_DATASOURCE_URL

jdbc:postgresql:///dvdrental?socketFactory=com.google.cloud.alloydb.SocketFactory&alloydbInstanceName=projects//locations//clusters//instances/&alloydbEnableIAMAuth=true

SPRING_DATASOURCE_USERNAME

java-alloydb-connector@.iam

AlloyDbTestApplication.java を作成します

src/main/java/com/example/alloydb/AlloyDbTestApplication.java を作成します(GitHub Gist で表示)。

package com.example.alloydb;

import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;

@SpringBootApplication
public class AlloyDbTestApplication {

    public static void main(String[] args) {
        System.exit(SpringApplication.exit(SpringApplication.run(AlloyDbTestApplication.class, args)));
    }

    @Bean
    CommandLineRunner testConnection(JdbcTemplate jdbcTemplate) {
        return args -> {
            String result = jdbcTemplate.queryForObject("SELECT 'Connection Successful!'", String.class);
            System.out.println(">>> ALLOYDB STATUS: " + result);
        };
    }
}

Spring Boot アプリケーションを実行する

環境変数をエクスポートし、mvn spring-boot:run を使用してアプリを実行します。

export SPRING_DATASOURCE_URL="jdbc:postgresql:///${DB_NAME}?socketFactory=com.google.cloud.alloydb.SocketFactory&alloydbInstanceName=projects/${PROJECT_ID}/locations/${REGION}/clusters/${CLUSTER_ID}/instances/${INSTANCE_ID}&alloydbEnableIAMAuth=true"
export SPRING_DATASOURCE_USERNAME="java-alloydb-connector@${PROJECT_ID}.iam"

mvn spring-boot:run

以下のように表示されます。

>>> ALLOYDB STATUS: Connection Successful!

Spring Boot の自動構成とライブ実行出力

5. Quarkus、Micronaut、GraalVM Native Image と接続する

AlloyDB Java コネクタは JDBC ドライバレベルで動作するため、クラウドネイティブの Java フレームワークを切り替えても、データベース トラフィックの保護方法や ID の管理方法は変わりません。Quarkus と Micronaut は、基盤となる JDBC ドライバをラップし、mTLS 暗号化、動的 IP 解決、IAM 認証を ADC 経由でコネクタに委任します。

クラウドネイティブ Java フレームワークと GraalVM ネイティブ イメージを AlloyDB で使用する

Quarkus の構成(Agroal を使用した application.properties)

Quarkus アプリケーション(quarkus-agroal と quarkus-jdbc-postgresql)で、com.google.cloud:alloydb-jdbc-connector:1.4.0 を依存関係に追加し、src/main/resources/application.properties の quarkus.datasource.jdbc.additional-jdbc-properties を介してコネクタ パラメータを渡します。

quarkus.datasource.db-kind=postgresql
quarkus.datasource.username=java-alloydb-connector@<PROJECT_ID>.iam
quarkus.datasource.jdbc.url=jdbc:postgresql:///dvdrental
quarkus.datasource.jdbc.additional-jdbc-properties.socketFactory=com.google.cloud.alloydb.SocketFactory
quarkus.datasource.jdbc.additional-jdbc-properties.alloydbInstanceName=projects/<PROJECT_ID>/locations/<REGION>/clusters/<CLUSTER_ID>/instances/<INSTANCE_ID>
quarkus.datasource.jdbc.additional-jdbc-properties.alloydbEnableIAMAuth=true

Micronaut の構成(HikariCP を使用した application.yml)

Micronaut アプリケーション(micronaut-jdbc-hikari)で、com.google.cloud:alloydb-jdbc-connector:1.4.0 を追加し、src/main/resources/application.yml を構成します。

datasources:
  default:
    url: jdbc:postgresql:///dvdrental?socketFactory=com.google.cloud.alloydb.SocketFactory&alloydbInstanceName=projects/<PROJECT_ID>/locations/<REGION>/clusters/<CLUSTER_ID>/instances/<INSTANCE_ID>&alloydbEnableIAMAuth=true
    username: java-alloydb-connector@<PROJECT_ID>.iam
    driver-class-name: org.postgresql.Driver

GraalVM ネイティブ イメージ用のコネクタを登録する

アプリケーションを GraalVM ネイティブ イメージ(Spring Boot 3+、Quarkus、Micronaut を使用)にコンパイルする際には、リフレクションという重要な詳細があります。

PostgreSQL JDBC ドライバは、リフレクションを使用してクラス名で com.google.cloud.alloydb.SocketFactory を動的にインスタンス化します。ネイティブ コンパイル中に GraalVM の静的分析でクラスが削除されないようにするには、クラスを明示的に登録します。

  • Spring Boot 3+: メイン アプリケーションまたは @Configuration クラスに @RegisterReflectionForBinding(com.google.cloud.alloydb.SocketFactory.class) を追加します。
    @SpringBootApplication
    @RegisterReflectionForBinding(com.google.cloud.alloydb.SocketFactory.class)
    public class AlloyDbTestApplication { ... }
    
  • Quarkus: メインクラスまたは CDI Bean に @RegisterForReflection(targets = com.google.cloud.alloydb.SocketFactory.class) を追加します。
    @QuarkusMain
    @RegisterForReflection(targets = com.google.cloud.alloydb.SocketFactory.class)
    public class QuarkusAlloyDbApp implements QuarkusApplication { ... }
    

6. IAM と接続に関する一般的な問題のトラブルシューティング

FATAL: password authentication failed for user エラーまたは AlloyDB IAM authentication failed エラーが発生した場合は、次の 4 つの領域を確認します。

AlloyDB IAM と接続のトラブルシューティング チートシート

1. サービス アカウントのデータベース ユーザー名から .gserviceaccount.com を削除する

IAM 認証エラーの最も一般的な原因は、サービス アカウントの完全なメールアドレスをデータベース ユーザー名として渡すことです。AlloyDB では、プリンシパル タイプに応じて IAM データベースのユーザー名の形式が異なります。

  • IAM サービス アカウントの場合(.gserviceaccount.com を削除): Google Cloud サービス アカウントのメールアドレスが java-alloydb-connector@.iam.gserviceaccount.com の場合は、.gserviceaccount.com サフィックスを削除し、JDBC / AlloyDB データベースのユーザー名を java-alloydb-connector@.iam に設定する必要があります。
  • IAM ユーザー アカウントまたはグループの場合(完全なメールアドレスを保持): Google Workspace または Cloud Identity のユーザーとして認証する場合は、完全なメールアドレスをそのまま使用します(例: )。

2. データベース ユーザーの作成方法を確認する

gcloud alloydb users create --type=IAM_BASED(またはコンソール / Terraform)でユーザーを登録しましたか?AlloyDB では GRANT alloydbiamuser がコントロール プレーンに制限されているため、未加工の SQL CREATE USER を使用してユーザーを作成しても、IAM 認証では機能しません。

3. 有効な ADC ID を確認する

Java プロセスが実行されている環境が、ターゲット IAM プリンシパルとして実際に認証されていることを確認します。

  • ローカル ワークステーション(サービス アカウントとして接続): gcloud auth application-default login --impersonate-service-account=java-alloydb-connector@.iam.gserviceaccount.com を実行して、ADC が個人のメールアドレスではなくサービス アカウントのトークンを生成するようにします。
  • Cloud Run / GKE: サービス アカウントがワークロードに接続され、roles/alloydb.client と roles/serviceusage.serviceUsageConsumer の両方を保持していることを確認します。

4. IAM の伝播とネットワーク ルーティングを考慮する

  • IAM の反映遅延: IAM ポリシー バインディングの反映には 60 ~ 120 秒かかることがあります。サービス アカウントまたはロール バインディングを作成したばかりの場合は、1 分ほど待ってからもう一度お試しください。
  • VPC ネットワーク アクセス: デフォルトでは、AlloyDB Java コネクタはインスタンスの PRIVATE IP に接続します。アプリケーションが Cloud Run で実行されている場合は、ダイレクト VPC 下り(外向き)を構成するか(以前のサーバーレス VPC アクセス コネクタよりもレイテンシとコストが低くなるため推奨)、Private Service Connect(PSC)経由で接続します。VPC 外のローカルマシンから接続する場合は、インスタンスでパブリック IP を有効にして alloydbIpType=PUBLIC を渡します。

7. クリーンアップ

Google Cloud アカウントに不要な課金が発生しないようにし、この Codelab で作成した IAM ID を削除するには、以下のリソースをクリーンアップします。

1. AlloyDB IAM データベース ユーザーとサービス アカウントを削除する

AlloyDB クラスタから IAM データベース ユーザーを削除し、サービス アカウントを削除します。

# Delete the IAM database user from AlloyDB
gcloud alloydb users delete "java-alloydb-connector@${PROJECT_ID}.iam" \
    --cluster="${CLUSTER_ID}" \
    --region="${REGION}" \
    --project="${PROJECT_ID}" \
    --quiet

# Remove IAM policy bindings
gcloud projects remove-iam-policy-binding "${PROJECT_ID}" \
    --member="serviceAccount:java-alloydb-connector@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/alloydb.client"

gcloud projects remove-iam-policy-binding "${PROJECT_ID}" \
    --member="serviceAccount:java-alloydb-connector@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role="roles/serviceusage.serviceUsageConsumer"

# Delete the Service Account
gcloud iam service-accounts delete \
    "java-alloydb-connector@${PROJECT_ID}.iam.gserviceaccount.com" \
    --project="${PROJECT_ID}" \
    --quiet

2. ローカルのアプリケーションのデフォルト認証情報をリセットする

ローカル ADC の権限借用を構成した場合は、ローカル認証情報をデフォルトのユーザー ID にリセットします。

gcloud auth application-default login

3. (省略可)AlloyDB クラスタを削除する

gcloud alloydb clusters delete "${CLUSTER_ID}" \
    --region="${REGION}" \
    --project="${PROJECT_ID}" \
    --force \
    --quiet

8. 完了

これで、この Codelab は完了です。Java から AlloyDB for PostgreSQL への安全なパスワードレス接続を確立できました。

達成したこと

  1. IAM データベース認証を構成: 最小権限のサービス アカウントを作成し、alloydb.iam_authentication=on を有効にして、AlloyDB クラスタに IAM ユーザーを登録し、PostgreSQL テーブル権限を付与しました。
  2. Plain JDBC と HikariCP で接続: HikariConfig を com.google.cloud.alloydb.SocketFactory で構成し、自動 mTLS 1.3 暗号化、IAM トークンの更新、動的 IP 解決を実現。
  3. 統合されたクラウドネイティブ フレームワーク: Spring Boot、Quarkus(Agroal)、Micronaut(HikariCP)を、カスタム接続プールのボイラープレートなしで構成。GraalVM Native Image のリフレクション ヒントも提供。
  4. IAM のトラブルシューティングを習得: ユーザー名の形式、ADC の権限借用、VPC ルーティングの問題を診断する方法を学習しました。

詳細