כניסה באמצעות אימות מסד נתונים של IAM

בדף הזה מוסבר איך משתמשים וחשבונות שירות יכולים להתחבר למסדי נתונים של Cloud SQL באמצעות אימות של מסד נתונים ב-Cloud SQL IAM. מידע נוסף מופיע במאמר אימות IAM.

לפני שמתחילים

התחברות באמצעות אימות אוטומטי של מסד נתונים ב-IAM

אתם יכולים להגדיר מחבר ל-Cloud SQL שיטפל באופן אוטומטי באימות למכונה של Cloud SQL בשם משתמש או אפליקציה. המחברים כוללים את Cloud SQL Auth Proxy, מחבר Go, מחבר Java ומחבר Python, וכולם תומכים באימות אוטומטי של מסד נתונים ב-IAM. כשמשתמשים במחבר של Cloud SQL עם אימות אוטומטי של מסד נתונים ב-IAM, חשבון ה-IAM שבו משתמשים כדי להפעיל את המחבר חייב להיות אותו חשבון שמאמת את מסד הנתונים.

כדי להתחבר באמצעות אימות אוטומטי של מסד נתונים ב-IAM:

Cloud SQL Auth Proxy

  1. מבצעים אימות ב- Cloud de Confiance by S3NS.

    משתמש

    אימות ב- Cloud de Confiance by S3NS באמצעות Application Default Credentials ‏(ADC).

    משתמשים בפקודה gcloud auth application-default login. מידע נוסף זמין במאמר הגדרת Application Default Credentials.

    חשבון שירות

    כדי לבצע אימות ב- Cloud de Confiance by S3NS באמצעות ADC עם חשבון שירות, אתם יכולים להתחזות לחשבון שירות או להשתמש במפתח לחשבון שירות. כדי להשתמש בהתחזות לחשבון שירות, מחליפים את SERVICE_ACCOUNT_EMAIL_ADDRESS ומריצים את הפקודה הבאה:

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

    מידע נוסף זמין במאמר הגדרת Application Default Credentials.

  2. מפעילים את Cloud SQL Auth Proxy עם הדגל --auto-iam-authn.

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫INSTANCE_CONNECTION_NAME: מחרוזת החיבור לזיהוי מכונה של Cloud SQL. אם אתם משתמשים ביציאה אחרת מיציאת ברירת המחדל של PostgreSQL, ציינו את מספר היציאה. למידע נוסף על איך למצוא וליצור את המחרוזת הזו, ראו אפשרויות לאימות של Cloud SQL Auth Proxy.
    ./cloud-sql-proxy --auto-iam-authn INSTANCE_CONNECTION_NAME

    מידע נוסף על הפעלת שרת ה-proxy זמין במאמר הפעלת Cloud SQL Auth Proxy.

  3. כשתהיו מוכנים להתחבר למכונה באמצעות Cloud SQL Auth Proxy, התחברו באמצעות הלקוח psql.

    מחליפים את מה שכתוב בשדות הבאים:

    • ‫HOSTNAME: כתובת ה-IP שמשמשת את Cloud SQL Auth Proxy. כברירת מחדל, Cloud SQL Auth Proxy משתמש בכתובת המארח המקומי 127.0.0.1, אבל אפשר להקצות כתובת IP אחרת כשמפעילים את Cloud SQL Auth Proxy.
    • ‫USERNAME: ב-IAM, שם המשתמש הוא כתובת האימייל המלאה של המשתמש. בחשבון שירות, זהו האימייל של חשבון השירות בלי סיומת אתר .s3ns-system.iam.gserviceaccount.com.
    • ‫PORT_NUMBER: אופציונלי. אם ציינתם יציאה אחרת במחרוזת החיבור של המכונה, צריך לציין את מספר היציאה הזו.
    • ‫DATABASE_NAME: השם של מסד הנתונים שאליו רוצים להתחבר.

    מריצים את הפקודה הבאה:

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

    למידע נוסף על התחברות ל-Cloud SQL Auth Proxy, קראו את המאמר התחברות באמצעות לקוח psql.

המשך

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");
  System.out.println("Using IAM user: " + DB_USER);
  // 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(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);

Node.js

const Knex = require('knex');
const {Connector} = require('@google-cloud/cloud-sql-connector');

