Conectarse mediante conectores de lenguaje de Cloud SQL

Los conectores de Cloud SQL son bibliotecas que proporcionan cifrado y autorización basada en Gestión de Identidades y Accesos (IAM) al conectarse a una instancia de Cloud SQL. No pueden proporcionar una ruta de red a una instancia de Cloud SQL si aún no hay ninguna.

Otras formas de conectarse a una instancia de Cloud SQL son usar un cliente de base de datos o el proxy de autenticación de Cloud SQL. Consulta la página Acerca de las opciones de conexión para obtener más información sobre cómo conectarse a una instancia de Cloud SQL.

En esta página se describen los siguientes conectores de Cloud SQL:

  • Conector Java de Cloud SQL
  • El conector de Python de Cloud SQL (abrir en Colab)
  • Conector Go de Cloud SQL
  • Conector de Cloud SQL para Node.js

Ventajas

Usar un conector de Cloud SQL ofrece las siguientes ventajas:

  • Autorización de IAM: usa permisos de IAM para controlar quién o qué puede conectarse a tus instancias de Cloud SQL.
  • Comodidad: elimina la necesidad de gestionar certificados SSL, configurar reglas de cortafuegos o habilitar redes autorizadas.

Antes de empezar

  • Habilita la API Admin de Cloud SQL.

    Roles required to enable APIs

    To enable APIs, you need the Service Usage Admin IAM role (roles/serviceusage.serviceUsageAdmin), which contains the serviceusage.services.enable permission. Learn how to grant roles.

    Enable the API

  • Crea una instancia de Cloud SQL, incluida la configuración del usuario predeterminado.

    Para obtener más información sobre cómo crear instancias, consulta Crear instancias.

    Para obtener más información sobre cómo configurar el usuario predeterminado, consulta el artículo Definir la contraseña de la cuenta de usuario predeterminada.

  • Configura los roles y permisos necesarios para conectarte a una instancia de Cloud SQL.

Configuración

Java

Cloud SQL Java Connector es una biblioteca que proporciona autorización y cifrado basados en IAM al conectarse a una instancia de Cloud SQL. No puede proporcionar una ruta de red a una instancia de Cloud SQL si aún no hay ninguna.

Instalar

Para obtener instrucciones sobre cómo compilar y usar los controladores de JDBC y R2DBC con Cloud SQL Java Connector, consulta los siguientes enlaces:

Para ver ejemplos de cómo se usa esta biblioteca en el contexto de una aplicación, consulta estas aplicaciones de muestra.

Autenticar

Esta biblioteca usa credenciales predeterminadas de la aplicación para autenticar la conexión con el servidor de Cloud SQL.

Para activar las credenciales de forma local, usa el siguiente comando gcloud:

    gcloud auth application-default login
    

Conectarse con IntelliJ

Para conectar IntelliJ a tu instancia de Cloud SQL, tendrás que añadir la biblioteca como un archivo JAR con dependencias en la sección Archivos adicionales de la página de configuración del controlador. Por ejemplo, puedes encontrar archivos JARs grandes precompilados en la página de versiones de Cloud SQL Connector para Java.

Python

El conector de Python de Cloud SQL es una biblioteca que se puede usar junto con un controlador de base de datos para permitir que los usuarios con permisos suficientes se conecten a una base de datos de Cloud SQL sin tener que incluir manualmente IPs en la lista de permitidos ni gestionar certificados SSL.

Para ver ejemplos interactivos del uso del conector Python de Cloud SQL, abre el notebook del conector Python de Cloud SQL.

El controlador que admite SQL Server es pytds.

Instalar

Para instalar la versión más reciente del conector Python de Cloud SQL, usa el comando pip install y especifica el controlador pytds de tu base de datos:

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

Autenticar

Esta biblioteca usa credenciales predeterminadas de la aplicación para autenticar la conexión con el servidor de Cloud SQL.

Para activar las credenciales de forma local, usa el siguiente comando gcloud:

    gcloud auth application-default login
    

Go

