חיבור באמצעות מחברי שפה של Cloud SQL

המחברים של Cloud SQL הם ספריות שמספקות הצפנה ואימות שמבוסס על ניהול זהויות והרשאות גישה (IAM) כשמתחברים למכונה של Cloud SQL. הם לא יכולים לספק נתיב רשת למכונה של Cloud SQL אם הוא לא קיים.

אפשר להתחבר למכונה של Cloud SQL גם בדרכים אחרות, כמו שימוש בלקוח של מסד נתונים או ב-Cloud SQL Auth Proxy. למידע נוסף על התחברות למכונה של Cloud SQL, ראו מידע על אפשרויות החיבור.

בדף הזה נסביר על המחברים הבאים של Cloud SQL:

יתרונות

השימוש במחבר של Cloud SQL מספק את היתרונות הבאים:

  • הרשאת IAM: משתמשת בהרשאות IAM כדי לקבוע מי או מה יכולים להתחבר למכונות Cloud SQL.
  • נוחות: לא צריך לנהל אישורי SSL, להגדיר כללים של חומת אש או להפעיל רשתות מורשות.
  • אימות IAM של מסד נתונים: תמיכה בתכונה אימות IAM אוטומטי של מסד נתונים ב-Cloud SQL.

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

  • מפעילים את Cloud SQL Admin API.

    התפקידים שנדרשים כדי להפעיל ממשקי API

    כדי להפעיל ממשקי API, צריך את ההרשאה serviceusage.services.enable. אם אתם יצרתם את הפרויקט, סביר להניח שכבר יש לכם את ההרשאה הזו דרך התפקיד "בעלים" (roles/owner). אחרת, אתם יכולים לקבל את ההרשאה הזו דרך התפקיד "אדמין בממשק 'שימוש בשירות'" (roles/serviceusage.serviceUsageAdmin). איך מקצים תפקידים

    להפעלת ה-API

  • יצירת מכונה של Cloud SQL, כולל הגדרת משתמש ברירת המחדל.

    מידע נוסף על יצירת מכונות זמין במאמר יצירת מכונות.

    למידע נוסף על הגדרת משתמש ברירת המחדל, קראו את המאמר הגדרת הסיסמה לחשבון המשתמש שמוגדר כברירת מחדל.

  • מגדירים את התפקידים וההרשאות שנדרשים כדי להתחבר למכונה של Cloud SQL.

הגדרה

Java

‫Cloud SQL Java Connector הוא ספרייה שמספקת הצפנה והרשאה שמבוססת על IAM כשמתחברים למכונה של Cloud SQL. הוא לא יכול לספק נתיב רשת למכונה של Cloud SQL אם אין כבר נתיב כזה.

התקנה

בקישורים הבאים מוסבר איך ליצור את מנהלי ההתקנים של JDBC ו-R2DBC ולהשתמש בהם עם Cloud SQL Java Connector:

באפליקציות לדוגמה האלה אפשר לראות דוגמאות לשימוש בספרייה הזו בהקשר של אפליקציה.

אמת

הספרייה הזו משתמשת ב-Application Default Credentials כדי לאמת את החיבור לשרת Cloud SQL.

כדי להפעיל את פרטי הכניסה באופן מקומי, משתמשים בפקודת gcloud הבאה:

    gcloud auth application-default login
    

חיבור באמצעות Intellij

כדי לחבר את IntelliJ למכונה של Cloud SQL, צריך להוסיף את הספרייה כקובץ JAR עם יחסי תלות בקטע Additional Files בדף ההגדרות של מנהל ההתקן. לדוגמה, אפשר למצוא קובצי fat jar מוכנים מראש בדף Cloud SQL Java Connector Releases למטרה הזו.

Python

הספרייה Cloud SQL Python Connector משמשת לצד מנהל התקן של מסד נתונים, ומאפשרת למשתמשים עם הרשאות מתאימות להתחבר למסד נתונים ב-Cloud SQL בלי להוסיף ידנית כתובות IP לרשימת ההיתרים או לנהל אישורי SSL.

כדי לראות דוגמאות אינטראקטיביות לשימוש ב-Cloud SQL Python Connector, פתחו את ה-notebook של Cloud SQL Python Connector.

מנהלי ההתקנים שנתמכים ב-PostgreSQL הם pg8000 ו-asyncpg.

התקנה

