使用 IAM 身份验证将 Java 应用连接到 AlloyDB for PostgreSQL

1. 准备工作

Java 和 AlloyDB:简单、安全的连接

AlloyDB for PostgreSQL 是 Google Cloud 的全托管式 PostgreSQL 兼容数据库服务,适用于要求严苛的企业工作负载。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 数据库身份验证。
  • 向 IAM 主账号授予最小权限的 PostgreSQL 架构和表权限。
  • 使用 AlloyDB SocketFactory,通过普通 JDBC 和 HikariCP 配置生产级 DataSource。
  • 在 Spring Boot、Quarkus 和 Micronaut 应用中集成 AlloyDB Java 连接器。
  • 注册 AlloyDB SocketFactory 以进行 GraalVM 原生映像编译,并排查常见的 IAM 身份验证问题。

所需条件

  • 一个已启用结算功能且具有活跃 AlloyDB 集群和主实例的 Google Cloud 项目(请参阅 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 从 VPC 外部连接,请设置 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 或环境变量

您可以在 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 原生映像连接器

将应用编译为 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 秒才能传播。如果您刚刚创建了服务账号或角色绑定,请稍等片刻,然后重试。
  • VPC 网络访问权限:默认情况下,AlloyDB Java 连接器会连接到实例的 PRIVATE IP。如果您的应用在 Cloud Run 上运行,请配置直接 VPC 出站流量(与旧版无服务器 VPC 访问通道连接器相比,建议使用此选项,以降低延迟时间和费用),或通过 Private Service Connect (PSC) 进行连接。如果从 VPC 外部的本地机器进行连接,请在实例上启用公共 IP 并传递 alloydbIpType=PUBLIC。

7. 清理

为避免您的 Google Cloud 账号产生不必要的费用,并移除在此 Codelab 期间创建的 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. 恭喜

您已完成此 Codelab,并建立了从 Java 到 AlloyDB for PostgreSQL 的安全无密码连接!

学习成果

  1. 配置了 IAM 数据库身份验证:创建了最小权限服务账号,启用了 alloydb.iam_authentication=on,在 AlloyDB 集群上注册了 IAM 用户,并授予了 PostgreSQL 表权限。
  2. 使用纯 JDBC 和 HikariCP 连接:使用 com.google.cloud.alloydb.SocketFactory 配置了 HikariConfig,以实现自动 mTLS 1.3 加密、IAM 令牌刷新和动态 IP 解析。
  3. 集成的云原生框架:配置了 Spring Boot、Quarkus (Agroal) 和 Micronaut (HikariCP),无需自定义连接池样板,并为 GraalVM 原生映像提供了反射提示。
  4. 掌握了 IAM 问题排查:学会了如何诊断用户名格式、ADC 模拟和 VPC 路由问题。

了解详情