alloydbconn

package module
v1.11.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 10, 2024 License: Apache-2.0 Imports: 28 Imported by: 2

README

alloydb-go-connector image

AlloyDB Go Connector

CI Go Reference

The AlloyDB Go Connector is an AlloyDB connector designed for use with the Go language. Using an AlloyDB connector provides the following benefits:

  • IAM Authorization: uses IAM permissions to control who/what can connect to your AlloyDB instances

  • Improved Security: uses TLS 1.3 encryption and identity verification between the client connector and the server-side proxy, independent of the database protocol.

  • Convenience: removes the requirement to use and distribute SSL certificates, as well as manage firewalls or source/destination IP addresses.

  • (optionally) IAM DB Authentication: provides support for AlloyDB’s automatic IAM DB AuthN feature.

Installation

You can install this repo with go get:

go get cloud.google.com/go/alloydbconn

Usage

This package provides several functions for authorizing and encrypting connections. These functions can be used with your database driver to connect to your AlloyDB instance.

AlloyDB supports network connectivity through public IP addresses and private, internal IP addresses. By default this package will attempt to connect over a private IP connection. When doing so, this package must be run in an environment that is connected to the VPC Network that hosts your AlloyDB private IP address.

Please see Configuring AlloyDB Connectivity for more details.

APIs and Services

This package requires the following to connect successfully:

  • IAM principal (user, service account, etc.) with the AlloyDB Client and Service Usage Consumer roles or equivalent permissions. Credentials for the IAM principal are used to authorize connections to an AlloyDB instance.

  • The AlloyDB API to be enabled within your Google Cloud Project. By default, the API will be called in the project associated with the IAM principal.

Credentials

This repo uses the Application Default Credentials (ADC) strategy for resolving credentials. Please see these instructions for how to set your ADC (Google Cloud Application vs Local Development, IAM user vs service account credentials), or consult the golang.org/x/oauth2/google documentation.

To explicitly set a specific source for the Credentials, see Using Options below.

Connecting with pgx

To use the dialer with pgx, use pgxpool by configuring a Config.DialFunc like so:

// Configure the driver to connect to the database
dsn := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable", pgUser, pgPass, pgDB)
config, err := pgxpool.ParseConfig(dsn)
if err != nil {
    log.Fatalf("failed to parse pgx config: %v", err)
}

// Create a new dialer with any options
d, err := alloydbconn.NewDialer(ctx)
if err != nil {
    log.Fatalf("failed to initialize dialer: %v", err)
}
// Don't close the dialer until you're done with the database connection
// e.g. at the end of your main function
defer d.Close()

// Tell the driver to use the AlloyDB Go Connector to create connections
config.ConnConfig.DialFunc = func(ctx context.Context, _ string, instance string) (net.Conn, error) {
    return d.Dial(ctx, "projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>")
}

// Interact with the driver directly as you normally would
conn, err := pgxpool.ConnectConfig(context.Background(), config)
if err != nil {
    log.Fatalf("failed to connect: %v", connErr)
}
defer conn.Close()
Using Options

If you need to customize something about the Dialer, you can initialize directly with NewDialer:

ctx := context.Background()
d, err := alloydbconn.NewDialer(
    ctx,
    alloydbconn.WithCredentialsFile("key.json"),
)
if err != nil {
    log.Fatalf("unable to initialize dialer: %s", err)
}

conn, err := d.Dial(ctx, "projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>")

For a full list of customizable behavior, see alloydbconn.Option.

Using DialOptions

If you want to customize how the connection is created, use a DialOption.

For example, to connect over public IP, use:

conn, err := d.Dial(
    ctx,
    "projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>",
    alloydbconn.WithPublicIP(),
)

Or to use PSC, use:

conn, err := d.Dial(
    ctx,
    "projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>",
    alloydbconn.WithPSC(),
)

You can also use the WithDefaultDialOptions Option to specify DialOptions to be used by default:

d, err := alloydbconn.NewDialer(
    ctx,
    alloydbconn.WithDefaultDialOptions(
        alloydbconn.WithPublicIP(),
    ),
)
Using the dialer with database/sql

Using the dialer directly will expose more configuration options. However, it is possible to use the dialer with the database/sql package.

To use database/sql, use pgxv5.RegisterDriver with any necessary Dialer configuration. Note: the connection string must use the keyword/value format with host set to the instance connection name.

package foo

import (
    "database/sql"

    "cloud.google.com/go/alloydbconn"
    "cloud.google.com/go/alloydbconn/driver/pgxv5"
)

