Documentation
¶
Overview ¶
Package lazydsn implements a database agnostic driver with delayed DSN evaluation. This allows for use cases where, despite connecting to the same (or functionally equivalent) database, applications are forced to cope with ever rotating credentials, where the password or even also the user change with time. Credentials rotation is typical in highly secured environments and needs to be performed online, while applications are running. This fully supports services such as AWS Secrets Manager.
Warning: Please make sure that you do NOT fundamentally change access when you rotate credentials. Changing the password is fine. Switching to a different user works, as long as both users have exactly equivalent access privileges (grants and whatever applies to your database). The database/sql package assumes a constant DSN after the database is opened. If access rights change, then different connections in the pool may behave differently, which will most likely lead to a debug nightmare, to say the least. Of course nothing prevents you from changing other pieces in the DSN, like the database/schema that you connect to, but that's more often than not a very bad idea. (To start with, all of your queries would have to be fully qualified. So, don't do it unless you know exactly what you're doing.)
Like any driver, you don't use this package directly. The only difference with respecto to other drivers is that this is not automatically available simply by importing the package. The reason is that this driver needs something else to work with: a DSN provider. That's the place where you define the actual DSN that you want to use, starting from the DSN that the database/sql package provides (that matches what you give in sql.Open). You can use any type that implements the DSNProvider interface. For extra convenience, a DSNProviderFunc allows you to define a single function inline, instead of having to declare a type and methods. Using it, your application may look like this:
import ( "database/sql" "time" "github.com/gkristic/lazydsn" "github.com/go-sql-driver/mysql" ) const alias = "lazydsn:mysql" func main() { lazydsn.Register(alias, &mysql.MySQLDriver{}, lazydsn.DSNProviderFunc(func (dsn string) (string, error) { // Compute a new dsn; e.g., by using AWS Secrets Manager return dsn, nil }), ) db := sql.Open(alias, "arn:...") db.SetConnMaxLifetime(time.Hour) // Keep working with db as usual }
Once you open the database with this driver and set the connection lifetime, everything looks just as usual from the application's perspective. However, behind the scenes, connections have a predefined expiration, and they are renewed using the latest credentials available. Credentials rotation is thus fully suported, but completely transparent.
If the type that you provide also implements FullDSNProvider, then a cancellation context will be provided when available. Again, for convenience, you can use a DSNProviderWCFunc to give your context-enabled function inline.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Register ¶
func Register(alias string, d driver.Driver, dsnp DSNProvider)
Register creates and registers the driver under the provided alias, with the given inner driver and DSN provider. Applications don't typically register drivers directly, relying on implicit registration via package import and drivers' init functions. However, this driver requires parameters (the DSN provider), that applications have to provide for this driver to be meaningful at all. It's a good practice to register this as close to the most basic packages in your application as possible, to separate business code from the intricacies of dealing with database drivers.
Types ¶
type DSNProvider ¶
A DSNProvider allows converting a DSN, as provided to this driver via database/sql, into a DSN suitable for using with the inner driver.
type DSNProviderFunc ¶
DSNProviderFunc provides a convenient type so that applications don't have to declare specific types and methods with the only purpose of having a DSNProvider. This makes it possible to use an inline function literal instead.
type DSNProviderWCFunc ¶
DSNProviderWCFunc provides a convenient type so that applications don't have to declare specific types and methods with the only purpose of having a DSNProvider. This makes it possible to use an inline function literal instead.
func (DSNProviderWCFunc) FetchDSN ¶
func (f DSNProviderWCFunc) FetchDSN(dsn string) (string, error)
FetchDSN exercises the function providing an empty context.
func (DSNProviderWCFunc) FetchDSNWithContext ¶
FetchDSNWithContext exercises the original function, providing the context passed in to this function by the driver.
type Driver ¶
Driver is not a database driver by itself, but rather a wrapper on top of any driver that can be used with Go's database/sql. It adds the capability to resolve DSNs at the moment that each individual connection in the pool is opened. Contrast with the typical database/sql behavior, where every new connection in the pool is created under the same DSN, set at the time the database was sql.Open'ed.
func New ¶
func New(d driver.Driver, dsnp DSNProvider) *Driver
New creates a new driver with the given inner driver d and DSN provider. Note that d can be a driver for any database; a Driver is database agnostic. This does NOT register the driver with database/sql. See Register. This function is provided so that other packages are able to create a properly initialized driver, in case they want to extend it (just like we're doing here with other drivers!)
func (*Driver) Open ¶
Open opens a database connection and returns the latter as a driver.Conn type. This is part of the driver.Driver interface. The DSN provided to this driver doesn't need to follow the format imposed by the underlying driver. In fact, it can be completely different; no restrictions are enforced by this package. The translation from the DSN provided by database/sql to this function and the one needed by the inner driver is entirely done by the DSNProvider assigned to this driver.
func (*Driver) OpenConnector ¶
OpenConnector returns a driver.Connector that can be used to open connections to the database without having the inner driver parsing the DSN repeatedly. That's, of course, as long as the inner driver implements the driver.DriverContext interface. If not, the resulting connector will simply be wrapping the Open method.
type FullDSNProvider ¶
type FullDSNProvider interface { DSNProvider FetchDSNWithContext(context.Context, string) (string, error) }
A FullDSNProvider acts like a DSNProvider, but provides an additional function to fetch the DSN using a context, thus allowing the chance to cancel the operation.