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.