使用 IAM 驗證機制,將 Java 應用程式連線至 AlloyDB for PostgreSQL

1. 事前準備

Java 和 AlloyDB:簡單、安全的連線

AlloyDB for PostgreSQL 是與 PostgreSQL 相容的全代管 Google Cloud 資料庫服務,專為嚴苛的企業工作負載打造。AlloyDB Java 連接器 (alloydb-jdbc-connector) 是超越標準 JDBC 驅動程式的用戶端程式庫,可讓您安全有效率地將 Java 應用程式連結至 AlloyDB。

AlloyDB Java 連接器的神奇之處

alloydb-jdbc-connector 是標準 PostgreSQL JDBC 驅動程式 (org.postgresql:postgresql) 的智慧型SocketFactory,可抽象化安全資料庫連線的建立作業,讓您專注於應用程式邏輯,而非網路安全或憑證輪換:

  • mTLS 1.3 加密:自動在 JVM 和 AlloyDB 執行個體之間建立相互驗證的 TLS 1.3 連線,您不必手動管理 SSL/TLS 用戶端憑證。
  • 以 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 角色。

學習內容

  • 設定 AlloyDB 執行個體和服務帳戶,以便使用無密碼 IAM 資料庫驗證。
  • 將最小權限的 PostgreSQL 結構定義和資料表權限,授予 IAM 主體。
  • 使用 AlloyDB SocketFactory,透過純 JDBC 和 HikariCP 設定正式環境等級的 DataSource。
  • 在 Spring Boot、Quarkus 和 Micronaut 應用程式中整合 AlloyDB Java 連接器。
  • 註冊 AlloyDB SocketFactory,以便編譯 GraalVM 原生映像檔,並排解常見的 IAM 驗證問題。

軟硬體需求

  • 已啟用計費功能的 Google Cloud 專案,以及運作中的 AlloyDB 叢集和主要執行個體 (請參閱 AlloyDB 叢集建立指南,或在兩秒內啟動 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 程式碼前,您需要設定 AlloyDB 執行個體,使其接受 IAM 權杖,並建立應用程式在三個層級 (Google Cloud IAM、AlloyDB 控制層和 PostgreSQL 引擎) 使用的 IAM 身分。

AlloyDB IAM 資料庫驗證的三層式設定

設定環境變數

在終端機中,匯出與 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 應用程式的身分:

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

將 AlloyDB Java 連接器所需的兩個 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 Rental 範例資料庫):

-- 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 結構定義,並驗證範例資料列:

在 AlloyDB Studio 授予 IAM 權限及檢查 public.film

設定本機應用程式預設憑證 (ADC)

在 Cloud Run、Google Kubernetes Engine (GKE) 或 Compute Engine 執行時,請將 java-alloydb-connector 服務帳戶直接附加至工作負載。在本機工作站執行時,請模擬服務帳戶,讓 ADC 為該身分產生權杖:

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

3. 使用純 JDBC 和 HikariCP 連線

對任何正式環境等級的 Java 應用程式來說,連線集區都不可或缺,而 HikariCP 是業界標準。在這個步驟中,您將建構一個簡單的 JDBC + HikariCP 應用程式,將通訊端建立作業委派給 com.google.cloud.alloydb.SocketFactory。

建立 Maven 專案 (pom.xml)

建立新目錄 jdbc-app,並在 pom.xml 檔案中加入 PostgreSQL JDBC 驅動程式 (42.7.14)、AlloyDB Java 連接器 (1.4.0) 和 HikariCP (7.1.0):

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 網址和 HikariCP 設定剖析

執行純 JDBC 應用程式

匯出 AlloyDB 執行個體的環境變數 (如果從虛擬私有雲外部透過公開 IP 連線,請設定 ALLOYDB_IP_TYPE="PUBLIC";如果是在虛擬私有雲內部,請設定 "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 或環境變數

您可以在 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 原生映像檔連結

AlloyDB Java 連接器是在 JDBC 驅動程式層級運作,因此切換雲端原生 Java 架構,不會影響保護資料庫流量或管理身分的方式。Quarkus 和 Micronaut 都會包裝基礎 JDBC 驅動程式,並透過 ADC 將 mTLS 加密、動態 IP 解析和 IAM 驗證委派給連接器。

雲端原生 Java 架構和 GraalVM 原生映像檔與 AlloyDB

Quarkus 設定 (application.properties 搭配 Agroal)

在 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 設定 (application.yml 搭配 HikariCP)

在 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 Native Image 連接器

將應用程式編譯成 GraalVM 原生映像檔 (使用 Spring Boot 3+、Quarkus 或 Micronaut) 時,有一個重要細節:反射。

PostgreSQL JDBC 驅動程式會使用反射,依類別名稱動態例項化 com.google.cloud.alloydb.SocketFactory。為避免 GraalVM 的靜態分析在原生編譯期間移除類別,請明確註冊:

  • Spring Boot 3+:將 @RegisterReflectionForBinding(com.google.cloud.alloydb.SocketFactory.class) 新增至主要應用程式或 @Configuration 類別:
    @SpringBootApplication
    @RegisterReflectionForBinding(com.google.cloud.alloydb.SocketFactory.class)
    public class AlloyDbTestApplication { ... }
    
  • Quarkus:將 @RegisterForReflection(targets = com.google.cloud.alloydb.SocketFactory.class) 新增至主要類別或 CDI Bean:
    @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 錯誤,請檢查下列四個部分:

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) 註冊使用者?使用原始 SQL CREATE USER 建立使用者,無法用於 IAM 驗證,因為 AlloyDB 會將 GRANT alloydbiamuser 限制在控制層。

3. 驗證有效的 ADC 身分

確認執行 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 秒才會生效。如果您才剛建立服務帳戶或角色繫結,請稍候再試。
  • 虛擬私有雲網路存取權:根據預設,AlloyDB Java 連接器會連線至執行個體的PRIVATE IP。如果應用程式在 Cloud Run 執行,請設定直連虛擬私有雲輸出 (建議做法,延遲時間和費用比舊版無伺服器 VPC 存取連接器低),或透過 Private Service Connect (PSC) 連線。如果是從虛擬私有雲以外的本機電腦連線,請在執行個體啟用公開 IP,並傳遞 alloydbIpType=PUBLIC。

7. 清除

為避免 Google Cloud 帳戶產生不必要的費用,並移除在本程式碼實驗室建立的 IAM 身分,請清除下列資源。

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 模擬功能,請將本機憑證重設回預設使用者身分:

gcloud auth application-default login

3. (選用) 刪除 AlloyDB 叢集

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

8. 恭喜

您已完成程式碼實驗室,並建立從 Java 到 AlloyDB for PostgreSQL 的安全無密碼連線!

學習成果

  1. 設定 IAM 資料庫驗證:建立最小權限服務帳戶、啟用 alloydb.iam_authentication=on、在 AlloyDB 叢集註冊 IAM 使用者,並授予 PostgreSQL 資料表權限。
  2. 使用純 JDBC 和 HikariCP 連線:設定 HikariConfig 搭配 com.google.cloud.alloydb.SocketFactory,自動執行 mTLS 1.3 加密、IAM 權杖重新整理和動態 IP 解析。
  3. 整合雲端原生架構:設定 Spring Boot、Quarkus (Agroal) 和 Micronaut (HikariCP),不需自訂連線集區樣板,並提供 GraalVM 原生映像檔的反射提示。
  4. 掌握 IAM 疑難排解技巧:瞭解如何診斷使用者名稱格式、ADC 模擬和虛擬私有雲路由問題。

瞭解詳情