Skip to content

Commit

Permalink
add tls_certificate_key and tls_ca to mysql (hashicorp#1098)
Browse files Browse the repository at this point in the history
* add mysql_tls test

Co-authored-by: Theron Voran <[email protected]>
  • Loading branch information
2 people authored and davidmontoyago committed Aug 17, 2021
1 parent 540adf6 commit 47f32c4
Show file tree
Hide file tree
Showing 3 changed files with 134 additions and 3 deletions.
57 changes: 54 additions & 3 deletions vault/resource_database_secret_backend_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ func databaseSecretBackendConnectionResource() *schema.Resource {
Type: schema.TypeList,
Optional: true,
Description: "Connection parameters for the mysql-database-plugin plugin.",
Elem: connectionStringResource(),
Elem: mysqlConnectionStringResource(),
MaxItems: 1,
ConflictsWith: util.CalculateConflictsWith("mysql", dbBackendTypes),
},
Expand Down Expand Up @@ -315,6 +315,22 @@ func connectionStringResource() *schema.Resource {
}
}

func mysqlConnectionStringResource() *schema.Resource {
r := connectionStringResource()
r.Schema["tls_certificate_key"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "x509 certificate for connecting to the database. This must be a PEM encoded version of the private key and the certificate combined.",
Sensitive: true,
}
r.Schema["tls_ca"] = &schema.Schema{
Type: schema.TypeString,
Optional: true,
Description: "x509 CA file for validating the certificate presented by the MySQL server. Must be PEM encoded.",
}
return r
}

func getDatabasePluginName(d *schema.ResourceData) (string, error) {
switch {
case len(d.Get("cassandra").([]interface{})) > 0:
Expand Down Expand Up @@ -412,7 +428,7 @@ func getDatabaseAPIData(d *schema.ResourceData) (map[string]interface{}, error)
case "mssql-database-plugin":
setDatabaseConnectionData(d, "mssql.0.", data)
case "mysql-database-plugin":
setDatabaseConnectionData(d, "mysql.0.", data)
setMySQLDatabaseConnectionData(d, "mysql.0.", data)
case "mysql-rds-database-plugin":
setDatabaseConnectionData(d, "mysql_rds.0.", data)
case "mysql-aurora-database-plugin":
Expand Down Expand Up @@ -471,6 +487,31 @@ func getConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, res
return []map[string]interface{}{result}
}

func getMySQLConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, resp *api.Secret) []map[string]interface{} {
commonDetails := getConnectionDetailsFromResponse(d, prefix, resp)
details := resp.Data["connection_details"]
data, ok := details.(map[string]interface{})
if !ok {
return nil
}
result := commonDetails[0]
if v, ok := d.GetOk(prefix + "tls_certificate_key"); ok {
result["tls_certificate_key"] = v.(string)
} else {
if v, ok := data["tls_certificate_key"]; ok {
result["tls_certificate_key"] = v.(string)
}
}
if v, ok := d.GetOk(prefix + "tls_ca"); ok {
result["tls_ca"] = v.(string)
} else {
if v, ok := data["tls_ca"]; ok {
result["tls_ca"] = v.(string)
}
}
return []map[string]interface{}{result}
}

func getElasticsearchConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, resp *api.Secret) []map[string]interface{} {
details := resp.Data["connection_details"]
data, ok := details.(map[string]interface{})
Expand Down Expand Up @@ -514,6 +555,16 @@ func setDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[s
}
}

func setMySQLDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[string]interface{}) {
setDatabaseConnectionData(d, prefix, data)
if v, ok := d.GetOk(prefix + "tls_certificate_key"); ok {
data["tls_certificate_key"] = v.(string)
}
if v, ok := d.GetOk(prefix + "tls_ca"); ok {
data["tls_ca"] = v.(string)
}
}

func setElasticsearchDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[string]interface{}) {
if v, ok := d.GetOk(prefix + "url"); ok {
data["url"] = v.(string)
Expand Down Expand Up @@ -684,7 +735,7 @@ func databaseSecretBackendConnectionRead(d *schema.ResourceData, meta interface{
case "mssql-database-plugin":
d.Set("mssql", getConnectionDetailsFromResponse(d, "mssql.0.", resp))
case "mysql-database-plugin":
d.Set("mysql", getConnectionDetailsFromResponse(d, "mysql.0.", resp))
d.Set("mysql", getMySQLConnectionDetailsFromResponse(d, "mysql.0.", resp))
case "mysql-rds-database-plugin":
d.Set("mysql_rds", getConnectionDetailsFromResponse(d, "mysql_rds.0.", resp))
case "mysql-aurora-database-plugin":
Expand Down
76 changes: 76 additions & 0 deletions vault/resource_database_secret_backend_connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,52 @@ func TestAccDatabaseSecretBackendConnectionTemplatedUpdateExcludePassword_mysql(
})
}

func TestAccDatabaseSecretBackendConnection_mysql_tls(t *testing.T) {
tls_ca := os.Getenv("MYSQL_CA")
if tls_ca == "" {
t.Skip("MYSQL_CA not set")
}
connURL := os.Getenv("MYSQL_URL")
if connURL == "" {
t.Skip("MYSQL_URL not set")
}
tls_certificate_key := os.Getenv("MYSQL_CERTIFICATE_KEY")
if tls_certificate_key == "" {
t.Skip("MYSQL_CERTIFICATE_KEY not set")
}
backend := acctest.RandomWithPrefix("tf-test-db")
name := acctest.RandomWithPrefix("db")
password := acctest.RandomWithPrefix("password")
resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t) },
CheckDestroy: testAccDatabaseSecretBackendConnectionCheckDestroy,
Steps: []resource.TestStep{
{
Config: testAccDatabaseSecretBackendConnectionConfig_mysql_tls(name, backend, connURL, password, tls_ca, tls_certificate_key),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "name", name),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "backend", backend),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "allowed_roles.#", "2"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "allowed_roles.0", "dev"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "allowed_roles.1", "prod"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "root_rotation_statements.#", "1"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "root_rotation_statements.0", "FOOBAR"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "verify_connection", "true"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "mysql.0.connection_url", connURL),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "mysql.0.max_open_connections", "2"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "mysql.0.max_idle_connections", "0"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "mysql.0.max_connection_lifetime", "0"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "data.%", "1"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "data.password", password),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "mysql.0.tls_ca", tls_ca+"\n"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "mysql.0.tls_certificate_key", tls_certificate_key+"\n"),
),
},
},
})
}

func TestAccDatabaseSecretBackendConnection_postgresql(t *testing.T) {
connURL := os.Getenv("POSTGRES_URL")
if connURL == "" {
Expand Down Expand Up @@ -723,6 +769,36 @@ resource "vault_database_secret_backend_connection" "test" {
`, path, name, connURL, connLifetime, password)
}

func testAccDatabaseSecretBackendConnectionConfig_mysql_tls(name, path, connURL, password, tls_ca, tls_certificate_key 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"]
mysql {
connection_url = "%s"
tls_ca = <<EOT
%s
EOT
tls_certificate_key = <<EOT
%s
EOT
}
data = {
password = "%s"
}
}
`, path, name, connURL, tls_ca, tls_certificate_key, password)
}

func testAccDatabaseSecretBackendConnectionConfigTemplated_mysql(name, path, connURL, username, password string, connLifetime int) string {
return fmt.Sprintf(`
resource "vault_mount" "db" {
Expand Down
4 changes: 4 additions & 0 deletions website/docs/r/database_secret_backend_connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -172,6 +172,10 @@ Exactly one of the nested blocks of configuration options must be supplied.
* `max_connection_lifetime` - (Optional) The maximum number of seconds to keep
a connection alive for.

* `tls_certificate_key` - (Optional) x509 certificate for connecting to the database. This must be a PEM encoded version of the private key and the certificate combined.

* `tls_ca` - (Optional) x509 CA file for validating the certificate presented by the MySQL server. Must be PEM encoded.

### PostgreSQL Configuration Options

* `connection_url` - (Required) A URL containing connection information. See
Expand Down

0 comments on commit 47f32c4

Please sign in to comment.