Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[VAULT-2533] Add Redshift support to Provider #1279

Merged
merged 14 commits into from
Jan 5, 2022
Merged
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 3.2.0 (Unreleased)
IMPROVEMENTS:
* `resource/database_secret_backend_connection`: Add support for configuring Redshift databases ([#1279](https://github.com/hashicorp/terraform-provider-vault/pull/1279))

## 3.1.1 (December 22, 2021)
BUGS:
* Prevent new `entity` read failures when the `VAULT_TOKEN` environment variable is not set ([#1270](https://github.com/hashicorp/terraform-provider-vault/pull/1270))
Expand Down
17 changes: 15 additions & 2 deletions vault/resource_database_secret_backend_connection.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ const (
dbBackendPostgres = "postgresql"
dbBackendOracle = "oracle"
dbBackendSnowflake = "snowflake"
dbBackendRedshift = "redshift"
)

var (
Expand All @@ -56,6 +57,7 @@ var (
dbBackendPostgres,
dbBackendOracle,
dbBackendSnowflake,
dbBackendRedshift,
}
)

Expand Down Expand Up @@ -388,6 +390,15 @@ func databaseSecretBackendConnectionResource() *schema.Resource {
ConflictsWith: util.CalculateConflictsWith(dbBackendOracle, dbBackendTypes),
},

"redshift": {
Type: schema.TypeList,
Optional: true,
Description: "Connection parameters for the redshift-database-plugin plugin.",
Elem: connectionStringResource(&connectionStringConfig{}),
MaxItems: 1,
ConflictsWith: util.CalculateConflictsWith(dbBackendRedshift, dbBackendTypes),
},

"snowflake": {
Type: schema.TypeList,
Optional: true,
Expand Down Expand Up @@ -521,6 +532,8 @@ func getDatabasePluginName(d *schema.ResourceData) (string, error) {
return "elasticsearch-database-plugin", nil
case len(d.Get(dbBackendSnowflake).([]interface{})) > 0:
return "snowflake-database-plugin", nil
case len(d.Get(dbBackendRedshift).([]interface{})) > 0:
return "redshift-database-plugin", nil
default:
return "", fmt.Errorf("at least one database plugin must be configured")
}
Expand Down Expand Up @@ -609,6 +622,8 @@ func getDatabaseAPIData(d *schema.ResourceData) (map[string]interface{}, error)
setElasticsearchDatabaseConnectionData(d, "elasticsearch.0.", data)
case "snowflake-database-plugin":
setSnowflakeDatabaseConnectionData(d, "snowflake.0.", data)
case "redshift-database-plugin":
setDatabaseConnectionData(d, "redshift.0.", data)
vinay-gopalan marked this conversation as resolved.
Show resolved Hide resolved
}

return data, nil
Expand Down Expand Up @@ -912,11 +927,9 @@ func setSnowflakeDatabaseConnectionData(d *schema.ResourceData, prefix string, d
if v, ok := d.GetOk(prefix + "username"); ok {
data["username"] = v.(string)
}

if v, ok := d.GetOk(prefix + "password"); ok {
data["password"] = v.(string)
}

if v, ok := d.GetOk(prefix + "username_template"); ok {
data["username_template"] = v.(string)
}
Expand Down
53 changes: 53 additions & 0 deletions vault/resource_database_secret_backend_connection_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -703,6 +703,41 @@ func TestAccDatabaseSecretBackendConnection_snowflake(t *testing.T) {
})
}

func TestAccDatabaseSecretBackendConnection_redshift(t *testing.T) {
MaybeSkipDBTests(t, dbBackendRedshift)

url := os.Getenv("REDSHIFT_URL")
if url == "" {
t.Skip("REDSHIFT_URL not set")
}
backend := acctest.RandomWithPrefix("tf-test-db")
name := acctest.RandomWithPrefix("db")
resource.Test(t, resource.TestCase{
Providers: testProviders,
PreCheck: func() { testAccPreCheck(t) },
vinay-gopalan marked this conversation as resolved.
Show resolved Hide resolved
CheckDestroy: testAccDatabaseSecretBackendConnectionCheckDestroy,
Steps: []resource.TestStep{
{
Config: testAccDatabaseSecretBackendConnectionConfig_redshift(name, backend, url),
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", "redshift.0.connection_url", url),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "redshift.0.max_open_connections", "2"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "redshift.0.max_idle_connections", "0"),
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "redshift.0.max_connection_lifetime", "0"),
),
},
},
})
}

func testAccDatabaseSecretBackendConnectionCheckDestroy(s *terraform.State) error {
client := testProvider.Meta().(*api.Client)

Expand Down Expand Up @@ -1094,6 +1129,24 @@ resource "vault_database_secret_backend_connection" "test" {
`, path, name, url, username, password, userTempl)
}

func testAccDatabaseSecretBackendConnectionConfig_redshift(name, path, connURL 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"]
vinay-gopalan marked this conversation as resolved.
Show resolved Hide resolved
redshift {
connection_url = "%s"
}
}
`, path, name, connURL)
}

func newMySQLConnection(t *testing.T, connURL string, username string, password string) *sql.DB {
dbURL := dbutil.QueryHelper(connURL, map[string]string{
"username": username,
Expand Down
21 changes: 21 additions & 0 deletions website/docs/r/database_secret_backend_connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -295,6 +295,27 @@ See the [Vault

* `username_template` - (Optional) - [Template](https://www.vaultproject.io/docs/concepts/username-templating) describing how dynamic usernames are generated.

### Redshift Configuration Options

* `connection_url` - (Required) Specifies the Redshift DSN. See
the [Vault
docs](https://www.vaultproject.io/api-docs/secret/databases/redshift#sample-payload)
for an example.

* `max_open_connections` - (Optional) The maximum number of open connections to
the database.

* `max_idle_connections` - (Optional) The maximum number of idle connections to
the database.

* `max_connection_lifetime` - (Optional) The maximum amount of time a connection may be reused.

* `username` - (Optional) The root credential username used in the connection URL.

* `password` - (Optional) The root credential password used in the connection URL.
benashz marked this conversation as resolved.
Show resolved Hide resolved

* `username_template` - (Optional) - [Template](https://www.vaultproject.io/docs/concepts/username-templating) describing how dynamic usernames are generated.

## Attributes Reference

No additional attributes are exported by this resource.
Expand Down