כדי להתקין את הגרסה האחרונה של Cloud SQL Python Connector, משתמשים בפקודה pip install ומציינים את מנהל ההתקן pg8000 או asyncpg של מסד הנתונים:

    pip install "cloud-sql-python-connector[pg8000]"
    

או

    pip install "cloud-sql-python-connector[asyncpg]"
    

אמת

הספרייה הזו משתמשת ב-Application Default Credentials כדי לאמת את החיבור לשרת Cloud SQL.

כדי להפעיל את פרטי הכניסה באופן מקומי, משתמשים בפקודת gcloud הבאה:

    gcloud auth application-default login
    

המשך

המחבר של Cloud SQL ל-Go הוא מחבר של Cloud SQL שמיועד לשימוש עם שפת Go. כדי לשפר את האבטחה, המחבר הזה משתמש בהצפנת TLS 1.3 חזקה שמאומתת באופן ידני בין מחבר הלקוח לבין שרת ה-proxy בצד השרת, ללא תלות בפרוטוקול של מסד הנתונים.

התקנה

אפשר להתקין את המאגר הזה באמצעות go get:

    go get cloud.google.com/go/cloudsqlconn
    

Node.js

המחבר של Node.js הוא ספרייה שמיועדת לשימוש עם סביבת זמן הריצה של Node.js, ומאפשרת להתחבר באופן מאובטח למכונה של Cloud SQL.

התקנה

אפשר להתקין את הספרייה באמצעות npm install:

    npm install @google-cloud/cloud-sql-connector
    

שימוש

Java

כדי לראות את קטע הקוד הזה בהקשר של אפליקציית אינטרנט, עיינו ב-README ב-GitHub.

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

public class ConnectorConnectionPoolFactory 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_USER = System.getenv("DB_USER");
  private static final String DB_PASS = System.getenv("DB_PASS");
  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_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:postgresql:///%s", DB_NAME));
    config.setUsername(DB_USER); // e.g. "root", _postgres"
    config.setPassword(DB_PASS); // e.g. "my-password"

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


    // The ipTypes argument can be used to specify a comma delimited list of preferred IP types
    // for connecting to a Cloud SQL instance. The argument ipTypes=PRIVATE will force the
    // SocketFactory to connect with an instance's associated private IP.
    config.addDataSourceProperty("ipTypes", "PUBLIC,PRIVATE");

    // 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);
  }
}

Python

במאמר איך משתמשים במחבר הזה מוסבר בפירוט איך משתמשים בספרייה. דוגמה לקוד של בדיקת חיבור ב-GitHub.

import os

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

