From 3b352f34df0568ea91cebb2604f1d5bffb32de69 Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Tue, 1 Feb 2022 16:33:36 -0800 Subject: [PATCH 01/10] add username and password support to DBs --- ...urce_database_secret_backend_connection.go | 55 +++++++++++++--- ...database_secret_backend_connection_test.go | 62 ++++++++++++++++--- 2 files changed, 99 insertions(+), 18 deletions(-) diff --git a/vault/resource_database_secret_backend_connection.go b/vault/resource_database_secret_backend_connection.go index e99106c90..49e1eb938 100644 --- a/vault/resource_database_secret_backend_connection.go +++ b/vault/resource_database_secret_backend_connection.go @@ -485,6 +485,7 @@ func databaseSecretBackendConnectionResource() *schema.Resource { Description: "Connection parameters for the hana-database-plugin plugin.", Elem: connectionStringResource(&connectionStringConfig{ excludeUsernameTemplate: true, + includeUserPass: true, }), MaxItems: 1, ConflictsWith: util.CalculateConflictsWith(dbEngineHana.Name(), dbEngineTypes), @@ -533,10 +534,12 @@ func databaseSecretBackendConnectionResource() *schema.Resource { }, dbEnginePostgres.name: { - Type: schema.TypeList, - Optional: true, - Description: "Connection parameters for the postgresql-database-plugin plugin.", - Elem: connectionStringResource(&connectionStringConfig{}), + Type: schema.TypeList, + Optional: true, + Description: "Connection parameters for the postgresql-database-plugin plugin.", + Elem: connectionStringResource(&connectionStringConfig{ + includeUserPass: true, + }), MaxItems: 1, ConflictsWith: util.CalculateConflictsWith(dbEnginePostgres.Name(), dbEngineTypes), }, @@ -650,7 +653,9 @@ func mysqlConnectionStringResource() *schema.Resource { } func mssqlConnectionStringResource() *schema.Resource { - r := connectionStringResource(&connectionStringConfig{}) + r := connectionStringResource(&connectionStringConfig{ + includeUserPass: true, + }) r.Schema["contained_db"] = &schema.Schema{ Type: schema.TypeBool, Optional: true, @@ -729,7 +734,7 @@ func getDatabaseAPIData(d *schema.ResourceData) (map[string]interface{}, error) case dbEngineInfluxDB: setInfluxDBDatabaseConnectionData(d, "influxdb.0.", data) case dbEngineHana: - setDatabaseConnectionData(d, "hana.0.", data) + setDatabaseConnectionDataWithUserPass(d, "hana.0.", data) case dbEngineMongoDB: setDatabaseConnectionData(d, "mongodb.0.", data) case dbEngineMongoDBAtlas: @@ -755,7 +760,7 @@ func getDatabaseAPIData(d *schema.ResourceData) (map[string]interface{}, error) case dbEngineOracle: setDatabaseConnectionData(d, "oracle.0.", data) case dbEnginePostgres: - setDatabaseConnectionData(d, "postgresql.0.", data) + setDatabaseConnectionDataWithUserPass(d, "postgresql.0.", data) case dbEngineElasticSearch: setElasticsearchDatabaseConnectionData(d, "elasticsearch.0.", data) case dbEngineSnowflake: @@ -831,6 +836,13 @@ func getMSSQLConnectionDetailsFromResponse(d *schema.ResourceData, prefix string } result[0]["contained_db"] = containedDB } + if v, ok := details["username"]; ok { + result[0]["username"] = v.(string) + } + if v, ok := d.GetOk(prefix + "password"); ok { + result[0]["password"] = v.(string) + } + return result, nil } @@ -1015,6 +1027,23 @@ func getSnowflakeConnectionDetailsFromResponse(d *schema.ResourceData, prefix st return []map[string]interface{}{result} } +func getUserPassConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, resp *api.Secret) []map[string]interface{} { + result := getConnectionDetailsFromResponse(d, prefix, resp) + if result == nil { + return nil + } + + details := resp.Data["connection_details"].(map[string]interface{}) + if v, ok := details["username"]; ok { + result[0]["username"] = v.(string) + } + if v, ok := d.GetOk(prefix + "password"); ok { + result[0]["password"] = v.(string) + } + + return result +} + func setDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[string]interface{}) { if v, ok := d.GetOk(prefix + "connection_url"); ok { data["connection_url"] = v.(string) @@ -1042,6 +1071,12 @@ func setMSSQLDatabaseConnectionData(d *schema.ResourceData, prefix string, data // is released. data["contained_db"] = strconv.FormatBool(v.(bool)) } + if v, ok := d.GetOk(prefix + "username"); ok { + data["username"] = v.(string) + } + if v, ok := d.GetOk(prefix + "password"); ok { + data["password"] = v.(string) + } } func setMySQLDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[string]interface{}) { @@ -1284,7 +1319,7 @@ func databaseSecretBackendConnectionRead(d *schema.ResourceData, meta interface{ case dbEngineInfluxDB: d.Set("influxdb", getInfluxDBConnectionDetailsFromResponse(d, "influxdb.0.", resp)) case dbEngineHana: - d.Set("hana", getConnectionDetailsFromResponse(d, "hana.0.", resp)) + d.Set("hana", getUserPassConnectionDetailsFromResponse(d, "hana.0.", resp)) case dbEngineMongoDB: d.Set("mongodb", getConnectionDetailsFromResponse(d, "mongodb.0.", resp)) case dbEngineMongoDBAtlas: @@ -1321,13 +1356,13 @@ func databaseSecretBackendConnectionRead(d *schema.ResourceData, meta interface{ case dbEngineOracle: d.Set("oracle", getConnectionDetailsFromResponse(d, "oracle.0.", resp)) case dbEnginePostgres: - d.Set("postgresql", getConnectionDetailsFromResponse(d, "postgresql.0.", resp)) + d.Set("postgresql", getUserPassConnectionDetailsFromResponse(d, "postgresql.0.", resp)) case dbEngineElasticSearch: d.Set("elasticsearch", getElasticsearchConnectionDetailsFromResponse(d, "elasticsearch.0.", resp)) case dbEngineSnowflake: d.Set("snowflake", getSnowflakeConnectionDetailsFromResponse(d, "snowflake.0.", resp)) case dbEngineRedshift: - d.Set("redshift", getConnectionDetailsFromResponse(d, "redshift.0.", resp)) + d.Set("redshift", getUserPassConnectionDetailsFromResponse(d, "redshift.0.", resp)) default: return fmt.Errorf("no response handler for dbEngine: %s", db) } diff --git a/vault/resource_database_secret_backend_connection_test.go b/vault/resource_database_secret_backend_connection_test.go index e6a67ad0a..4a4d37d20 100644 --- a/vault/resource_database_secret_backend_connection_test.go +++ b/vault/resource_database_secret_backend_connection_test.go @@ -5,6 +5,7 @@ import ( "errors" "fmt" "log" + "net/url" "os" "reflect" "strings" @@ -46,7 +47,7 @@ func TestAccDatabaseSecretBackendConnection_import(t *testing.T) { CheckDestroy: testAccDatabaseSecretBackendConnectionCheckDestroy, Steps: []resource.TestStep{ { - Config: testAccDatabaseSecretBackendConnectionConfig_postgresql(name, backend, connURL, userTempl), + Config: testAccDatabaseSecretBackendConnectionConfig_import(name, backend, connURL, userTempl), Check: testComposeCheckFuncCommonDatabaseSecretBackend(name, backend, pluginName, resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.#", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.0", "dev"), @@ -322,13 +323,19 @@ func TestAccDatabaseSecretBackendConnection_mssql(t *testing.T) { pluginName := dbEngineMSSQL.DefaultPluginName() name := acctest.RandomWithPrefix("db") + parsedURL, err := url.Parse(connURL) + if err != nil { + t.Fatal(err) + } + + username := parsedURL.User.Username() resource.Test(t, resource.TestCase{ Providers: testProviders, PreCheck: func() { testutil.TestAccPreCheck(t) }, CheckDestroy: testAccDatabaseSecretBackendConnectionCheckDestroy, Steps: []resource.TestStep{ { - Config: testAccDatabaseSecretBackendConnectionConfig_mssql(name, backend, connURL, pluginName, false), + Config: testAccDatabaseSecretBackendConnectionConfig_mssql(name, backend, pluginName, parsedURL, false), Check: testComposeCheckFuncCommonDatabaseSecretBackend(name, backend, pluginName, resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.#", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.0", "dev"), @@ -340,11 +347,12 @@ func TestAccDatabaseSecretBackendConnection_mssql(t *testing.T) { resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mssql.0.max_open_connections", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mssql.0.max_idle_connections", "0"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mssql.0.max_connection_lifetime", "0"), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mssql.0.username", username), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mssql.0.contained_db", "false"), ), }, { - Config: testAccDatabaseSecretBackendConnectionConfig_mssql(name, backend, connURL, pluginName, true), + Config: testAccDatabaseSecretBackendConnectionConfig_mssql(name, backend, pluginName, parsedURL, true), Check: testComposeCheckFuncCommonDatabaseSecretBackend(name, backend, pluginName, resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "plugin_name", pluginName), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.#", "2"), @@ -357,6 +365,7 @@ func TestAccDatabaseSecretBackendConnection_mssql(t *testing.T) { resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mssql.0.max_open_connections", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mssql.0.max_idle_connections", "0"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mssql.0.max_connection_lifetime", "0"), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mssql.0.username", username), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mssql.0.contained_db", "true"), ), }, @@ -631,7 +640,12 @@ func TestAccDatabaseSecretBackendConnection_postgresql(t *testing.T) { // TODO: make these fatal once we auto provision the required test infrastructure. values := testutil.SkipTestEnvUnset(t, "POSTGRES_URL") connURL := values[0] + parsedURL, err := url.Parse(connURL) + if err != nil { + t.Fatal(err) + } + username := parsedURL.User.Username() backend := acctest.RandomWithPrefix("tf-test-db") pluginName := dbEnginePostgres.DefaultPluginName() name := acctest.RandomWithPrefix("db") @@ -642,7 +656,7 @@ func TestAccDatabaseSecretBackendConnection_postgresql(t *testing.T) { CheckDestroy: testAccDatabaseSecretBackendConnectionCheckDestroy, Steps: []resource.TestStep{ { - Config: testAccDatabaseSecretBackendConnectionConfig_postgresql(name, backend, connURL, userTempl), + Config: testAccDatabaseSecretBackendConnectionConfig_postgresql(name, backend, userTempl, parsedURL), Check: testComposeCheckFuncCommonDatabaseSecretBackend(name, backend, pluginName, resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.#", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.0", "dev"), @@ -654,6 +668,7 @@ func TestAccDatabaseSecretBackendConnection_postgresql(t *testing.T) { resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "postgresql.0.max_open_connections", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "postgresql.0.max_idle_connections", "0"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "postgresql.0.max_connection_lifetime", "0"), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "postgresql.0.username", username), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "postgresql.0.username_template", userTempl), ), }, @@ -848,6 +863,27 @@ resource "vault_database_secret_backend_connection" "test" { `, path, name, host, username, password) } +func testAccDatabaseSecretBackendConnectionConfig_import(name, path, connURL, userTempl string) string { + return fmt.Sprintf(` +resource "vault_mount" "db" { + path = "%s" + type = "database" +} + +resource "vault_database_secret_backend_connection" "test" { + backend = vault_mount.db.path + name = "%s" + allowed_roles = ["dev", "prod"] + root_rotation_statements = ["FOOBAR"] + + postgresql { + connection_url = "%s" + username_template = "%s" + } +} +`, path, name, connURL, userTempl) +} + func testAccDatabaseSecretBackendConnectionConfig_influxdb(name, path, host, username, password string) string { return fmt.Sprintf(` resource "vault_mount" "db" { @@ -955,18 +991,24 @@ resource "vault_database_secret_backend_connection" "test" { `, path, name, connURL) } -func testAccDatabaseSecretBackendConnectionConfig_mssql(name, path, connURL, pluginName string, containedDB bool) string { +func testAccDatabaseSecretBackendConnectionConfig_mssql(name, path, pluginName string, parsedURL *url.URL, containedDB bool) string { var config string + password, _ := parsedURL.User.Password() + if containedDB { config = ` mssql { connection_url = "%s" + username = "%s" + password = "%s" contained_db = true }` } else { config = ` mssql { connection_url = "%s" + username = "%s" + password = "%s" }` } @@ -984,7 +1026,7 @@ resource "vault_database_secret_backend_connection" "test" { root_rotation_statements = ["FOOBAR"] %s } -`, path, pluginName, name, fmt.Sprintf(config, connURL)) +`, path, pluginName, name, fmt.Sprintf(config, parsedURL.String(), parsedURL.User.Username(), password)) return result } @@ -1153,7 +1195,9 @@ resource "vault_database_secret_backend_connection" "test" { `, path, name, connURL) } -func testAccDatabaseSecretBackendConnectionConfig_postgresql(name, path, connURL, userTempl string) string { +func testAccDatabaseSecretBackendConnectionConfig_postgresql(name, path, userTempl string, parsedURL *url.URL) string { + password, _ := parsedURL.User.Password() + return fmt.Sprintf(` resource "vault_mount" "db" { path = "%s" @@ -1168,10 +1212,12 @@ resource "vault_database_secret_backend_connection" "test" { postgresql { connection_url = "%s" + username = "%s" + password = "%s" username_template = "%s" } } -`, path, name, connURL, userTempl) +`, path, name, parsedURL.String(), parsedURL.User.Username(), password, userTempl) } func testAccDatabaseSecretBackendConnectionConfig_snowflake(name, path, url, username, password, userTempl string) string { From 2d5026d518f6231b72128529b6b206cdf49b73c2 Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Tue, 1 Feb 2022 16:46:02 -0800 Subject: [PATCH 02/10] update changelog --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index db4cbe55a..ca33a5304 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,7 @@ BUGS: IMPROVEMENTS: * `resource/token_auth_backend_role`: Add `allowed_policies_glob` and `disallowed_polices_glob` ([#1316](https://github.com/hashicorp/terraform-provider-vault/pull/1316)) * `resource/database_secret_backend_connection`: Add support for configuring the secret engine's `plugin_name` ([#1320](https://github.com/hashicorp/terraform-provider-vault/pull/1320)) +* `resource/database_secret_backend_connection`: Add `username` and `password` support to Redshift, Hana, Postgres and MSSQL ([#1331](https://github.com/hashicorp/terraform-provider-vault/pull/1331)) ## 3.2.1 (January 20, 2022) BUGS: From 98e69855b51fbe388ec0d53b6b1344b101223e58 Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Wed, 2 Feb 2022 15:19:05 -0800 Subject: [PATCH 03/10] remove unnecessary duplications od user pass schema in MSSQL --- ...esource_database_secret_backend_connection.go | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/vault/resource_database_secret_backend_connection.go b/vault/resource_database_secret_backend_connection.go index 49e1eb938..7f121ca7e 100644 --- a/vault/resource_database_secret_backend_connection.go +++ b/vault/resource_database_secret_backend_connection.go @@ -823,7 +823,7 @@ func getConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, res } func getMSSQLConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, resp *api.Secret) ([]map[string]interface{}, error) { - result := getConnectionDetailsFromResponse(d, prefix, resp) + result := getUserPassConnectionDetailsFromResponse(d, prefix, resp) if result == nil { return nil, nil } @@ -836,12 +836,6 @@ func getMSSQLConnectionDetailsFromResponse(d *schema.ResourceData, prefix string } result[0]["contained_db"] = containedDB } - if v, ok := details["username"]; ok { - result[0]["username"] = v.(string) - } - if v, ok := d.GetOk(prefix + "password"); ok { - result[0]["password"] = v.(string) - } return result, nil } @@ -1063,7 +1057,7 @@ func setDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[s } func setMSSQLDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[string]interface{}) { - setDatabaseConnectionData(d, prefix, data) + setDatabaseConnectionDataWithUserPass(d, prefix, data) if v, ok := d.GetOk(prefix + "contained_db"); ok { // TODO: // we have to pass string value here due to an issue with the @@ -1071,12 +1065,6 @@ func setMSSQLDatabaseConnectionData(d *schema.ResourceData, prefix string, data // is released. data["contained_db"] = strconv.FormatBool(v.(bool)) } - if v, ok := d.GetOk(prefix + "username"); ok { - data["username"] = v.(string) - } - if v, ok := d.GetOk(prefix + "password"); ok { - data["password"] = v.(string) - } } func setMySQLDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[string]interface{}) { From f526a7fe61f11ed9a08c181f5da916d056978b5d Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Wed, 2 Feb 2022 15:23:22 -0800 Subject: [PATCH 04/10] renameget user pass function --- vault/resource_database_secret_backend_connection.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vault/resource_database_secret_backend_connection.go b/vault/resource_database_secret_backend_connection.go index 7f121ca7e..ebe4b8847 100644 --- a/vault/resource_database_secret_backend_connection.go +++ b/vault/resource_database_secret_backend_connection.go @@ -823,7 +823,7 @@ func getConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, res } func getMSSQLConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, resp *api.Secret) ([]map[string]interface{}, error) { - result := getUserPassConnectionDetailsFromResponse(d, prefix, resp) + result := getConnectionDetailsFromResponseWithUserPass(d, prefix, resp) if result == nil { return nil, nil } @@ -1021,7 +1021,7 @@ func getSnowflakeConnectionDetailsFromResponse(d *schema.ResourceData, prefix st return []map[string]interface{}{result} } -func getUserPassConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, resp *api.Secret) []map[string]interface{} { +func getConnectionDetailsFromResponseWithUserPass(d *schema.ResourceData, prefix string, resp *api.Secret) []map[string]interface{} { result := getConnectionDetailsFromResponse(d, prefix, resp) if result == nil { return nil @@ -1307,7 +1307,7 @@ func databaseSecretBackendConnectionRead(d *schema.ResourceData, meta interface{ case dbEngineInfluxDB: d.Set("influxdb", getInfluxDBConnectionDetailsFromResponse(d, "influxdb.0.", resp)) case dbEngineHana: - d.Set("hana", getUserPassConnectionDetailsFromResponse(d, "hana.0.", resp)) + d.Set("hana", getConnectionDetailsFromResponseWithUserPass(d, "hana.0.", resp)) case dbEngineMongoDB: d.Set("mongodb", getConnectionDetailsFromResponse(d, "mongodb.0.", resp)) case dbEngineMongoDBAtlas: @@ -1344,13 +1344,13 @@ func databaseSecretBackendConnectionRead(d *schema.ResourceData, meta interface{ case dbEngineOracle: d.Set("oracle", getConnectionDetailsFromResponse(d, "oracle.0.", resp)) case dbEnginePostgres: - d.Set("postgresql", getUserPassConnectionDetailsFromResponse(d, "postgresql.0.", resp)) + d.Set("postgresql", getConnectionDetailsFromResponseWithUserPass(d, "postgresql.0.", resp)) case dbEngineElasticSearch: d.Set("elasticsearch", getElasticsearchConnectionDetailsFromResponse(d, "elasticsearch.0.", resp)) case dbEngineSnowflake: d.Set("snowflake", getSnowflakeConnectionDetailsFromResponse(d, "snowflake.0.", resp)) case dbEngineRedshift: - d.Set("redshift", getUserPassConnectionDetailsFromResponse(d, "redshift.0.", resp)) + d.Set("redshift", getConnectionDetailsFromResponseWithUserPass(d, "redshift.0.", resp)) default: return fmt.Errorf("no response handler for dbEngine: %s", db) } From daae4189ced5237352ba69f7a70565cdc431a6ea Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Fri, 4 Feb 2022 11:46:47 -0800 Subject: [PATCH 05/10] add username and password to all DBs except mongoDB atlas --- ...urce_database_secret_backend_connection.go | 99 +++++++++++-------- ...database_secret_backend_connection_test.go | 72 +++++++------- 2 files changed, 96 insertions(+), 75 deletions(-) diff --git a/vault/resource_database_secret_backend_connection.go b/vault/resource_database_secret_backend_connection.go index ebe4b8847..2292a414b 100644 --- a/vault/resource_database_secret_backend_connection.go +++ b/vault/resource_database_secret_backend_connection.go @@ -443,10 +443,12 @@ func databaseSecretBackendConnectionResource() *schema.Resource { }, dbEngineMongoDB.name: { - Type: schema.TypeList, - Optional: true, - Description: "Connection parameters for the mongodb-database-plugin plugin.", - Elem: connectionStringResource(&connectionStringConfig{}), + Type: schema.TypeList, + Optional: true, + Description: "Connection parameters for the mongodb-database-plugin plugin.", + Elem: connectionStringResource(&connectionStringConfig{ + includeUserPass: true, + }), MaxItems: 1, ConflictsWith: util.CalculateConflictsWith(dbEngineMongoDB.Name(), dbEngineTypes), }, @@ -509,26 +511,32 @@ func databaseSecretBackendConnectionResource() *schema.Resource { ConflictsWith: util.CalculateConflictsWith(dbEngineMySQL.Name(), dbEngineTypes), }, dbEngineMySQLRDS.name: { - Type: schema.TypeList, - Optional: true, - Description: "Connection parameters for the mysql-rds-database-plugin plugin.", - Elem: connectionStringResource(&connectionStringConfig{}), + Type: schema.TypeList, + Optional: true, + Description: "Connection parameters for the mysql-rds-database-plugin plugin.", + Elem: connectionStringResource(&connectionStringConfig{ + includeUserPass: true, + }), MaxItems: 1, ConflictsWith: util.CalculateConflictsWith(dbEngineMySQLRDS.Name(), dbEngineTypes), }, dbEngineMySQLAurora.name: { - Type: schema.TypeList, - Optional: true, - Description: "Connection parameters for the mysql-aurora-database-plugin plugin.", - Elem: connectionStringResource(&connectionStringConfig{}), + Type: schema.TypeList, + Optional: true, + Description: "Connection parameters for the mysql-aurora-database-plugin plugin.", + Elem: connectionStringResource(&connectionStringConfig{ + includeUserPass: true, + }), MaxItems: 1, ConflictsWith: util.CalculateConflictsWith(dbEngineMySQLAurora.Name(), dbEngineTypes), }, dbEngineMySQLLegacy.name: { - Type: schema.TypeList, - Optional: true, - Description: "Connection parameters for the mysql-legacy-database-plugin plugin.", - Elem: connectionStringResource(&connectionStringConfig{}), + Type: schema.TypeList, + Optional: true, + Description: "Connection parameters for the mysql-legacy-database-plugin plugin.", + Elem: connectionStringResource(&connectionStringConfig{ + includeUserPass: true, + }), MaxItems: 1, ConflictsWith: util.CalculateConflictsWith(dbEngineMySQLLegacy.Name(), dbEngineTypes), }, @@ -545,28 +553,34 @@ func databaseSecretBackendConnectionResource() *schema.Resource { }, dbEngineOracle.name: { - Type: schema.TypeList, - Optional: true, - Description: "Connection parameters for the oracle-database-plugin plugin.", - Elem: connectionStringResource(&connectionStringConfig{}), + Type: schema.TypeList, + Optional: true, + Description: "Connection parameters for the oracle-database-plugin plugin.", + Elem: connectionStringResource(&connectionStringConfig{ + includeUserPass: true, + }), MaxItems: 1, ConflictsWith: util.CalculateConflictsWith(dbEngineOracle.Name(), dbEngineTypes), }, dbEngineRedshift.name: { - Type: schema.TypeList, - Optional: true, - Description: "Connection parameters for the redshift-database-plugin plugin.", - Elem: connectionStringResource(&connectionStringConfig{includeUserPass: true}), + Type: schema.TypeList, + Optional: true, + Description: "Connection parameters for the redshift-database-plugin plugin.", + Elem: connectionStringResource(&connectionStringConfig{ + includeUserPass: true, + }), MaxItems: 1, ConflictsWith: util.CalculateConflictsWith(dbEngineRedshift.Name(), dbEngineTypes), }, dbEngineSnowflake.name: { - Type: schema.TypeList, - Optional: true, - Description: "Connection parameters for the snowflake-database-plugin plugin.", - Elem: connectionStringResource(&connectionStringConfig{includeUserPass: true}), + Type: schema.TypeList, + Optional: true, + Description: "Connection parameters for the snowflake-database-plugin plugin.", + Elem: connectionStringResource(&connectionStringConfig{ + includeUserPass: true, + }), MaxItems: 1, ConflictsWith: util.CalculateConflictsWith(dbEngineSnowflake.Name(), dbEngineTypes), }, @@ -637,7 +651,9 @@ func connectionStringResource(config *connectionStringConfig) *schema.Resource { } func mysqlConnectionStringResource() *schema.Resource { - r := connectionStringResource(&connectionStringConfig{}) + r := connectionStringResource(&connectionStringConfig{ + includeUserPass: true, + }) r.Schema["tls_certificate_key"] = &schema.Schema{ Type: schema.TypeString, Optional: true, @@ -736,7 +752,7 @@ func getDatabaseAPIData(d *schema.ResourceData) (map[string]interface{}, error) case dbEngineHana: setDatabaseConnectionDataWithUserPass(d, "hana.0.", data) case dbEngineMongoDB: - setDatabaseConnectionData(d, "mongodb.0.", data) + setDatabaseConnectionDataWithUserPass(d, "mongodb.0.", data) case dbEngineMongoDBAtlas: if v, ok := d.GetOk("mongodbatlas.0.public_key"); ok { data["public_key"] = v.(string) @@ -752,13 +768,13 @@ func getDatabaseAPIData(d *schema.ResourceData) (map[string]interface{}, error) case dbEngineMySQL: setMySQLDatabaseConnectionData(d, "mysql.0.", data) case dbEngineMySQLRDS: - setDatabaseConnectionData(d, "mysql_rds.0.", data) + setDatabaseConnectionDataWithUserPass(d, "mysql_rds.0.", data) case dbEngineMySQLAurora: - setDatabaseConnectionData(d, "mysql_aurora.0.", data) + setDatabaseConnectionDataWithUserPass(d, "mysql_aurora.0.", data) case dbEngineMySQLLegacy: - setDatabaseConnectionData(d, "mysql_legacy.0.", data) + setDatabaseConnectionDataWithUserPass(d, "mysql_legacy.0.", data) case dbEngineOracle: - setDatabaseConnectionData(d, "oracle.0.", data) + setDatabaseConnectionDataWithUserPass(d, "oracle.0.", data) case dbEnginePostgres: setDatabaseConnectionDataWithUserPass(d, "postgresql.0.", data) case dbEngineElasticSearch: @@ -841,7 +857,7 @@ func getMSSQLConnectionDetailsFromResponse(d *schema.ResourceData, prefix string } func getMySQLConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, resp *api.Secret) []map[string]interface{} { - commonDetails := getConnectionDetailsFromResponse(d, prefix, resp) + commonDetails := getConnectionDetailsFromResponseWithUserPass(d, prefix, resp) details := resp.Data["connection_details"] data, ok := details.(map[string]interface{}) if !ok { @@ -990,6 +1006,7 @@ func getInfluxDBConnectionDetailsFromResponse(d *schema.ResourceData, prefix str } func getSnowflakeConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, resp *api.Secret) []map[string]interface{} { + // TODO Clarify Snowflake behavior commonDetails := getConnectionDetailsFromResponse(d, prefix, resp) details := resp.Data["connection_details"] data, ok := details.(map[string]interface{}) @@ -1068,7 +1085,7 @@ func setMSSQLDatabaseConnectionData(d *schema.ResourceData, prefix string, data } func setMySQLDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[string]interface{}) { - setDatabaseConnectionData(d, prefix, data) + setDatabaseConnectionDataWithUserPass(d, prefix, data) if v, ok := d.GetOk(prefix + "tls_certificate_key"); ok { data["tls_certificate_key"] = v.(string) } @@ -1309,7 +1326,7 @@ func databaseSecretBackendConnectionRead(d *schema.ResourceData, meta interface{ case dbEngineHana: d.Set("hana", getConnectionDetailsFromResponseWithUserPass(d, "hana.0.", resp)) case dbEngineMongoDB: - d.Set("mongodb", getConnectionDetailsFromResponse(d, "mongodb.0.", resp)) + d.Set("mongodb", getConnectionDetailsFromResponseWithUserPass(d, "mongodb.0.", resp)) case dbEngineMongoDBAtlas: details := resp.Data["connection_details"] data, ok := details.(map[string]interface{}) @@ -1336,13 +1353,13 @@ func databaseSecretBackendConnectionRead(d *schema.ResourceData, meta interface{ case dbEngineMySQL: d.Set("mysql", getMySQLConnectionDetailsFromResponse(d, "mysql.0.", resp)) case dbEngineMySQLRDS: - d.Set("mysql_rds", getConnectionDetailsFromResponse(d, "mysql_rds.0.", resp)) + d.Set("mysql_rds", getConnectionDetailsFromResponseWithUserPass(d, "mysql_rds.0.", resp)) case dbEngineMySQLAurora: - d.Set("mysql_aurora", getConnectionDetailsFromResponse(d, "mysql_aurora.0.", resp)) + d.Set("mysql_aurora", getConnectionDetailsFromResponseWithUserPass(d, "mysql_aurora.0.", resp)) case dbEngineMySQLLegacy: - d.Set("mysql_legacy", getConnectionDetailsFromResponse(d, "mysql_legacy.0.", resp)) + d.Set("mysql_legacy", getConnectionDetailsFromResponseWithUserPass(d, "mysql_legacy.0.", resp)) case dbEngineOracle: - d.Set("oracle", getConnectionDetailsFromResponse(d, "oracle.0.", resp)) + d.Set("oracle", getConnectionDetailsFromResponseWithUserPass(d, "oracle.0.", resp)) case dbEnginePostgres: d.Set("postgresql", getConnectionDetailsFromResponseWithUserPass(d, "postgresql.0.", resp)) case dbEngineElasticSearch: diff --git a/vault/resource_database_secret_backend_connection_test.go b/vault/resource_database_secret_backend_connection_test.go index 4a4d37d20..f15abd706 100644 --- a/vault/resource_database_secret_backend_connection_test.go +++ b/vault/resource_database_secret_backend_connection_test.go @@ -377,20 +377,21 @@ func TestAccDatabaseSecretBackendConnection_mysql(t *testing.T) { MaybeSkipDBTests(t, dbEngineMySQL) // TODO: make these fatal once we auto provision the required test infrastructure. - values := testutil.SkipTestEnvUnset(t, "MYSQL_URL") + values := testutil.SkipTestEnvUnset(t, "MYSQL_URL", "MYSQL_USER", "MYSQL_PASSWORD") connURL := values[0] + username := values[1] + password := values[2] backend := acctest.RandomWithPrefix("tf-test-db") pluginName := dbEngineMySQL.DefaultPluginName() name := acctest.RandomWithPrefix("db") - password := acctest.RandomWithPrefix("password") resource.Test(t, resource.TestCase{ Providers: testProviders, PreCheck: func() { testutil.TestAccPreCheck(t) }, CheckDestroy: testAccDatabaseSecretBackendConnectionCheckDestroy, Steps: []resource.TestStep{ { - Config: testAccDatabaseSecretBackendConnectionConfig_mysql(name, backend, connURL, password), + Config: testAccDatabaseSecretBackendConnectionConfig_mysql(name, backend, connURL, username, password), Check: testComposeCheckFuncCommonDatabaseSecretBackend(name, backend, pluginName, resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.#", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.0", "dev"), @@ -399,15 +400,14 @@ func TestAccDatabaseSecretBackendConnection_mysql(t *testing.T) { resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "root_rotation_statements.0", "FOOBAR"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "verify_connection", "true"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.connection_url", connURL), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.username", username), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.max_open_connections", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.max_idle_connections", "0"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.max_connection_lifetime", "0"), - resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "data.%", "1"), - resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "data.password", password), ), }, { - Config: testAccDatabaseSecretBackendConnectionConfig_mysql_rds(name, backend, connURL), + Config: testAccDatabaseSecretBackendConnectionConfig_mysql_rds(name, backend, connURL, username, password), Check: testComposeCheckFuncCommonDatabaseSecretBackend(name, backend, pluginName, resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.#", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.0", "dev"), @@ -416,13 +416,14 @@ func TestAccDatabaseSecretBackendConnection_mysql(t *testing.T) { resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "root_rotation_statements.0", "FOOBAR"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "verify_connection", "true"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_rds.0.connection_url", connURL), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_rds.0.username", username), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_rds.0.max_open_connections", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_rds.0.max_idle_connections", "0"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_rds.0.max_connection_lifetime", "0"), ), }, { - Config: testAccDatabaseSecretBackendConnectionConfig_mysql_aurora(name, backend, connURL), + Config: testAccDatabaseSecretBackendConnectionConfig_mysql_aurora(name, backend, connURL, username, password), Check: testComposeCheckFuncCommonDatabaseSecretBackend(name, backend, pluginName, resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.#", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.0", "dev"), @@ -431,13 +432,14 @@ func TestAccDatabaseSecretBackendConnection_mysql(t *testing.T) { resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "root_rotation_statements.0", "FOOBAR"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "verify_connection", "true"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_aurora.0.connection_url", connURL), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_aurora.0.username", username), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_aurora.0.max_open_connections", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_aurora.0.max_idle_connections", "0"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_aurora.0.max_connection_lifetime", "0"), ), }, { - Config: testAccDatabaseSecretBackendConnectionConfig_mysql_legacy(name, backend, connURL), + Config: testAccDatabaseSecretBackendConnectionConfig_mysql_legacy(name, backend, connURL, username, password), Check: testComposeCheckFuncCommonDatabaseSecretBackend(name, backend, pluginName, resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.#", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.0", "dev"), @@ -446,6 +448,7 @@ func TestAccDatabaseSecretBackendConnection_mysql(t *testing.T) { resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "root_rotation_statements.0", "FOOBAR"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "verify_connection", "true"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_legacy.0.connection_url", connURL), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_legacy.0.username", username), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_legacy.0.max_open_connections", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_legacy.0.max_idle_connections", "0"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql_legacy.0.max_connection_lifetime", "0"), @@ -470,20 +473,21 @@ func TestAccDatabaseSecretBackendConnectionUpdate_mysql(t *testing.T) { MaybeSkipDBTests(t, dbEngineMySQL) // TODO: make these fatal once we auto provision the required test infrastructure. - values := testutil.SkipTestEnvUnset(t, "MYSQL_URL") + values := testutil.SkipTestEnvUnset(t, "MYSQL_URL", "MYSQL_USER", "MYSQL_PASSWORD") connURL := values[0] + username := values[1] + password := values[2] backend := acctest.RandomWithPrefix("tf-test-db") pluginName := dbEngineMySQL.DefaultPluginName() name := acctest.RandomWithPrefix("db") - password := acctest.RandomWithPrefix("password") resource.Test(t, resource.TestCase{ Providers: testProviders, PreCheck: func() { testutil.TestAccPreCheck(t) }, CheckDestroy: testAccDatabaseSecretBackendConnectionCheckDestroy, Steps: []resource.TestStep{ { - Config: testAccDatabaseSecretBackendConnectionConfigUpdate_mysql(name, backend, connURL, password, 0), + Config: testAccDatabaseSecretBackendConnectionConfigUpdate_mysql(name, backend, connURL, username, password, 0), Check: testComposeCheckFuncCommonDatabaseSecretBackend(name, backend, pluginName, resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.#", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.0", "dev"), @@ -492,14 +496,13 @@ func TestAccDatabaseSecretBackendConnectionUpdate_mysql(t *testing.T) { resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "root_rotation_statements.0", "FOOBAR"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "verify_connection", "true"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.connection_url", connURL), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.username", username), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.max_open_connections", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.max_connection_lifetime", "0"), - resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "data.%", "1"), - resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "data.password", password), ), }, { - Config: testAccDatabaseSecretBackendConnectionConfigUpdate_mysql(name, backend, connURL, password, 10), + Config: testAccDatabaseSecretBackendConnectionConfigUpdate_mysql(name, backend, connURL, username, password, 10), Check: testComposeCheckFuncCommonDatabaseSecretBackend(name, backend, pluginName, resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.#", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.0", "dev"), @@ -508,10 +511,9 @@ func TestAccDatabaseSecretBackendConnectionUpdate_mysql(t *testing.T) { resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "root_rotation_statements.0", "FOOBAR"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "verify_connection", "true"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.connection_url", connURL), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.username", username), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.max_open_connections", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.max_connection_lifetime", "10"), - resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "data.%", "1"), - resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "data.password", password), ), }, }, @@ -1031,7 +1033,7 @@ resource "vault_database_secret_backend_connection" "test" { return result } -func testAccDatabaseSecretBackendConnectionConfig_mysql(name, path, connURL, password string) string { +func testAccDatabaseSecretBackendConnectionConfig_mysql(name, path, connURL, username, password string) string { return fmt.Sprintf(` resource "vault_mount" "db" { path = "%s" @@ -1046,16 +1048,14 @@ resource "vault_database_secret_backend_connection" "test" { mysql { connection_url = "%s" - } - - data = { - password = "%s" + username = "%s" + password = "%s" } } -`, path, name, connURL, password) +`, path, name, connURL, username, password) } -func testAccDatabaseSecretBackendConnectionConfigUpdate_mysql(name, path, connURL, password string, connLifetime int) string { +func testAccDatabaseSecretBackendConnectionConfigUpdate_mysql(name, path, connURL, username, password string, connLifetime int) string { return fmt.Sprintf(` resource "vault_mount" "db" { path = "%s" @@ -1070,14 +1070,12 @@ resource "vault_database_secret_backend_connection" "test" { mysql { connection_url = "%s" + username = "%s" + password = "%s" max_connection_lifetime = "%d" } - - data = { - password = "%s" - } } -`, path, name, connURL, connLifetime, password) +`, path, name, connURL, username, password, connLifetime) } func testAccDatabaseSecretBackendConnectionConfig_mysql_tls(name, path, connURL, password, tls_ca, tls_certificate_key string) string { @@ -1135,7 +1133,7 @@ resource "vault_database_secret_backend_connection" "test" { `, path, name, connURL, connLifetime, username, password) } -func testAccDatabaseSecretBackendConnectionConfig_mysql_rds(name, path, connURL string) string { +func testAccDatabaseSecretBackendConnectionConfig_mysql_rds(name, path, connURL, username, password string) string { return fmt.Sprintf(` resource "vault_mount" "db" { path = "%s" @@ -1150,12 +1148,14 @@ resource "vault_database_secret_backend_connection" "test" { mysql_rds { connection_url = "%s" + username = "%s" + password = "%s" } } -`, path, name, connURL) +`, path, name, connURL, username, password) } -func testAccDatabaseSecretBackendConnectionConfig_mysql_aurora(name, path, connURL string) string { +func testAccDatabaseSecretBackendConnectionConfig_mysql_aurora(name, path, connURL, username, password string) string { return fmt.Sprintf(` resource "vault_mount" "db" { path = "%s" @@ -1170,12 +1170,14 @@ resource "vault_database_secret_backend_connection" "test" { mysql_aurora { connection_url = "%s" + username = "%s" + password = "%s" } } -`, path, name, connURL) +`, path, name, connURL, username, password) } -func testAccDatabaseSecretBackendConnectionConfig_mysql_legacy(name, path, connURL string) string { +func testAccDatabaseSecretBackendConnectionConfig_mysql_legacy(name, path, connURL, username, password string) string { return fmt.Sprintf(` resource "vault_mount" "db" { path = "%s" @@ -1190,9 +1192,11 @@ resource "vault_database_secret_backend_connection" "test" { mysql_legacy { connection_url = "%s" + username = "%s" + password = "%s" } } -`, path, name, connURL) +`, path, name, connURL, username, password) } func testAccDatabaseSecretBackendConnectionConfig_postgresql(name, path, userTempl string, parsedURL *url.URL) string { From 6ada5fd699be413bd6bb8ed0831c7dbec294ac1f Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Fri, 4 Feb 2022 11:50:58 -0800 Subject: [PATCH 06/10] update snowflake get method --- vault/resource_database_secret_backend_connection.go | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/vault/resource_database_secret_backend_connection.go b/vault/resource_database_secret_backend_connection.go index 2292a414b..b074fac8f 100644 --- a/vault/resource_database_secret_backend_connection.go +++ b/vault/resource_database_secret_backend_connection.go @@ -1006,8 +1006,7 @@ func getInfluxDBConnectionDetailsFromResponse(d *schema.ResourceData, prefix str } func getSnowflakeConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, resp *api.Secret) []map[string]interface{} { - // TODO Clarify Snowflake behavior - commonDetails := getConnectionDetailsFromResponse(d, prefix, resp) + commonDetails := getConnectionDetailsFromResponseWithUserPass(d, prefix, resp) details := resp.Data["connection_details"] data, ok := details.(map[string]interface{}) if !ok { From 8b2008291746d96778d13e941fda4aafacce9666 Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Fri, 4 Feb 2022 11:55:24 -0800 Subject: [PATCH 07/10] update changelog --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index f3264f153..508bec3c9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,7 +9,7 @@ IMPROVEMENTS: * `resource/pki_secret_backend_root_sign_intermediate`: Update schema for `ca_chain` from string to a list of `issuing_ca` and `certificate`, add new `certificate_bundle` attribute that provides the concatenation of the intermediate and issuing CA certificates (PEM encoded) ([#1330](https://github.com/hashicorp/terraform-provider-vault/pull/1330)) -* `resource/database_secret_backend_connection`: Add `username` and `password` support to Redshift, Hana, Postgres and MSSQL ([#1331](https://github.com/hashicorp/terraform-provider-vault/pull/1331)) +* `resource/database_secret_backend_connection`: Add `username` and `password` fields to all DB Engines that support them ([#1331](https://github.com/hashicorp/terraform-provider-vault/pull/1331)) ## 3.2.1 (January 20, 2022) BUGS: From ea89ebfc31da22f05afa5b882482748c7ecad265 Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Fri, 4 Feb 2022 14:29:43 -0800 Subject: [PATCH 08/10] fix templated mysql test --- ...database_secret_backend_connection_test.go | 20 ++++++------------- 1 file changed, 6 insertions(+), 14 deletions(-) diff --git a/vault/resource_database_secret_backend_connection_test.go b/vault/resource_database_secret_backend_connection_test.go index f15abd706..ff63f701f 100644 --- a/vault/resource_database_secret_backend_connection_test.go +++ b/vault/resource_database_secret_backend_connection_test.go @@ -549,31 +549,29 @@ func TestAccDatabaseSecretBackendConnectionTemplatedUpdateExcludePassword_mysql( createMySQSUser(t, db, testUsername, testPassword) defer deleteMySQLUser(t, db, testUsername) - client := testProvider.Meta().(*api.Client) - resource.Test(t, resource.TestCase{ Providers: testProviders, PreCheck: func() { testutil.TestAccPreCheck(t) }, CheckDestroy: testAccDatabaseSecretBackendConnectionCheckDestroy, Steps: []resource.TestStep{ { - Config: testAccDatabaseSecretBackendConnectionConfigTemplated_mysql(name, backend, testConnURL, testUsername, testPassword, 0), + Config: testAccDatabaseSecretBackendConnectionConfigTemplated_mysql(name, backend, testConnURL, username, password, 0), Check: testComposeCheckFuncCommonDatabaseSecretBackend(name, backend, pluginName, resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.#", "2"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.0", "dev"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.1", "prod"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "verify_connection", "true"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.connection_url", testConnURL), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.username", username), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.password", password), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.max_connection_lifetime", "0"), - resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "data.%", "2"), - resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "data.username", testUsername), - resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "data.password", testPassword), ), }, { Config: testAccDatabaseSecretBackendConnectionConfigTemplated_mysql(name, backend, testConnURL, testUsername, testPassword, 10), PreConfig: func() { path := fmt.Sprintf("%s/rotate-root/%s", backend, name) + client := testProvider.Meta().(*api.Client) resp, err := client.Logical().Write(path, map[string]interface{}{}) if err != nil { t.Error(err) @@ -588,9 +586,6 @@ func TestAccDatabaseSecretBackendConnectionTemplatedUpdateExcludePassword_mysql( resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "verify_connection", "true"), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.connection_url", testConnURL), resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.max_connection_lifetime", "10"), - resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "data.%", "2"), - resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "data.username", testUsername), - resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "data.password", testPassword), ), }, }, @@ -1123,11 +1118,8 @@ resource "vault_database_secret_backend_connection" "test" { mysql { connection_url = "%s" max_connection_lifetime = "%d" - } - - data = { - username = "%s" - password = "%s" + username = "%s" + password = "%s" } } `, path, name, connURL, connLifetime, username, password) From 3ddbcba39c68c61e593f05eedc82512fdf05881f Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Fri, 4 Feb 2022 14:35:20 -0800 Subject: [PATCH 09/10] update changelog --- CHANGELOG.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2db91a6e1..2d255d101 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,9 +12,6 @@ IMPROVEMENTS: * `resource/azure_secret_backend`: Add support for setting `use_microsoft_graph_api` ([#1335](https://github.com/hashicorp/terraform-provider-vault/pull/1335)) * `resource/database_secret_backend_connection`: Add `username` and `password` fields to all DB Engines that support them ([#1331](https://github.com/hashicorp/terraform-provider-vault/pull/1331)) - - - ## 3.2.1 (January 20, 2022) BUGS: * `resource/rabbitmq_secret_backend_role`: Add nil check when reading RabbitMQ role from Vault ([#1312](https://github.com/hashicorp/terraform-provider-vault/pull/1312)) From 2d7e0994c18d7e6cb61ec6c6271afc70968045d3 Mon Sep 17 00:00:00 2001 From: Ben Ash <32777270+benashz@users.noreply.github.com> Date: Thu, 10 Feb 2022 16:40:32 -0500 Subject: [PATCH 10/10] Prevent rotate root test from breaking the other MySQL tests (#1340) - ensure related MySQL tests run in CI --- ...database_secret_backend_connection_test.go | 48 +++++++++++++------ 1 file changed, 33 insertions(+), 15 deletions(-) diff --git a/vault/resource_database_secret_backend_connection_test.go b/vault/resource_database_secret_backend_connection_test.go index ff63f701f..44bad1679 100644 --- a/vault/resource_database_secret_backend_connection_test.go +++ b/vault/resource_database_secret_backend_connection_test.go @@ -377,10 +377,9 @@ func TestAccDatabaseSecretBackendConnection_mysql(t *testing.T) { MaybeSkipDBTests(t, dbEngineMySQL) // TODO: make these fatal once we auto provision the required test infrastructure. - values := testutil.SkipTestEnvUnset(t, "MYSQL_URL", "MYSQL_USER", "MYSQL_PASSWORD") - connURL := values[0] - username := values[1] - password := values[2] + values := testutil.SkipTestEnvUnset(t, + "MYSQL_CONNECTION_URL", "MYSQL_CONNECTION_USERNAME", "MYSQL_CONNECTION_PASSWORD") + connURL, username, password := values[0], values[1], values[2] backend := acctest.RandomWithPrefix("tf-test-db") pluginName := dbEngineMySQL.DefaultPluginName() @@ -473,10 +472,9 @@ func TestAccDatabaseSecretBackendConnectionUpdate_mysql(t *testing.T) { MaybeSkipDBTests(t, dbEngineMySQL) // TODO: make these fatal once we auto provision the required test infrastructure. - values := testutil.SkipTestEnvUnset(t, "MYSQL_URL", "MYSQL_USER", "MYSQL_PASSWORD") - connURL := values[0] - username := values[1] - password := values[2] + values := testutil.SkipTestEnvUnset(t, + "MYSQL_CONNECTION_URL", "MYSQL_CONNECTION_USERNAME", "MYSQL_CONNECTION_PASSWORD") + connURL, username, password := values[0], values[1], values[2] backend := acctest.RandomWithPrefix("tf-test-db") pluginName := dbEngineMySQL.DefaultPluginName() @@ -542,12 +540,15 @@ func TestAccDatabaseSecretBackendConnectionTemplatedUpdateExcludePassword_mysql( backend := acctest.RandomWithPrefix("tf-test-db") pluginName := dbEngineMySQL.DefaultPluginName() name := acctest.RandomWithPrefix("db") - testUsername := acctest.RandomWithPrefix("username") - testPassword := acctest.RandomWithPrefix("password") + // setup a secondary root user which is required for the rotate-root test portion below. + secondaryRootUsername := acctest.RandomWithPrefix("username") + secondaryRootPassword := acctest.RandomWithPrefix("password") db := newMySQLConnection(t, connURL, username, password) - createMySQSUser(t, db, testUsername, testPassword) - defer deleteMySQLUser(t, db, testUsername) + createMySQSUser(t, db, secondaryRootUsername, secondaryRootPassword) + t.Cleanup(func() { + deleteMySQLUser(t, db, secondaryRootUsername) + }) resource.Test(t, resource.TestCase{ Providers: testProviders, @@ -568,7 +569,20 @@ func TestAccDatabaseSecretBackendConnectionTemplatedUpdateExcludePassword_mysql( ), }, { - Config: testAccDatabaseSecretBackendConnectionConfigTemplated_mysql(name, backend, testConnURL, testUsername, testPassword, 10), + Config: testAccDatabaseSecretBackendConnectionConfigTemplated_mysql(name, backend, testConnURL, secondaryRootUsername, secondaryRootPassword, 10), + Check: testComposeCheckFuncCommonDatabaseSecretBackend(name, backend, pluginName, + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.#", "2"), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.0", "dev"), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "allowed_roles.1", "prod"), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "verify_connection", "true"), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.connection_url", testConnURL), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.username", secondaryRootUsername), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.password", secondaryRootPassword), + resource.TestCheckResourceAttr(testDefaultDatabaseSecretBackendResource, "mysql.0.max_connection_lifetime", "10"), + ), + }, + { + Config: testAccDatabaseSecretBackendConnectionConfigTemplated_mysql(name, backend, testConnURL, secondaryRootUsername, secondaryRootPassword, 10), PreConfig: func() { path := fmt.Sprintf("%s/rotate-root/%s", backend, name) client := testProvider.Meta().(*api.Client) @@ -1051,7 +1065,7 @@ resource "vault_database_secret_backend_connection" "test" { } func testAccDatabaseSecretBackendConnectionConfigUpdate_mysql(name, path, connURL, username, password string, connLifetime int) string { - return fmt.Sprintf(` + config := fmt.Sprintf(` resource "vault_mount" "db" { path = "%s" type = "database" @@ -1071,6 +1085,8 @@ resource "vault_database_secret_backend_connection" "test" { } } `, path, name, connURL, username, password, connLifetime) + + return config } func testAccDatabaseSecretBackendConnectionConfig_mysql_tls(name, path, connURL, password, tls_ca, tls_certificate_key string) string { @@ -1104,7 +1120,7 @@ EOT } func testAccDatabaseSecretBackendConnectionConfigTemplated_mysql(name, path, connURL, username, password string, connLifetime int) string { - return fmt.Sprintf(` + config := fmt.Sprintf(` resource "vault_mount" "db" { path = "%s" type = "database" @@ -1123,6 +1139,8 @@ resource "vault_database_secret_backend_connection" "test" { } } `, path, name, connURL, connLifetime, username, password) + + return config } func testAccDatabaseSecretBackendConnectionConfig_mysql_rds(name, path, connURL, username, password string) string {