כניסה באמצעות אימות מסד נתונים של 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:

שרת proxy ל-Cloud SQL Auth

  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. מריצים את שרת ה-proxy ל-Cloud SQL Auth עם הדגל --auto-iam-authn. מחליפים את INSTANCE_CONNECTION_NAME במחרוזת החיבור שמשמשת לזיהוי מכונת Cloud SQL. אם משתמשים ביציאה שאינה יציאת ברירת המחדל של MySQL, צריך לציין את מספר היציאה. מידע נוסף על איתור המחרוזת הזו ויצירתה זמין במאמר אפשרויות לאימות שרת ה-proxy ל-Cloud SQL Auth.

    ./cloud-sql-proxy --auto-iam-authn INSTANCE_CONNECTION_NAME

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

  3. כשמוכנים להתחבר למכונה באמצעות שרת proxy ל-Cloud SQL Auth, מתחברים באמצעות לקוח mysql. מחליפים את מה שכתוב בשדות הבאים:

    • HOSTNAME: כתובת ה-IP שבה נעשה שימוש על ידי שרת proxy ל-Cloud SQL Auth. כברירת מחדל, שרת proxy ל-Cloud SQL Auth משתמש בכתובת localhost ‏127.0.0.1, אבל אפשר להקצות כתובת IP אחרת כשמפעילים את שרת proxy ל-Cloud SQL Auth.
    • USERNAME: בחשבון משתמש ב-IAM, זו כתובת האימייל של המשתמש, בלי הסמל @ או שם הדומיין. לדוגמה, אם כתובת האימייל היא test-user@example.com, מזינים test-user. בחשבון שירות, זו כתובת האימייל של חשבון השירות בלי הסיומת @project-id.s3ns.iam.gserviceaccount.com.
    • PORT_NUMBER: אופציונלי. אם ציינתם יציאה אחרת במחרוזת החיבור של המופע, צריך לציין את מספר היציאה הזה.

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

    mysql --host=HOSTNAME \
    --user=USERNAME \
    --port=PORT_NUMBER

    מידע נוסף על חיבור לשרת proxy ל-Cloud SQL Auth זמין במאמר בנושא חיבור באמצעות לקוח mysql.

המשך

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

	"cloud.google.com/go/cloudsqlconn"
	"github.com/go-sql-driver/mysql"
)

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'
		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())
	}
	mysql.RegisterDialContext("cloudsqlconn",
		func(ctx context.Context, addr string) (net.Conn, error) {
			return d.Dial(ctx, instanceConnectionName, opts...)
		})

	dbURI := fmt.Sprintf("%s:empty@cloudsqlconn(localhost:3306)/%s?parseTime=true",
		dbUser, dbName)

	dbPool, err := sql.Open("mysql", 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 INSTANCE_UNIX_SOCKET = System.getenv("INSTANCE_UNIX_SOCKET");
  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:mysql:///<DB_NAME>?cloudSqlInstance=<INSTANCE_CONNECTION_NAME>&
    // socketFactory=com.google.cloud.sql.mysql.SocketFactory&user=<DB_USER>&password=<DB_PASS>
    // 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 user to connect with.
    config.setJdbcUrl(String.format("jdbc:mysql:///%s", DB_NAME));

    config.addDataSourceProperty("socketFactory", "com.google.cloud.sql.mysql.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);
    // 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

// Set up ConnectionFactoryOptions
ConnectionFactoryOptions options =
    ConnectionFactoryOptions.builder()
        .option(DRIVER, "gcp")
        .option(PROTOCOL, "mysql")
        .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 mysql = require('mysql2/promise');
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 a connection pool for a Cloud SQL instance
// of MySQL 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 = {
    ...clientOpts,
    user: process.env.IAM_DB_USER, // e.g. 'service-account-name'
    database: process.env.DB_NAME, // e.g. 'my-database'
    // ... Specify additional properties here.
    ...config,
  };
  // Establish a connection to the database.
  return mysql.createPool(dbConfig);
};

Python

import os

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

import sqlalchemy


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

    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. 'service-account-name'
    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() -> pymysql.connections.Connection:
        conn: pymysql.connections.Connection = connector.connect(
            instance_connection_name,
            "pymysql",
            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(
        "mysql+pymysql://",
        creator=getconn,
        # ...
    )
    return pool

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

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

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

בשלבים האלה, צריך:

כדי להיכנס באמצעות אימות ידני של מסד נתונים של 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, זו כתובת האימייל של המשתמש, בלי הסמל @ או שם הדומיין. לדוגמה, אם כתובת האימייל היא test-user@example.com, מזינים test-user. בחשבון שירות, זו כתובת האימייל של חשבון השירות בלי הסיומת @project-id.s3ns.iam.gserviceaccount.com.

     export MYSQL_PWD=`gcloud sql generate-login-token` \
     mysql --enable-cleartext-plugin \
     --ssl-mode=REQUIRED \
     --host=HOSTNAME \
     --user=USERNAME
     

    אם ssl_mode במכונת Cloud SQL מוגדר ל-TRUSTED_CLIENT_CERTIFICATE_REQUIRED, צריך לכלול אישור לקוח ומפתח לקוח כשמתחברים. בנוסף, כדי לאפשר ללקוח לאמת את זהות השרת לצורך אימות הדדי, צריך לציין את אישור השרת server-ca.pem. לדוגמה:

     export MYSQL_PWD=`gcloud sql generate-login-token` \
     mysql --enable-cleartext-plugin \
     --ssl-mode=VERIFY_CA \
     --ssl-ca=server-ca.pem \
     --ssl-cert=client-cert.pem \
     --ssl-key=client-key.pem \
     --host=HOSTNAME \
     --user=USERNAME
     

    מידע על יצירת אישור ומפתח לקוח מופיע במאמר בנושא אישורי לקוח.

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