El conector Go de Cloud SQL es un conector de Cloud SQL diseñado para usarse con el lenguaje Go. Para mejorar la seguridad, este conector usa un cifrado TLS 1.3 robusto y autenticado manualmente entre el conector del cliente y el proxy del lado del servidor, independientemente del protocolo de la base de datos.

Instalar

Puedes instalar este repositorio con go get:

    go get cloud.google.com/go/cloudsqlconn
    

Node.js

El conector de Node.js es una biblioteca diseñada para usarse con el tiempo de ejecución de Node.js que te permite conectarte de forma segura a tu instancia de Cloud SQL.

Instalar

Puedes instalar la biblioteca con npm install:

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

Uso

Java

Para ver este fragmento en el contexto de una aplicación web, consulta el archivo README en 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 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 is equivalent to setting the config options below:
    // jdbc:sqlserver://;user=<DB_USER>;password=<DB_PASS>;databaseName=<DB_NAME>;
    // socketFactoryClass=com.google.cloud.sql.sqlserver.SocketFactory;
    // socketFactoryConstructorArg=<INSTANCE_CONNECTION_NAME>

    // 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
        .setDataSourceClassName("com.microsoft.sqlserver.jdbc.SQLServerDataSource");
    config.setUsername(DB_USER); // e.g. "root", "sqlserver"
    config.setPassword(DB_PASS); // e.g. "my-password"
    config.addDataSourceProperty("databaseName", DB_NAME);

    config.addDataSourceProperty("socketFactoryClass",
        "com.google.cloud.sql.sqlserver.SocketFactory");
    config.addDataSourceProperty("socketFactoryConstructorArg", INSTANCE_CONNECTION_NAME);

    // The Java Connector provides SSL encryption, so it should be disabled
    // at the driver level.
    config.addDataSourceProperty("encrypt", "false");

    // 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

Consulta Cómo usar este conector para obtener instrucciones detalladas sobre cómo usar la biblioteca. Consulta un ejemplo de código de prueba de conexión en GitHub.

import os

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

import sqlalchemy


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

    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.get("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(ip_type=ip_type, refresh_strategy="LAZY")

    connect_args = {}
    # If your SQL Server instance requires SSL, you need to download the CA
    # certificate for your instance and include cafile={path to downloaded
    # certificate} and validate_host=False. This is a workaround for a known issue.
    if os.environ.get("DB_ROOT_CERT"):  # e.g. '/path/to/my/server-ca.pem'
        connect_args = {
            "cafile": os.environ["DB_ROOT_CERT"],
            "validate_host": False,
        }

    def getconn() -> pytds.Connection:
        conn = connector.connect(
            instance_connection_name,
            "pytds",
            user=db_user,
            password=db_pass,
            db=db_name,
            **connect_args
        )
        return conn

    pool = sqlalchemy.create_engine(
        "mssql+pytds://",
        creator=getconn,
        # ...
    )
    return pool

Go

Consulta la sección Uso para obtener instrucciones detalladas sobre cómo usar la biblioteca. Consulta un ejemplo de código de prueba de conexión en GitHub.

package cloudsql

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

	"cloud.google.com/go/cloudsqlconn"
	mssql "github.com/denisenkom/go-mssqldb"
)

type csqlDialer struct {
	dialer     *cloudsqlconn.Dialer
	connName   string
	usePrivate bool
}

// DialContext adheres to the mssql.Dialer interface.
func (c *csqlDialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
	var opts []cloudsqlconn.DialOption
	if c.usePrivate {
		opts = append(opts, cloudsqlconn.WithPrivateIP())
	}
	return c.dialer.Dial(ctx, c.connName, opts...)
}

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 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")
	)

	dbURI := fmt.Sprintf("user id=%s;password=%s;database=%s;", dbUser, dbPwd, dbName)
	c, err := mssql.NewConnector(dbURI)
	if err != nil {
		return nil, fmt.Errorf("mssql.NewConnector: %w", err)
	}
	// 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.
	dialer, err := cloudsqlconn.NewDialer(context.Background(), cloudsqlconn.WithLazyRefresh())
	if err != nil {
		return nil, fmt.Errorf("cloudsqlconn.NewDailer: %w", err)
	}
	c.Dialer = &csqlDialer{
		dialer:     dialer,
		connName:   instanceConnectionName,
		usePrivate: usePrivate != "",
	}

	dbPool := sql.OpenDB(c)
	if err != nil {
		return nil, fmt.Errorf("sql.Open: %w", err)
	}
	return dbPool, nil
}

