使用 IAM 資料庫驗證功能登入

本頁說明使用者和服務帳戶如何使用 Cloud SQL 身分與存取權管理資料庫驗證功能登入 Cloud SQL 資料庫。詳情請參閱「IAM 驗證」。

事前準備

使用自動 IAM 資料庫驗證功能登入

您可以設定 Cloud SQL 連接器,讓系統自動代表使用者或應用程式處理 Cloud SQL 執行個體的驗證作業。連接器包括 Cloud SQL Auth Proxy、Go 連接器、Java 連接器和 Python 連接器,皆支援自動 IAM 資料庫驗證。使用 Cloud SQL 連接器時,如果啟用自動 IAM 資料庫驗證功能,用來啟動連接器的 IAM 帳戶必須與資料庫驗證帳戶相同。

如要使用自動 IAM 資料庫驗證功能登入,請按照下列步驟操作:

Cloud SQL 驗證 Proxy

  1. 驗證 Google Cloud。

    User

    使用應用程式預設憑證 (ADC) 驗證 Google Cloud 。

    使用 gcloud auth application-default login 指令。詳情請參閱「設定應用程式預設憑證」。

    服務帳戶

    如要使用服務帳戶透過 ADC 進行驗證,您可以使用服務帳戶冒用或服務帳戶金鑰。 Google Cloud 如要使用服務帳戶冒用功能,請替換 SERVICE_ACCOUNT_EMAIL_ADDRESS,然後執行下列指令:

    gcloud auth application-default login --impersonate-service-account SERVICE_ACCOUNT_EMAIL_ADDRESS

    詳情請參閱「設定應用程式預設憑證」。

  2. 使用 --auto-iam-authn 標記啟動 Cloud SQL 驗證 Proxy。

    更改下列內容:

    • INSTANCE_CONNECTION_NAME:用於識別 Cloud SQL 執行個體的連線字串。如果您使用的是預設 PostgreSQL 通訊埠以外的通訊埠,請指定通訊埠編號。如要進一步瞭解如何尋找及建構這個字串,請參閱「驗證 Cloud SQL 驗證 Proxy 的選項」。
    ./cloud-sql-proxy --auto-iam-authn INSTANCE_CONNECTION_NAME

    如要進一步瞭解如何啟動 Proxy,請參閱「啟動 Cloud SQL 驗證 Proxy」。

  3. 準備好使用 Cloud SQL 驗證 Proxy 連線至執行個體時,請使用 psql 用戶端登入。

    更改下列內容:

    • HOSTNAME:Cloud SQL 驗證 Proxy 使用的 IP 位址。根據預設,Cloud SQL 驗證 Proxy 會使用 127.0.0.1 的本機位址,但您可以在啟動 Cloud SQL 驗證 Proxy 時指派其他 IP 位址。
    • USERNAME:對於 IAM,使用者名稱是使用者的完整電子郵件地址。如果是服務帳戶,則是服務帳戶的電子郵件地址,不含 .gserviceaccount.com 網域後置字串。
    • PORT_NUMBER:選用。如果您在執行個體連線字串中指定了其他通訊埠,請指定該通訊埠號碼。
    • DATABASE_NAME:要連線的資料庫名稱。

    執行下列指令:

    psql -h HOSTNAME \
     -U USERNAME \
     --port PORT_NUMBER \
     --dbname=DATABASE_NAME
     

    如要進一步瞭解如何連線至 Cloud SQL 驗證 Proxy,請參閱「連線至 psql 用戶端」一文。

Go

import (
	"context"
	"database/sql"
	"fmt"
	"log"
	"net"
	"os"

	"cloud.google.com/go/cloudsqlconn"
	"github.com/jackc/pgx/v5"
	"github.com/jackc/pgx/v5/stdlib"
)