func Connect() {
    cleanup, err := pgxv5.RegisterDriver("alloydb", alloydbconn.WithPublicIP())
    if err != nil {
        // ... handle error
    }
    defer cleanup()

    db, err := sql.Open(
        "alloydb",
        "host=projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE> user=myuser password=mypass dbname=mydb sslmode=disable",
	)
    // ... etc
}
Automatic IAM Database Authentication

The Go Connector supports Automatic IAM database authentication.

Make sure to configure your AlloyDB Instance to allow IAM authentication and add an IAM database user.

A Dialer can be configured to connect to an AlloyDB instance using automatic IAM database authentication with the WithIAMAuthN Option.

d, err := alloydbconn.NewDialer(ctx, alloydbconn.WithIAMAuthN())

When configuring the DSN for IAM authentication, the password field can be omitted and the user field should be formatted as follows:

  • For an IAM user account, this is the user's email address.
  • For a service account, it is the service account's email without the .gserviceaccount.com domain suffix.

For example, to connect using the test-sa@test-project.iam.gserviceaccount.com service account, the DSN would look like:

dsn := "user=test-sa@test-project.iam dbname=mydb sslmode=disable"
Enabling Metrics and Tracing

This library includes support for metrics and tracing using OpenCensus. To enable metrics or tracing, you need to configure an exporter. OpenCensus supports many backends for exporters.

Supported metrics include:

  • alloydbconn/dial_latency: The distribution of dialer latencies (ms)
  • alloydbconn/open_connections: The current number of open AlloyDB connections
  • alloydbconn/dial_failure_count: The number of failed dial attempts
  • alloydbconn/refresh_success_count: The number of successful certificate refresh operations
  • alloydbconn/refresh_failure_count: The number of failed refresh operations.

Supported traces include:

  • cloud.google.com/go/alloydbconn.Dial: The dial operation including refreshing an ephemeral certificate and connecting to the instance
  • cloud.google.com/go/alloydbconn/internal.InstanceInfo: The call to retrieve instance metadata (e.g., IP address, etc)
  • cloud.google.com/go/alloydbconn/internal.Connect: The connection attempt using the ephemeral certificate
  • AlloyDB API client operations

For example, to use Cloud Monitoring and Cloud Trace, you would configure an exporter like so:

package main

import (
    "contrib.go.opencensus.io/exporter/stackdriver"
    "go.opencensus.io/trace"
)

func main() {
    sd, err := stackdriver.NewExporter(stackdriver.Options{
        ProjectID: "mycoolproject",
    })
    if err != nil {
        // handle error
    }
    defer sd.Flush()
    trace.RegisterExporter(sd)

    sd.StartMetricsExporter()
    defer sd.StopMetricsExporter()

    // Use alloydbconn as usual.
    // ...
}
Debug Logging

The Go Connector supports optional debug logging to help diagnose problems with the background certificate refresh. To enable it, provide a logger that implements the debug.ContextLogger interface when initializing the Dialer.

For example:

import (
    "context"
    "net"

    "cloud.google.com/go/alloydbconn"
)

type myLogger struct{}

func (l *myLogger) Debugf(ctx context.Context, format string, args ...interface{}) {
    // Log as you like here
}

func connect() {
    l := &myLogger{}

    d, err := NewDialer(
        context.Background(),
        alloydbconn.WithContextDebugLogger(l),
    )
    // use dialer as usual...
}

Support policy

Major version lifecycle

This project uses semantic versioning, and uses the following lifecycle regarding support for a major version:

Active - Active versions get all new features and security fixes (that wouldn’t otherwise introduce a breaking change). New major versions are guaranteed to be "active" for a minimum of 1 year.

Deprecated - Deprecated versions continue to receive security and critical bug fixes, but do not receive new features. Deprecated versions will be supported for 1 year.

Unsupported - Any major version that has been deprecated for >=1 year is considered unsupported.

Supported Go Versions

We follow the Go Version Support Policy used by Google Cloud Libraries for Go.

Release cadence

This project aims for a release on at least a monthly basis. If no new features or fixes have been added, a new PATCH version with the latest dependencies is released.

Documentation

Overview

Package alloydbconn provides functions for authorizing and encrypting connections. These functions can be used with a database driver to connect to an AlloyDB cluster.

Creating a Dialer

To start working with this package, create a Dialer. There are two ways of creating a Dialer, which one you use depends on your database driver.

Users have the option of using the database/sql interface or using pgx directly.

To use a dialer with pgx, we recommend using connection pooling with pgxpool. To create the dialer use the NewDialer func.

import (
    "context"
    "net"

    "cloud.google.com/go/alloydbconn"
    "github.com/jackc/pgx/v4/pgxpool"
)