// In case the PRIVATE_IP environment variable is defined then we set
// the ipType=PRIVATE for the new connector instance, otherwise defaults
// to public ip type.
const getIpType = () =>
  process.env.PRIVATE_IP === '1' || process.env.PRIVATE_IP === 'true'
    ? 'PRIVATE'
    : 'PUBLIC';

// connectWithConnectorAutoIAMAuthn initializes connection pool for a Cloud SQL instance
// of Postgres using the Cloud SQL Node.js Connector.
const connectWithConnectorAutoIAMAuthn = async config => {
  // 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.
  const connector = new Connector();
  const clientOpts = await connector.getOptions({
    instanceConnectionName: process.env.INSTANCE_CONNECTION_NAME,
    ipType: getIpType(),
    authType: 'IAM',
  });
  const dbConfig = {
    client: 'pg',
    connection: {
      ...clientOpts,
      user: process.env.IAM_DB_USER, // e.g. 'sa-name@project-id.iam'
      database: process.env.DB_NAME, // e.g. 'my-database'
    },
    // ... Specify additional properties here.
    ...config,
  };
  // Establish a connection to the database.
  return Knex(dbConfig);
};

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, על ידי בקשה ידנית של אסימון גישה מ- Cloud de Confiance by S3NS והצגתו למסד הנתונים. באמצעות ה-CLI של gcloud, אתם יכולים לבקש באופן מפורש אסימון OAuth 2.0 עם היקף ההרשאות של Cloud SQL Admin API שמשמש להתחברות למסד הנתונים. כשאתם מתחברים כמשתמשים במסד הנתונים עם אימות ידני של IAM, אתם משתמשים בכתובת האימייל שלכם כשם המשתמש ובטוקן הגישה כסיסמה. אתם יכולים להשתמש בשיטה הזו עם חיבור ישיר למסד הנתונים או עם מחבר של Cloud SQL.

במהלך הזה, אתם מאמתים את Cloud de Confiance by S3NS, מבקשים אסימון גישה ואז מתחברים למסד הנתונים על ידי העברת האסימון כסיסמה למשתמש של מסד הנתונים ב-IAM. כדי להתחבר בלי Cloud SQL Auth Proxy, צריך לפעול לפי השלבים הבאים.

כדי לבצע את השלבים האלה, צריך:

  • אם אתם מתחברים למכונה עם כתובת IP ציבורית, צריך לאשר גישה חיצונית למכונה. למידע נוסף, ראו אישור כתובת ה-IP של המכונה לכתובת IP ציבורית.
  • אם אתם מתחברים למכונה עם כתובת IP פרטית, צריך להריץ את הפקודה ברשת של הענן הווירטואלי הפרטי (VPC).
  • משתמשים בפקודה gcloud sql generate-login-token כדי ליצור את אסימון האימות.
  • כדי להתחבר באמצעות אימות ידני של מסד נתונים ב-IAM:

    gcloud

    1. מבצעים אימות ב- Cloud de Confiance by S3NS.

      משתמש

      מאמתים את IAM באמצעות gcloud auth login. מידע נוסף זמין במאמר אימות ל-CLI של gcloud.

      חשבון שירות

      מאמתים את IAM באמצעות gcloud auth activate-service-account. למידע נוסף, קראו את המאמר אימות ל-CLI של gcloud.

    2. מבקשים את טוקן הגישה ומתחברים באמצעות לקוח.

      מחליפים את מה שכתוב בשדות הבאים:

      • ‫HOSTNAME: כתובת ה-IP של המכונה, כתובת IP ציבורית או כתובת IP פרטית.
      • ‫USERNAME: ב-IAM, שם המשתמש הוא כתובת האימייל המלאה של המשתמש. בחשבון שירות, זהו האימייל של חשבון השירות בלי סיומת אתר .s3ns-system.iam.gserviceaccount.com.
      • ‫DATABASE_NAME: השם של מסד הנתונים שאליו רוצים להתחבר.

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

      אם הדגל ssl_mode במכונה של Cloud SQL מוגדר לערך TRUSTED_CLIENT_CERTIFICATE_REQUIRED, מומלץ להתחבר באמצעות אימות אוטומטי של מסד הנתונים ב-IAM כדי לאכוף את אימות הזהות של הלקוח.

    המאמרים הבאים