func connectWithConnectorIAMAuthN() (*sql.DB, error) {
	mustGetenv := func(k string) string {
		v := os.Getenv(k)
		if v == "" {
			log.Fatalf("Warning: %s environment variable not set.", k)
		}
		return v
	}
	// Note: Saving credentials in environment variables is convenient, but not
	// secure - consider a more secure solution such as
	// Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
	// keep secrets safe.
	var (
		dbUser                 = mustGetenv("DB_IAM_USER")              // e.g. '[email protected]'
		dbName                 = mustGetenv("DB_NAME")                  // e.g. 'my-database'
		instanceConnectionName = mustGetenv("INSTANCE_CONNECTION_NAME") // e.g. 'project:region:instance'
		usePrivate             = os.Getenv("PRIVATE_IP")
	)

	// WithLazyRefresh() Option is used to perform refresh
	// when needed, rather than on a scheduled interval.
	// This is recommended for serverless environments to
	// avoid background refreshes from throttling CPU.
	d, err := cloudsqlconn.NewDialer(
		context.Background(),
		cloudsqlconn.WithIAMAuthN(),
		cloudsqlconn.WithLazyRefresh(),
	)
	if err != nil {
		return nil, fmt.Errorf("cloudsqlconn.NewDialer: %w", err)
	}
	var opts []cloudsqlconn.DialOption
	if usePrivate != "" {
		opts = append(opts, cloudsqlconn.WithPrivateIP())
	}

	dsn := fmt.Sprintf("user=%s database=%s", dbUser, dbName)
	config, err := pgx.ParseConfig(dsn)
	if err != nil {
		return nil, err
	}

	config.DialFunc = func(ctx context.Context, network, instance string) (net.Conn, error) {
		return d.Dial(ctx, instanceConnectionName, opts...)
	}
	dbURI := stdlib.RegisterConnConfig(config)
	dbPool, err := sql.Open("pgx", dbURI)
	if err != nil {
		return nil, fmt.Errorf("sql.Open: %w", err)
	}
	return dbPool, nil
}

Java JDBC

import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import javax.sql.DataSource;

public class ConnectorIamAuthnConnectionPoolFactory extends ConnectionPoolFactory {

  // Note: Saving credentials in environment variables is convenient, but not
  // secure - consider a more secure solution such as
  // Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
  // keep secrets safe.
  private static final String INSTANCE_CONNECTION_NAME =
      System.getenv("INSTANCE_CONNECTION_NAME");
  private static final String DB_IAM_USER = System.getenv("DB_IAM_USER");
  private static final String DB_NAME = System.getenv("DB_NAME");

  public static DataSource createConnectionPool() {
    // The configuration object specifies behaviors for the connection pool.
    HikariConfig config = new HikariConfig();

    // The following URL is equivalent to setting the config options below:
    // jdbc:postgresql:///<DB_NAME>?cloudSqlInstance=<INSTANCE_CONNECTION_NAME>&
    // socketFactory=com.google.cloud.sql.postgres.SocketFactory&user=<DB_IAM_USER>&
    // password=password
    // See the link below for more info on building a JDBC URL for the Cloud SQL JDBC Socket Factory
    // https://github.com/GoogleCloudPlatform/cloud-sql-jdbc-socket-factory#creating-the-jdbc-url

    // Configure which instance and what database to connect with.
    config.setJdbcUrl(String.format("jdbc:postgresql:///%s", DB_NAME));

    config.addDataSourceProperty("socketFactory", "com.google.cloud.sql.postgres.SocketFactory");
    config.addDataSourceProperty("cloudSqlInstance", INSTANCE_CONNECTION_NAME);

    // If connecting using automatic database authentication, follow the instructions for
    // connecting using the connector, but set the DB_IAM_USER value to an IAM user or
    // service account that has been given access to the database.
    // See https://cloud.google.com/sql/docs/postgres/iam-logins for more details.
    config.addDataSourceProperty("enableIamAuth", "true");
    config.addDataSourceProperty("user", DB_IAM_USER);
    // Password must be set to a nonempty value to bypass driver validation errors.
    config.addDataSourceProperty("password", "password");
    // Explicitly set sslmode to disable to prevent driver from hanging.
    // The Java Connector will handle SSL so it is unneccesary to enable it at the driver level.
    config.addDataSourceProperty("sslmode", "disable");

    // cloudSqlRefreshStrategy set to "lazy" is used to perform a
    // refresh when needed, rather than on a scheduled interval.
    // This is recommended for serverless environments to
    // avoid background refreshes from throttling CPU.
    config.addDataSourceProperty("cloudSqlRefreshStrategy", "lazy");

    // ... Specify additional connection properties here.
    // ...

    // Initialize the connection pool using the configuration object.
    return new HikariDataSource(config);
  }
}

Java R2DBC

private static final String CONNECTION_NAME = System.getenv("POSTGRES_CONNECTION_NAME");
private static final String DB_NAME = System.getenv("POSTGRES_DB");
private static final String DB_USER = System.getenv("POSTGRES_IAM_USER");
private static final String IP_TYPE =
    System.getenv("IP_TYPE") == null ? "PUBLIC" : System.getenv("IP_TYPE");
  // Set up ConnectionFactoryOptions
  ConnectionFactoryOptions options =
      ConnectionFactoryOptions.builder()
          .option(DRIVER, "gcp")
          .option(PROTOCOL, "postgresql")
          // Password must be set to a nonempty value to bypass driver validation errors
          .option(PASSWORD, "password")
          .option(USER, DB_USER)
          .option(DATABASE, DB_NAME)
          .option(HOST, CONNECTION_NAME)
          .option(IP_TYPES, IP_TYPE)
          .option(ENABLE_IAM_AUTH, true)
          .build();

  // Initialize connection pool
  ConnectionFactory connectionFactory = ConnectionFactories.get(options);
  ConnectionPoolConfiguration configuration =
      ConnectionPoolConfiguration.builder(connectionFactory).build();

  this.connectionPool = new ConnectionPool(configuration);

Python

import os

from google.cloud.sql.connector import Connector, IPTypes
import pg8000

import sqlalchemy


def connect_with_connector_auto_iam_authn() -> sqlalchemy.engine.base.Engine:
    """
    Initializes a connection pool for a Cloud SQL instance of Postgres.

    Uses the Cloud SQL Python Connector with Automatic IAM Database Authentication.
    """
    # Note: Saving credentials in environment variables is convenient, but not
    # secure - consider a more secure solution such as
    # Cloud Secret Manager (https://cloud.google.com/secret-manager) to help
    # keep secrets safe.
    instance_connection_name = os.environ[
        "INSTANCE_CONNECTION_NAME"
    ]  # e.g. 'project:region:instance'
    db_iam_user = os.environ["DB_IAM_USER"]  # e.g. '[email protected]'
    db_name = os.environ["DB_NAME"]  # e.g. 'my-database'

    ip_type = IPTypes.PRIVATE if os.environ.get("PRIVATE_IP") else IPTypes.PUBLIC

    # initialize Cloud SQL Python Connector object
    connector = Connector(refresh_strategy="LAZY")

    def getconn() -> pg8000.dbapi.Connection:
        conn: pg8000.dbapi.Connection = connector.connect(
            instance_connection_name,
            "pg8000",
            user=db_iam_user,
            db=db_name,
            enable_iam_auth=True,
            ip_type=ip_type,
        )
        return conn

    # The Cloud SQL Python Connector can be used with SQLAlchemy
    # using the 'creator' argument to 'create_engine'
    pool = sqlalchemy.create_engine(
        "postgresql+pg8000://",
        creator=getconn,
        # ...
    )
    return pool

使用手動 IAM 資料庫驗證功能登入

使用者或應用程式可以使用 IAM 驗證資料庫,方法是手動向 Google Cloud 要求存取權杖,然後將其提交給資料庫。您可以使用 gcloud CLI,透過 Cloud SQL Admin API 範圍明確要求 OAuth 2.0 權杖,用於登入資料庫。當您以手動 IAM 資料庫驗證功能登入資料庫使用者時,請使用電子郵件地址做為使用者名稱,並將存取權存取權杖做為密碼。您可以使用這個方法,直接連線至資料庫,也可以使用 Cloud SQL 連接器。

在這個程序中,您會驗證 Google Cloud、要求存取權杖,然後將權杖傳遞為 IAM 資料庫使用者的密碼,以便連線至資料庫。請按照下列步驟,在不使用 Cloud SQL 驗證 Proxy 的情況下連線。

在這些步驟中,您必須:

  • 如果您要連線至具有公開 IP 的執行個體,請授權外部存取該執行個體。詳情請參閱「授權電腦的 IP 位址使用公開 IP」。
  • 如果您要連線至私人 IP 的執行個體,請在虛擬私有雲 (VPC) 網路中執行指令。
  • 使用 gcloud sql generate-login-token 指令產生驗證權杖。
  • 如要使用手動 IAM 資料庫驗證功能登入,請按照下列步驟操作:

    gcloud

    1. 驗證 Google Cloud。

      User

      使用 gcloud auth login 向 IAM 進行驗證。詳情請參閱「使用使用者帳戶授權」。

      服務帳戶

      使用 gcloud auth activate-service-account 向 IAM 進行驗證。詳情請參閱「使用服務帳戶授權」。

    2. 要求存取權憑證,並使用用戶端登入。

      更改下列內容:

      • HOSTNAME:執行個體的 IP 位址,可能是公開 IP 位址或私人 IP 位址。
      • USERNAME:對於 IAM,使用者名稱是使用者的完整電子郵件地址。如果是服務帳戶,則是服務帳戶的電子郵件地址,不含 .gserviceaccount.com 網域後置字串。
      • DATABASE_NAME:要連線的資料庫名稱。

       PGPASSWORD=`gcloud sql generate-login-token` \
       psql "sslmode=require \
       hostaddr=HOSTNAME \
       user=USERNAME \
       dbname=DATABASE_NAME" \
       --no-password
       

      如果 Cloud SQL 執行個體上的 ssl_mode 已設為 TRUSTED_CLIENT_CERTIFICATE_REQUIRED,建議您使用自動 IAM 資料庫驗證功能登入,以便強制執行用戶端身分驗證。

    後續步驟