Node.js

Para obtener instrucciones detalladas sobre cómo usar la biblioteca, consulta la sección Uso.

const {Connection} = require('tedious');
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 a TCP connection
// to a Cloud SQL instance of SQL Server.
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.getTediousOptions({
    instanceConnectionName: process.env.INSTANCE_CONNECTION_NAME,
    ipType: getIpType(),
  });
  const dbConfig = {
    // Please note that the `server` property here is not used and is only
    // defined due to a bug in the tedious driver
    // (ref: https://github.com/tediousjs/tedious/issues/1541)
    // With that in mind, do not try to change this value since it will have no
    // impact in how the connector works, this sample will be updated to remove
    // this property declaration as soon as the tedious driver bug is fixed
    server: '0.0.0.0', // e.g. '127.0.0.1'
    authentication: {
      type: 'default',
      options: {
        userName: process.env.DB_USER, // e.g. 'my-db-user'
        password: process.env.DB_PASS, // e.g. 'my-db-password'
      },
    },
    options: {
      ...clientOpts,
      // Please note that the `port` property here is not used and is only
      // defined due to a bug in the tedious driver
      // (ref: https://github.com/tediousjs/tedious/issues/1541)
      // With that in mind, do not try to change this value since it will have
      // no impact in how the connector works, this sample will be updated to
      // remove this property declaration as soon as the tedious driver bug is
      // fixed
      port: 9999,
      database: process.env.DB_NAME, // e.g. 'my-database'
      useColumnNames: true,
    },
    // ... Specify additional properties here.
    ...config,
  };

  // Establish a connection to the database.
  return new Connection(dbConfig);
};

Aplicar

Si usas la aplicación de conectores, puedes obligar a que solo se usen el proxy de autenticación de Cloud SQL o los conectores de lenguaje de Cloud SQL para conectarse a las instancias de Cloud SQL. Con la aplicación de conectores, Cloud SQL rechaza las conexiones directas a la base de datos.

Si usas una instancia habilitada para Private Service Connect, hay una limitación. Si la instancia tiene habilitada la aplicación de conectores, no puedes crear réplicas de lectura para la instancia. Del mismo modo, si la instancia tiene réplicas de lectura, no puedes habilitar la aplicación de conectores en ella.

gcloud

Para obligar a usar solo el proxy de autenticación de Cloud SQL o los conectores de lenguaje de Cloud SQL para conectarse a una instancia, usa el comando gcloud sql instances patch:

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

Sustituye INSTANCE_NAME por el nombre de tu instancia de Cloud SQL.

REST

Antes de usar los datos de la solicitud, haz las siguientes sustituciones:

  • PROJECT_ID: el ID o el número de proyecto del Google Cloud proyecto que contiene la instancia
  • INSTANCE_NAME: el nombre de tu instancia de Cloud SQL

Método HTTP y URL:

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

Cuerpo JSON de la solicitud:

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

Para enviar tu solicitud, despliega una de estas opciones:

Deberías recibir una respuesta JSON similar a la siguiente:

{
  "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"
}

Solucionar problemas

Versiones de controladores

Asegúrate de que estás usando la versión más reciente de los conectores de Cloud SQL y del controlador de tu base de datos para evitar incompatibilidades. No se admiten algunas versiones anteriores de los controladores.

Rutas de conexión

Los conectores de Cloud SQL proporcionan autorización para las conexiones, pero no ofrecen nuevas rutas de conectividad. Por ejemplo, para conectarte a una instancia de Cloud SQL mediante una dirección IP privada, tu aplicación ya debe tener acceso a la VPC.

Depurar problemas de conexión

Para obtener más ayuda con los problemas de conexión, consulta las páginas Solucionar problemas y Depurar problemas de conexión.

Siguientes pasos