func connect() {
    // Configure the driver to connect to the database
    dsn := fmt.Sprintf("user=%s password=%s dbname=%s sslmode=disable", pgUser, pgPass, pgDB)
    config, err := pgxpool.ParseConfig(dsn)
    if err != nil {
        log.Fatalf("failed to parse pgx config: %v", err)
    }

    // Create a new dialer with any options
    d, err := alloydbconn.NewDialer(ctx)
    if err != nil {
        log.Fatalf("failed to initialize dialer: %v", err)
    }
    defer d.Close()

    // Tell the driver to use the AlloyDB Go Connector to create connections
    config.ConnConfig.DialFunc = func(ctx context.Context, _ string, instance string) (net.Conn, error) {
        return d.Dial(ctx, "projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>")
    }

    // Interact with the driver directly as you normally would
    conn, err := pgxpool.ConnectConfig(context.Background(), config)
    if err != nil {
        log.Fatalf("failed to connect: %v", connErr)
    }
    defer conn.Close()
}

To use database/sql, call pgxv4.RegisterDriver with any necessary Dialer configuration.

import (
    "database/sql"

    "cloud.google.com/go/alloydbconn"
    "cloud.google.com/go/alloydbconn/driver/pgxv4"
)

func connect() {
    // adjust options as needed
    cleanup, err := pgxv4.RegisterDriver("alloydb")
    if err != nil {
        // ... handle error
    }
    defer cleanup()

    db, err := sql.Open(
        "alloydb",
        "host=projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE> user=myuser password=mypass dbname=mydb sslmode=disable",
    )
    //... etc
}

Index

Constants

View Source
const CloudPlatformScope = "https://www.googleapis.com/auth/cloud-platform"

CloudPlatformScope is the default OAuth2 scope set on the API client.

Variables

View Source
var (
	// ErrDialerClosed is used when a caller invokes Dial after closing the
	// Dialer.
	ErrDialerClosed = errors.New("alloydbconn: dialer is closed")
)

Functions

This section is empty.

Types

type DialOption

type DialOption func(d *dialCfg)

A DialOption is an option for configuring how a Dialer's Dial call is executed.

func DialOptions

func DialOptions(opts ...DialOption) DialOption

DialOptions turns a list of DialOption instances into an DialOption.

func WithOneOffDialFunc added in v1.4.0

func WithOneOffDialFunc(dial func(ctx context.Context, network, addr string) (net.Conn, error)) DialOption

WithOneOffDialFunc configures the dial function on a one-off basis for an individual call to Dial. To configure a dial function across all invocations of Dial, use WithDialFunc.

func WithPSC added in v1.9.0

func WithPSC() DialOption

WithPSC returns a DialOption that specifies a PSC endpoint will be used to connect.

func WithPrivateIP added in v1.6.0

func WithPrivateIP() DialOption

WithPrivateIP returns a DialOption that specifies a private IP (VPC) will be used to connect.

func WithPublicIP added in v1.6.0

func WithPublicIP() DialOption

WithPublicIP returns a DialOption that specifies a public IP will be used to connect.

func WithTCPKeepAlive

func WithTCPKeepAlive(d time.Duration) DialOption

WithTCPKeepAlive returns a DialOption that specifies the tcp keep alive period for the connection returned by Dial.

type Dialer

type Dialer struct {
	// contains filtered or unexported fields
}

A Dialer is used to create connections to AlloyDB instance.

Use NewDialer to initialize a Dialer.

func NewDialer

func NewDialer(ctx context.Context, opts ...Option) (*Dialer, error)

NewDialer creates a new Dialer.

Initial calls to NewDialer make take longer than normal because generation of an RSA keypair is performed. Calls with a WithRSAKeyPair DialOption or after a default RSA keypair is generated will be faster.

func (*Dialer) Close

func (d *Dialer) Close() error

Close closes the Dialer; it prevents the Dialer from refreshing the information needed to connect.

func (*Dialer) Dial

func (d *Dialer) Dial(ctx context.Context, instance string, opts ...DialOption) (conn net.Conn, err error)

Dial returns a net.Conn connected to the specified AlloyDB instance. The instance argument must be the instance's URI, which is in the format projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>

type Option

type Option func(d *dialerConfig)

An Option is an option for configuring a Dialer.

func WithAdminAPIEndpoint

func WithAdminAPIEndpoint(url string) Option

WithAdminAPIEndpoint configures the underlying AlloyDB Admin API client to use the provided URL.

func WithContextLogger added in v1.10.0

func WithContextLogger(l debug.ContextLogger) Option

WithContextLogger configures a debug lgoger for reporting on internal operations. By default the debug logger is disabled.