import sqlalchemy


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

    Uses the Cloud SQL Python Connector package.
    """
    # 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_user = os.environ["DB_USER"]  # e.g. 'my-db-user'
    db_pass = os.environ["DB_PASS"]  # e.g. 'my-db-password'
    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_user,
            password=db_pass,
            db=db_name,
            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

המשך

בקטע שימוש מפורטות הוראות לשימוש בספרייה. דוגמה לקוד של בדיקת חיבור ב-GitHub.

package cloudsql

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 connectWithConnector() (*sql.DB, error) {
	mustGetenv := func(k string) string {
		v := os.Getenv(k)
		if v == "" {
			log.Fatalf("Fatal Error in connect_connector.go: %s environment variable not set.\n", 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 passwords and other secrets safe.
	var (
		dbUser                 = mustGetenv("DB_USER")                  // e.g. 'my-db-user'
		dbPwd                  = mustGetenv("DB_PASS")                  // e.g. 'my-db-password'
		dbName                 = mustGetenv("DB_NAME")                  // e.g. 'my-database'
		instanceConnectionName = mustGetenv("INSTANCE_CONNECTION_NAME") // e.g. 'project:region:instance'
		usePrivate             = os.Getenv("PRIVATE_IP")
	)

	dsn := fmt.Sprintf("user=%s password=%s database=%s", dbUser, dbPwd, dbName)
	config, err := pgx.ParseConfig(dsn)
	if err != nil {
		return nil, err
	}
	var opts []cloudsqlconn.Option
	if usePrivate != "" {
		opts = append(opts, cloudsqlconn.WithDefaultDialOptions(cloudsqlconn.WithPrivateIP()))
	}
	// 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.
	opts = append(opts, cloudsqlconn.WithLazyRefresh())
	d, err := cloudsqlconn.NewDialer(context.Background(), opts...)
	if err != nil {
		return nil, err
	}
	// Use the Cloud SQL connector to handle connecting to the instance.
	// This approach does *NOT* require the Cloud SQL proxy.
	config.DialFunc = func(ctx context.Context, network, instance string) (net.Conn, error) {
		return d.Dial(ctx, instanceConnectionName)
	}
	dbURI := stdlib.RegisterConnConfig(config)
	dbPool, err := sql.Open("pgx", dbURI)
	if err != nil {
		return nil, fmt.Errorf("sql.Open: %w", err)
	}
	return dbPool, nil
}

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';

// connectWithConnector initializes connection pool for a Cloud SQL instance
// of Postgres using the Cloud SQL Node.js Connector.
const connectWithConnector = 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(),
  });
  const dbConfig = {
    client: 'pg',
    connection: {
      ...clientOpts,
      user: process.env.DB_USER, // e.g. 'my-user'
      password: process.env.DB_PASS, // e.g. 'my-user-password'
      database: process.env.DB_NAME, // e.g. 'my-database'
    },
    // ... Specify additional properties here.
    ...config,
  };
  // Establish a connection to the database.
  return Knex(dbConfig);
};

לאכוף

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

אם אתם משתמשים במכונה שמופעל בה Private Service Connect, יש מגבלה. אם במכונה מופעלת אכיפת מחבר, אי אפשר ליצור רפליקות לקריאה בלבד של המכונה. באופן דומה, אם למכונה יש רפליקות לקריאה בלבד, אי אפשר להפעיל את אכיפת המחבר במכונה.

gcloud

כדי לאכוף שימוש רק ב-Cloud SQL Auth Proxy או ב-Cloud SQL Language Connectors להתחברות למכונה, משתמשים בפקודה gcloud sql instances patch:

gcloud sql instances patch INSTANCE_NAME \
--connector-enforcement=REQUIRED

מחליפים את INSTANCE_NAME בשם של מכונת Cloud SQL.

REST

לפני שמשתמשים בנתוני הבקשה, צריך להחליף את הנתונים הבאים:

  • ‫PROJECT_ID: המזהה או מספר הפרויקט של הפרויקט ב- Cloud de Confiance שמכיל את המכונה
  • ‫INSTANCE_NAME: השם של מכונת Cloud SQL

ה-method של ה-HTTP וכתובת ה-URL:

PATCH https://sqladmin.googleapis.com/v1/projects/PROJECT_ID/instances/INSTANCE_NAME

תוכן בקשת JSON:

{
  "kind": "sql#instance",
  "name": INSTANCE_NAME,
  "project": PROJECT_ID,
  "settings": {
  "connectorEnforcement": "REQUIRED",
  "kind": "sql#settings"
  }
}

כדי לשלוח את הבקשה צריך להרחיב אחת מהאפשרויות הבאות:

אתם אמורים לקבל תגובת JSON שדומה לזו:

{
  "kind": "sql#operation",
  "targetLink": "https://sqladmin.googleapis.com/v1/projects/PROJECT_ID/instances/INSTANCE_NAME",
  "status": "PENDING",
  "user": "user@example.com",
  "insertTime": "2020-01-16T02:32:12.281Z",
  "operationType": "UPDATE",
  "name": "OPERATION_ID",
  "targetId": "INSTANCE_NAME",
  "selfLink": "https://sqladmin.googleapis.com/v1/projects/PROJECT_ID/operations/OPERATION_ID",
  "targetProject": "PROJECT_ID"
}

פתרון בעיות

גרסאות של מנהלי התקנים

כדי למנוע בעיות תאימות, חשוב לוודא שאתם משתמשים בגרסה העדכנית של מחברי Cloud SQL ושל מנהל ההתקן של מסד הנתונים. חלק מהגרסאות הישנות של מנהלי ההתקנים לא נתמכות.

נתיבי חיבור

המחברים של Cloud SQL מספקים הרשאה לחיבורים, אבל הם לא מספקים נתיבים חדשים לקישוריות. לדוגמה, כדי להתחבר למכונה של Cloud SQL באמצעות כתובת IP פרטית, לאפליקציה כבר צריכה להיות גישה ל-VPC.

ניפוי באגים בבעיות בחיבור

לקבלת עזרה נוספת בבעיות חיבור, עיינו בדפים פתרון בעיות וניפוי באגים בבעיות חיבור.

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