使用 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. 'service-account-name@project-id.iam'
		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. 'sa-name@project-id.iam'
    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 資料庫驗證功能登入,以便強制執行用戶端身分驗證。

    後續步驟