From 82786f8278322e780b8e6bfce848176d0fcb810d Mon Sep 17 00:00:00 2001 From: "Colton J. McCurdy" Date: Tue, 3 Dec 2019 16:48:38 -0500 Subject: [PATCH] physical/posgresql: add ability to prefer VAULT_PG_CONNECTION_URL envar over config file (#7937) * physical/posgresql: add ability to use CONNECTION_URL environment variable instead of requiring it to be configured in the Vault config file. Signed-off-by: Colton McCurdy * storage/postgresql: update configuration documentation for postgresql storage backend to include connection_url configuration via the PG_CONNECTION_URL environment variable Signed-off-by: Colton McCurdy * physical/postgresql: add a configuration file and tests for getting the connection_url from the config file or environment Signed-off-by: Colton McCurdy * physical/postgresql: update postgresql backend to pull the required connection_url from the PG_CONNECTION_URL environment variable if it exists, otherwise, fallback to using the config file Signed-off-by: Colton McCurdy * physical/postgresql: remove configure*.go files and prefer the postgresql*.go files Signed-off-by: Colton McCurdy * physical/postgresql: move and simplify connectionURL function Signed-off-by: Colton McCurdy * physical/postgresql: update connectionURL test to use an unordered map instead of slice to avoid test flakiness Signed-off-by: Colton McCurdy * physical/postgresql: update config env to be prefixed with VAULT_ - VAULT_PG_CONNECTION_URL Signed-off-by: Colton McCurdy * docs/web: update postgresql backend docs to use updated, VAULT_ prefixed config env Signed-off-by: Colton McCurdy --- physical/postgresql/postgresql.go | 18 +++++- physical/postgresql/postgresql_test.go | 61 +++++++++++++++++++ .../configuration/storage/postgresql.html.md | 3 +- 3 files changed, 79 insertions(+), 3 deletions(-) diff --git a/physical/postgresql/postgresql.go b/physical/postgresql/postgresql.go index dbd3a0d2ef773..596b6c519bea0 100644 --- a/physical/postgresql/postgresql.go +++ b/physical/postgresql/postgresql.go @@ -4,6 +4,7 @@ import ( "context" "database/sql" "fmt" + "os" "strconv" "strings" "sync" @@ -88,8 +89,8 @@ type PostgreSQLLock struct { // API client, server address, credentials, and database. func NewPostgreSQLBackend(conf map[string]string, logger log.Logger) (physical.Backend, error) { // Get the PostgreSQL credentials to perform read/write operations. - connURL, ok := conf["connection_url"] - if !ok || connURL == "" { + connURL := connectionURL(conf) + if connURL == "" { return nil, fmt.Errorf("missing connection_url") } @@ -197,6 +198,19 @@ func NewPostgreSQLBackend(conf map[string]string, logger log.Logger) (physical.B return m, nil } +// connectionURL first check the environment variables for a connection URL. If +// no connection URL exists in the environment variable, the Vault config file is +// checked. If neither the environment variables or the config file set the connection +// URL for the Postgres backend, because it is a required field, an error is returned. +func connectionURL(conf map[string]string) string { + connURL := conf["connection_url"] + if envURL := os.Getenv("VAULT_PG_CONNECTION_URL"); envURL != "" { + connURL = envURL + } + + return connURL +} + // splitKey is a helper to split a full path key into individual // parts: parentPath, path, key func (m *PostgreSQLBackend) splitKey(fullPath string) (string, string, string) { diff --git a/physical/postgresql/postgresql_test.go b/physical/postgresql/postgresql_test.go index 20cb8ae0b78b4..759e1a0673b19 100644 --- a/physical/postgresql/postgresql_test.go +++ b/physical/postgresql/postgresql_test.go @@ -114,6 +114,67 @@ func TestPostgreSQLBackendMaxIdleConnectionsParameter(t *testing.T) { } } +func TestConnectionURL(t *testing.T) { + type input struct { + envar string + conf map[string]string + } + + var cases = map[string]struct { + want string + input input + }{ + "environment_variable_not_set_use_config_value": { + want: "abc", + input: input{ + envar: "", + conf: map[string]string{"connection_url": "abc"}, + }, + }, + + "no_value_connection_url_set_key_exists": { + want: "", + input: input{ + envar: "", + conf: map[string]string{"connection_url": ""}, + }, + }, + + "no_value_connection_url_set_key_doesnt_exist": { + want: "", + input: input{ + envar: "", + conf: map[string]string{}, + }, + }, + + "environment_variable_set": { + want: "abc", + input: input{ + envar: "abc", + conf: map[string]string{"connection_url": "def"}, + }, + }, + } + + for name, tt := range cases { + t.Run(name, func(t *testing.T) { + // This is necessary to avoid always testing the branch where the env is set. + // As long the the env is set --- even if the value is "" --- `ok` returns true. + if tt.input.envar != "" { + os.Setenv("VAULT_PG_CONNECTION_URL", tt.input.envar) + defer os.Unsetenv("VAULT_PG_CONNECTION_URL") + } + + got := connectionURL(tt.input.conf) + + if got != tt.want { + t.Errorf("connectionURL(%s): want '%s', got '%s'", tt.input, tt.want, got) + } + }) + } +} + // Similar to testHABackend, but using internal implementation details to // trigger the lock failure scenario by setting the lock renew period for one // of the locks to a higher value than the lock TTL. diff --git a/website/source/docs/configuration/storage/postgresql.html.md b/website/source/docs/configuration/storage/postgresql.html.md index 8ee819520efa2..59c192cbfbf84 100644 --- a/website/source/docs/configuration/storage/postgresql.html.md +++ b/website/source/docs/configuration/storage/postgresql.html.md @@ -93,7 +93,8 @@ LANGUAGE plpgsql; ## `postgresql` Parameters - `connection_url` `(string: )` – Specifies the connection string to - use to authenticate and connect to PostgreSQL. A full list of supported + use to authenticate and connect to PostgreSQL. The connection URL can also be + set using the `VAULT_PG_CONNECTION_URL` environment variable. A full list of supported parameters can be found in [the pq library documentation][pglib]. For example connection string URLs, see the examples section below.