func WithCredentialsFile

func WithCredentialsFile(filename string) Option

WithCredentialsFile returns an Option that specifies a service account or refresh token JSON credentials file to be used as the basis for authentication.

func WithCredentialsJSON

func WithCredentialsJSON(b []byte) Option

WithCredentialsJSON returns an Option that specifies a service account or refresh token JSON credentials to be used as the basis for authentication.

func WithDebugLogger added in v1.8.0

func WithDebugLogger(l debug.Logger) Option

WithDebugLogger configures a debug logger for reporting on internal operations. By default the debug logger is disabled. Prefer WithContextLogger.

func WithDefaultDialOptions

func WithDefaultDialOptions(opts ...DialOption) Option

WithDefaultDialOptions returns an Option that specifies the default DialOptions used.

func WithDialFunc

func WithDialFunc(dial func(ctx context.Context, network, addr string) (net.Conn, error)) Option

WithDialFunc configures the function used to connect to the address on the named network. This option is generally unnecessary except for advanced use-cases. The function is used for all invocations of Dial. To configure a dial function per individual calls to dial, use WithOneOffDialFunc.

func WithHTTPClient

func WithHTTPClient(client *http.Client) Option

WithHTTPClient configures the underlying AlloyDB Admin API client with the provided HTTP client. This option is generally unnecessary except for advanced use-cases.

func WithIAMAuthN added in v1.5.0

func WithIAMAuthN() Option

WithIAMAuthN enables automatic IAM Authentication. If no token source has been configured (such as with WithTokenSource, WithCredentialsFile, etc), the dialer will use the default token source as defined by https://pkg.go.dev/golang.org/x/oauth2/google#FindDefaultCredentialsWithParams.

func WithLazyRefresh added in v1.10.0

func WithLazyRefresh() Option

WithLazyRefresh configures the dialer to refresh certificates on an as-needed basis. If a certificate is expired when a connection request occurs, the Go Connector will block the attempt and refresh the certificate immediately. This option is useful when running the Go Connector in environments where the CPU may be throttled, thus preventing a background goroutine from running consistently (e.g., in Cloud Run the CPU is throttled outside of a request context causing the background refresh to fail).

func WithOptions

func WithOptions(opts ...Option) Option

WithOptions turns a list of Option's into a single Option.

func WithRSAKey

func WithRSAKey(k *rsa.PrivateKey) Option

WithRSAKey returns an Option that specifies a rsa.PrivateKey used to represent the client.

func WithRefreshTimeout

func WithRefreshTimeout(t time.Duration) Option

WithRefreshTimeout returns an Option that sets a timeout on refresh operations. Defaults to 60s.

func WithStaticConnectionInfo added in v1.10.0

func WithStaticConnectionInfo(r io.Reader) Option

WithStaticConnectionInfo specifies an io.Reader from which to read static connection info. This is a *dev-only* option and should not be used in production as it will result in failed connections after the client certificate expires. It is also subject to breaking changes in the format. NOTE: The static connection info is not refreshed by the dialer. The JSON format supports multiple instances, regardless of cluster.

The reader should hold JSON with the following format:

{
    "publicKey": "<PEM Encoded public RSA key>",
    "privateKey": "<PEM Encoded private RSA key>",
    "projects/<PROJECT>/locations/<REGION>/clusters/<CLUSTER>/instances/<INSTANCE>": {
        "ipAddress": "<PSA-based private IP address>",
        "publicIpAddress": "<public IP address>",
        "pscInstanceConfig": {
            "pscDnsName": "<PSC DNS name>"
        },
        "pemCertificateChain": [
            "<client cert>", "<intermediate cert>", "<CA cert>"
        ],
        "caCert": "<CA cert>"
    }
}

func WithTokenSource

func WithTokenSource(s oauth2.TokenSource) Option

WithTokenSource returns an Option that specifies an OAuth2 token source to be used as the basis for authentication.

func WithUserAgent

func WithUserAgent(ua string) Option

WithUserAgent returns an Option that sets the User-Agent.

Directories

Path Synopsis
driver
pgxv4
Package pgxv4 provides an AlloyDB driver that uses pgx v4 and works with the database/sql package.
Package pgxv4 provides an AlloyDB driver that uses pgx v4 and works with the database/sql package.
pgxv5
Package pgxv5 provides an AlloyDB driver that uses pgx v5 and works with the database/sql package.
Package pgxv5 provides an AlloyDB driver that uses pgx v5 and works with the database/sql package.
Package errtype provides a number of concrete types which are used by the alloydbconn package.
Package errtype provides a number of concrete types which are used by the alloydbconn package.
internal

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL