mirror of
https://github.com/opentofu/terraform-provider-vault.git
synced 2026-01-11 19:46:35 +00:00
Elasticsearch support in vault_database_secret_backend_connection (#704)
* Add basic elasticsearch variables and handling * Added elasticsearch to documentation * Added basic acceptance test, and elastic node to docker-compose * Mark elasticsearch url, username and password properties as required
This commit is contained in:
parent
3f89dde8c8
commit
b0cdcbe5a1
5 changed files with 154 additions and 1 deletions
|
|
@ -1,3 +1,6 @@
|
|||
export VAULT_ADDR="http://localhost:8200"
|
||||
export VAULT_TOKEN="TEST"
|
||||
export MYSQL_URL="vault:vault@tcp(mysql:3306)/"
|
||||
export ELASTIC_URL="http://elastic:9200"
|
||||
export ELASTIC_USERNAME="elastic"
|
||||
export ELASTIC_PASSWORD="elastic"
|
||||
|
|
|
|||
|
|
@ -21,3 +21,12 @@ services:
|
|||
MYSQL_DATABASE: "main"
|
||||
MYSQL_USER: "vault"
|
||||
MYSQL_PASSWORD: "vault"
|
||||
|
||||
elastic:
|
||||
image: elasticsearch:7.6.0
|
||||
ports:
|
||||
- "9200:9200"
|
||||
environment:
|
||||
"discovery.type": "single-node"
|
||||
"xpack.security.enabled": "true"
|
||||
"ELASTIC_PASSWORD": "elastic"
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@ import (
|
|||
var (
|
||||
databaseSecretBackendConnectionBackendFromPathRegex = regexp.MustCompile("^(.+)/config/.+$")
|
||||
databaseSecretBackendConnectionNameFromPathRegex = regexp.MustCompile("^.+/config/(.+$)")
|
||||
dbBackendTypes = []string{"cassandra", "hana", "mongodb", "mssql", "mysql", "mysql_rds", "mysql_aurora", "mysql_legacy", "postgresql", "oracle"}
|
||||
dbBackendTypes = []string{"cassandra", "hana", "mongodb", "mssql", "mysql", "mysql_rds", "mysql_aurora", "mysql_legacy", "postgresql", "oracle", "elasticsearch"}
|
||||
)
|
||||
|
||||
func databaseSecretBackendConnectionResource() *schema.Resource {
|
||||
|
|
@ -66,6 +66,34 @@ func databaseSecretBackendConnectionResource() *schema.Resource {
|
|||
Sensitive: true,
|
||||
},
|
||||
|
||||
"elasticsearch": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Description: "Connection parameters for the elasticsearch-database-plugin.",
|
||||
Elem: &schema.Resource{
|
||||
Schema: map[string]*schema.Schema{
|
||||
"url": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "The URL for Elasticsearch's API",
|
||||
},
|
||||
"username": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "The username to be used in the connection URL",
|
||||
},
|
||||
"password": {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
Description: "The password to be used in the connection URL",
|
||||
Sensitive: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
MaxItems: 1,
|
||||
ConflictsWith: util.CalculateConflictsWith("elasticsearch", dbBackendTypes),
|
||||
},
|
||||
|
||||
"cassandra": {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
|
|
@ -281,6 +309,8 @@ func getDatabasePluginName(d *schema.ResourceData) (string, error) {
|
|||
return "oracle-database-plugin", nil
|
||||
case len(d.Get("postgresql").([]interface{})) > 0:
|
||||
return "postgresql-database-plugin", nil
|
||||
case len(d.Get("elasticsearch").([]interface{})) > 0:
|
||||
return "elasticsearch-database-plugin", nil
|
||||
default:
|
||||
return "", fmt.Errorf("at least one database plugin must be configured")
|
||||
}
|
||||
|
|
@ -353,6 +383,8 @@ func getDatabaseAPIData(d *schema.ResourceData) (map[string]interface{}, error)
|
|||
setDatabaseConnectionData(d, "oracle.0.", data)
|
||||
case "postgresql-database-plugin":
|
||||
setDatabaseConnectionData(d, "postgresql.0.", data)
|
||||
case "elasticsearch-database-plugin":
|
||||
setElasticsearchDatabaseConnectionData(d, "elasticsearch.0.", data)
|
||||
}
|
||||
|
||||
return data, nil
|
||||
|
|
@ -399,6 +431,34 @@ func getConnectionDetailsFromResponse(d *schema.ResourceData, prefix string, res
|
|||
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{})
|
||||
if !ok {
|
||||
return nil
|
||||
}
|
||||
result := map[string]interface{}{}
|
||||
if v, ok := d.GetOk(prefix + "url"); ok {
|
||||
result["url"] = v.(string)
|
||||
} else {
|
||||
if v, ok := data["url"]; ok {
|
||||
result["url"] = v.(string)
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := data["username"]; ok {
|
||||
result["username"] = v.(string)
|
||||
}
|
||||
if v, ok := data["password"]; ok {
|
||||
result["password"] = v.(string)
|
||||
} else if v, ok := d.GetOk(prefix + "password"); ok {
|
||||
// keep the password we have in state/config if the API doesn't return one
|
||||
result["password"] = v.(string)
|
||||
}
|
||||
|
||||
return []map[string]interface{}{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)
|
||||
|
|
@ -414,6 +474,20 @@ func setDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[s
|
|||
}
|
||||
}
|
||||
|
||||
func setElasticsearchDatabaseConnectionData(d *schema.ResourceData, prefix string, data map[string]interface{}) {
|
||||
if v, ok := d.GetOk(prefix + "url"); ok {
|
||||
data["url"] = v.(string)
|
||||
}
|
||||
|
||||
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 databaseSecretBackendConnectionCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*api.Client)
|
||||
|
||||
|
|
@ -564,6 +638,8 @@ func databaseSecretBackendConnectionRead(d *schema.ResourceData, meta interface{
|
|||
d.Set("oracle", getConnectionDetailsFromResponse(d, "oracle.0.", resp))
|
||||
case "postgresql-database-plugin":
|
||||
d.Set("postgresql", getConnectionDetailsFromResponse(d, "postgresql.0.", resp))
|
||||
case "elasticsearch-database-plugin":
|
||||
d.Set("elasticsearch", getElasticsearchConnectionDetailsFromResponse(d, "elasticsearch.0.", resp))
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
|
|
|
|||
|
|
@ -372,6 +372,38 @@ func TestAccDatabaseSecretBackendConnection_postgresql(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccDatabaseSecretBackendConnection_elasticsearch(t *testing.T) {
|
||||
connURL := os.Getenv("ELASTIC_URL")
|
||||
if connURL == "" {
|
||||
t.Skip("ELASTIC_URL not set")
|
||||
}
|
||||
|
||||
username := os.Getenv("ELASTIC_USERNAME")
|
||||
password := os.Getenv("ELASTIC_PASSWORD")
|
||||
backend := acctest.RandomWithPrefix("tf-test-db")
|
||||
name := acctest.RandomWithPrefix("db")
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
Providers: testProviders,
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
CheckDestroy: testAccDatabaseSecretBackendConnectionCheckDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccDatabaseSecretBackendConnectionConfig_elasticsearch(name, backend, connURL, username, password),
|
||||
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", "verify_connection", "true"),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_connection.test", "elasticsearch.0.url", connURL),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccDatabaseSecretBackendConnectionCheckDestroy(s *terraform.State) error {
|
||||
client := testProvider.Meta().(*api.Client)
|
||||
|
||||
|
|
@ -437,6 +469,28 @@ resource "vault_database_secret_backend_connection" "test" {
|
|||
`, path, name, host, username, password)
|
||||
}
|
||||
|
||||
func testAccDatabaseSecretBackendConnectionConfig_elasticsearch(name, path, host, username, password 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"]
|
||||
|
||||
elasticsearch {
|
||||
url = "%s"
|
||||
username = "%s"
|
||||
password = "%s"
|
||||
}
|
||||
}
|
||||
`, path, name, host, username, password)
|
||||
}
|
||||
|
||||
func testAccDatabaseSecretBackendConnectionConfig_mongodb(name, path, connURL string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "vault_mount" "db" {
|
||||
|
|
|
|||
|
|
@ -75,6 +75,8 @@ The following arguments are supported:
|
|||
|
||||
* `oracle` - (Optional) A nested block containing configuration options for Oracle connections.
|
||||
|
||||
* `elasticsearch` - (Optional) A nested block containing configuration options for Elasticsearch connections.
|
||||
|
||||
Exactly one of the nested blocks of configuration options must be supplied.
|
||||
|
||||
### Cassandra Configuration Options
|
||||
|
|
@ -190,6 +192,15 @@ 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.
|
||||
|
||||
### Elasticsearch Configuration Options
|
||||
|
||||
* `url` - (Required) The URL for Elasticsearch's API. https requires certificate
|
||||
by trusted CA if used.
|
||||
|
||||
* `username` - (Required) The username to be used in the connection.
|
||||
|
||||
* `password` - (Required) The password to be used in the connection.
|
||||
|
||||
## Attributes Reference
|
||||
|
||||
No additional attributes are exported by this resource.
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue