Skip to content

Commit 47f32c4

Browse files
cassidy1tvoran
authored andcommitted
add tls_certificate_key and tls_ca to mysql (hashicorp#1098)
* add mysql_tls test Co-authored-by: Theron Voran <tvoran@users.noreply.github.com>
1 parent 540adf6 commit 47f32c4

3 files changed

Lines changed: 134 additions & 3 deletions

File tree

vault/resource_database_secret_backend_connection.go

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ func databaseSecretBackendConnectionResource() *schema.Resource {
226226
Type: schema.TypeList,
227227
Optional: true,
228228
Description: "Connection parameters for the mysql-database-plugin plugin.",
229-
Elem: connectionStringResource(),
229+
Elem: mysqlConnectionStringResource(),
230230
MaxItems: 1,
231231
ConflictsWith: util.CalculateConflictsWith("mysql", dbBackendTypes),
232232
},
@@ -315,6 +315,22 @@ func connectionStringResource() *schema.Resource {
315315
}
316316
}
317317

318+
func mysqlConnectionStringResource() *schema.Resource {
319+
r := connectionStringResource()
320+
r.Schema["tls_certificate_key"] = &schema.Schema{
321+
Type: schema.TypeString,
322+
Optional: true,
323+
Description: "x509 certificate for connecting to the database. This must be a PEM encoded version of the private key and the certificate combined.",
324+
Sensitive: true,
325+
}
326+
r.Schema["tls_ca"] = &schema.Schema{
327+
Type: schema.TypeString,
328+
Optional: true,
329+
Description: "x509 CA file for validating the certificate presented by the MySQL server. Must be PEM encoded.",
330+
}
331+
return r
332+
}
333+
318334
func getDatabasePluginName(d *schema.ResourceData) (string, error) {
319335
switch {
320336
case len(d.Get("cassandra").([]interface{})) > 0:
@@ -412,7 +428,7 @@ func getDatabaseAPIData(d *schema.ResourceData) (map[string]interface{}, error)
412428
case "mssql-database-plugin":
413429
setDatabaseConnectionData(d, "mssql.0.", data)
414430
case "mysql-database-plugin":
415-
setDatabaseConnectionData(d, "mysql.0.", data)
431+
setMySQLDatabaseConnectionData(d, "mysql.0.", data)
416432
case "mysql-rds-database-plugin":
417433
setDatabaseConnectionData(d, "mysql_rds.0.", data)
418434
case "mysql-aurora-database-plugin":
@@ -471,6 +487,31 @@ func getConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, res
471487
return []map[string]interface{}{result}
472488
}
473489

490+
func getMySQLConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, resp *api.Secret) []map[string]interface{} {
491+
commonDetails := getConnectionDetailsFromResponse(d, prefix, resp)
492+
details := resp.Data["connection_details"]
493+
data, ok := details.(map[string]interface{})
494+
if !ok {
495+
return nil
496+
}
497+
result := commonDetails[0]
498+
if v, ok := d.GetOk(prefix + "tls_certificate_key"); ok {
499+
result["tls_certificate_key"] = v.(string)
500+
} else {
501+
if v, ok := data["tls_certificate_key"]; ok {
502+
result["tls_certificate_key"] = v.(string)
503+
}
504+
}
505+
if v, ok := d.GetOk(prefix + "tls_ca"); ok {
506+
result["tls_ca"] = v.(string)
507+
} else {
508+
if v, ok := data["tls_ca"]; ok {
509+
result["tls_ca"] = v.(string)
510+
}
511+
}
512+
return []map[string]interface{}{result}
513+
}
514+
474515
func getElasticsearchConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, resp *api.Secret) []map[string]interface{} {
475516
details := resp.Data["connection_details"]
476517
data, ok := details.(map[string]interface{})
@@ -514,6 +555,16 @@ func setDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[s
514555
}
515556
}
516557

558+
func setMySQLDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[string]interface{}) {
559+
setDatabaseConnectionData(d, prefix, data)
560+
if v, ok := d.GetOk(prefix + "tls_certificate_key"); ok {
561+
data["tls_certificate_key"] = v.(string)
562+
}
563+
if v, ok := d.GetOk(prefix + "tls_ca"); ok {
564+
data["tls_ca"] = v.(string)
565+
}
566+
}
567+
517568
func setElasticsearchDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[string]interface{}) {
518569
if v, ok := d.GetOk(prefix + "url"); ok {
519570
data["url"] = v.(string)
@@ -684,7 +735,7 @@ func databaseSecretBackendConnectionRead(d *schema.ResourceData, meta interface{
684735
case "mssql-database-plugin":
685736
d.Set("mssql", getConnectionDetailsFromResponse(d, "mssql.0.", resp))
686737
case "mysql-database-plugin":
687-
d.Set("mysql", getConnectionDetailsFromResponse(d, "mysql.0.", resp))
738+
d.Set("mysql", getMySQLConnectionDetailsFromResponse(d, "mysql.0.", resp))
688739
case "mysql-rds-database-plugin":
689740
d.Set("mysql_rds", getConnectionDetailsFromResponse(d, "mysql_rds.0.", resp))
690741
case "mysql-aurora-database-plugin":

vault/resource_database_secret_backend_connection_test.go

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,6 +460,52 @@ func TestAccDatabaseSecretBackendConnectionTemplatedUpdateExcludePassword_mysql(
460460
})
461461
}
462462

463+
func TestAccDatabaseSecretBackendConnection_mysql_tls(t *testing.T) {
464+
tls_ca := os.Getenv("MYSQL_CA")
465+
if tls_ca == "" {
466+
t.Skip("MYSQL_CA not set")
467+
}
468+
connURL := os.Getenv("MYSQL_URL")
469+
if connURL == "" {
470+
t.Skip("MYSQL_URL not set")
471+
}
472+
tls_certificate_key := os.Getenv("MYSQL_CERTIFICATE_KEY")
473+
if tls_certificate_key == "" {
474+
t.Skip("MYSQL_CERTIFICATE_KEY not set")
475+
}
476+
backend := acctest.RandomWithPrefix("tf-test-db")
477+
name := acctest.RandomWithPrefix("db")
478+
password := acctest.RandomWithPrefix("password")
479+
resource.Test(t, resource.TestCase{
480+
Providers: testProviders,
481+
PreCheck: func() { testAccPreCheck(t) },
482+
CheckDestroy: testAccDatabaseSecretBackendConnectionCheckDestroy,
483+
Steps: []resource.TestStep{
484+
{
485+
Config: testAccDatabaseSecretBackendConnectionConfig_mysql_tls(name, backend, connURL, password, tls_ca, tls_certificate_key),
486+
Check: resource.ComposeTestCheckFunc(
487+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "name", name),
488+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "backend", backend),
489+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "allowed_roles.#", "2"),
490+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "allowed_roles.0", "dev"),
491+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "allowed_roles.1", "prod"),
492+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "root_rotation_statements.#", "1"),
493+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "root_rotation_statements.0", "FOOBAR"),
494+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "verify_connection", "true"),
495+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "mysql.0.connection_url", connURL),
496+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "mysql.0.max_open_connections", "2"),
497+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "mysql.0.max_idle_connections", "0"),
498+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "mysql.0.max_connection_lifetime", "0"),
499+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "data.%", "1"),
500+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "data.password", password),
501+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "mysql.0.tls_ca", tls_ca+"\n"),
502+
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "mysql.0.tls_certificate_key", tls_certificate_key+"\n"),
503+
),
504+
},
505+
},
506+
})
507+
}
508+
463509
func TestAccDatabaseSecretBackendConnection_postgresql(t *testing.T) {
464510
connURL := os.Getenv("POSTGRES_URL")
465511
if connURL == "" {
@@ -723,6 +769,36 @@ resource "vault_database_secret_backend_connection" "test" {
723769
`, path, name, connURL, connLifetime, password)
724770
}
725771

772+
func testAccDatabaseSecretBackendConnectionConfig_mysql_tls(name, path, connURL, password, tls_ca, tls_certificate_key string) string {
773+
return fmt.Sprintf(`
774+
resource "vault_mount" "db" {
775+
path = "%s"
776+
type = "database"
777+
}
778+
779+
resource "vault_database_secret_backend_connection" "test" {
780+
backend = "${vault_mount.db.path}"
781+
name = "%s"
782+
allowed_roles = ["dev", "prod"]
783+
root_rotation_statements = ["FOOBAR"]
784+
785+
mysql {
786+
connection_url = "%s"
787+
tls_ca = <<EOT
788+
%s
789+
EOT
790+
tls_certificate_key = <<EOT
791+
%s
792+
EOT
793+
}
794+
795+
data = {
796+
password = "%s"
797+
}
798+
}
799+
`, path, name, connURL, tls_ca, tls_certificate_key, password)
800+
}
801+
726802
func testAccDatabaseSecretBackendConnectionConfigTemplated_mysql(name, path, connURL, username, password string, connLifetime int) string {
727803
return fmt.Sprintf(`
728804
resource "vault_mount" "db" {

website/docs/r/database_secret_backend_connection.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -172,6 +172,10 @@ Exactly one of the nested blocks of configuration options must be supplied.
172172
* `max_connection_lifetime` - (Optional) The maximum number of seconds to keep
173173
a connection alive for.
174174

175+
* `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.
176+
177+
* `tls_ca` - (Optional) x509 CA file for validating the certificate presented by the MySQL server. Must be PEM encoded.
178+
175179
### PostgreSQL Configuration Options
176180

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

0 commit comments

Comments
 (0)