mirror of
https://github.com/opentofu/terraform-provider-vault.git
synced 2026-01-11 19:46:35 +00:00
Add support for DB Adv TTL Mgmt (#2011)
* add support for schedule-based roles
This commit is contained in:
parent
8adb474d0b
commit
2653605832
5 changed files with 263 additions and 110 deletions
|
|
@ -16,16 +16,19 @@ services:
|
|||
VAULT_TOKEN: "TEST"
|
||||
MYSQL_URL: "vault:vault@tcp(mysql:3306)/"
|
||||
|
||||
# to run this container on Mac M1 you need to
|
||||
# export DOCKER_DEFAULT_PLATFORM=linux/amd64
|
||||
# to run acceptance tests locally you need to
|
||||
# export MYSQL_URL=root:mysql@tcp(localhost:3306)/
|
||||
# to run the docker container
|
||||
# docker compose up -d mysql
|
||||
mysql:
|
||||
image: mysql:5.7
|
||||
image: docker.mirror.hashicorp.services/mysql:latest
|
||||
command: --default-authentication-plugin=mysql_native_password
|
||||
ports:
|
||||
- "3306:3306"
|
||||
environment:
|
||||
MYSQL_ROOT_PASSWORD: "root"
|
||||
MYSQL_DATABASE: "main"
|
||||
MYSQL_USER: "vault"
|
||||
MYSQL_PASSWORD: "vault"
|
||||
MYSQL_ROOT_PASSWORD: "mysql"
|
||||
|
||||
elastic:
|
||||
image: elasticsearch:7.17.10
|
||||
|
|
@ -95,4 +98,4 @@ services:
|
|||
ports:
|
||||
- "9042:9042"
|
||||
volumes:
|
||||
- ./testdata/cassandra.yaml:/etc/cassandra/cassandra.yaml
|
||||
- ./testdata/cassandra.yaml:/etc/cassandra/cassandra.yaml
|
||||
|
|
|
|||
|
|
@ -352,6 +352,9 @@ const (
|
|||
FieldCredentialType = "credential_type"
|
||||
FieldFilename = "filename"
|
||||
FieldDefault = "default"
|
||||
FieldRotationStatements = "rotation_statements"
|
||||
FieldRotationSchedule = "rotation_schedule"
|
||||
FieldRotationWindow = "rotation_window"
|
||||
FieldKubernetesCACert = "kubernetes_ca_cert"
|
||||
FieldDisableLocalCAJWT = "disable_local_ca_jwt"
|
||||
FieldKubernetesHost = "kubernetes_host"
|
||||
|
|
|
|||
|
|
@ -4,8 +4,10 @@
|
|||
package vault
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"context"
|
||||
"fmt"
|
||||
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
|
||||
"github.com/hashicorp/terraform-provider-vault/internal/consts"
|
||||
"log"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
|
@ -20,39 +22,44 @@ var (
|
|||
databaseSecretBackendStaticRoleNameFromPathRegex = regexp.MustCompile("^.+/static-roles/(.+$)")
|
||||
)
|
||||
|
||||
var staticRoleFields = []string{
|
||||
consts.FieldRotationPeriod,
|
||||
consts.FieldRotationStatements,
|
||||
consts.FieldDBName,
|
||||
}
|
||||
|
||||
func databaseSecretBackendStaticRoleResource() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: databaseSecretBackendStaticRoleWrite,
|
||||
Read: provider.ReadWrapper(databaseSecretBackendStaticRoleRead),
|
||||
Update: databaseSecretBackendStaticRoleWrite,
|
||||
Delete: databaseSecretBackendStaticRoleDelete,
|
||||
Exists: databaseSecretBackendStaticRoleExists,
|
||||
CreateContext: databaseSecretBackendStaticRoleWrite,
|
||||
ReadContext: provider.ReadContextWrapper(databaseSecretBackendStaticRoleRead),
|
||||
UpdateContext: databaseSecretBackendStaticRoleWrite,
|
||||
DeleteContext: databaseSecretBackendStaticRoleDelete,
|
||||
Importer: &schema.ResourceImporter{
|
||||
State: schema.ImportStatePassthrough,
|
||||
StateContext: schema.ImportStatePassthroughContext,
|
||||
},
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": {
|
||||
consts.FieldName: {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: "Unique name for the static role.",
|
||||
},
|
||||
"backend": {
|
||||
consts.FieldBackend: {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: "The path of the Database Secret Backend the role belongs to.",
|
||||
},
|
||||
"username": {
|
||||
consts.FieldUsername: {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: "The database username that this role corresponds to.",
|
||||
},
|
||||
"rotation_period": {
|
||||
consts.FieldRotationPeriod: {
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
Optional: true,
|
||||
Description: "The amount of time Vault should wait before rotating the password, in seconds.",
|
||||
ValidateFunc: func(v interface{}, k string) (ws []string, errs []error) {
|
||||
value := v.(int)
|
||||
|
|
@ -62,13 +69,24 @@ func databaseSecretBackendStaticRoleResource() *schema.Resource {
|
|||
return
|
||||
},
|
||||
},
|
||||
"db_name": {
|
||||
consts.FieldRotationSchedule: {
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
Description: "A cron-style string that will define the schedule on which rotations should occur.",
|
||||
},
|
||||
consts.FieldRotationWindow: {
|
||||
Type: schema.TypeInt,
|
||||
Optional: true,
|
||||
Description: "The amount of time in seconds in which the rotations are allowed to occur starting " +
|
||||
"from a given rotation_schedule.",
|
||||
},
|
||||
consts.FieldDBName: {
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Description: "Database connection to use for this role.",
|
||||
},
|
||||
"rotation_statements": {
|
||||
consts.FieldRotationStatements: {
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
Elem: &schema.Schema{Type: schema.TypeString},
|
||||
|
|
@ -78,43 +96,56 @@ func databaseSecretBackendStaticRoleResource() *schema.Resource {
|
|||
}
|
||||
}
|
||||
|
||||
func databaseSecretBackendStaticRoleWrite(d *schema.ResourceData, meta interface{}) error {
|
||||
func databaseSecretBackendStaticRoleWrite(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
client, e := provider.GetClient(d, meta)
|
||||
if e != nil {
|
||||
return e
|
||||
return diag.FromErr(e)
|
||||
}
|
||||
|
||||
backend := d.Get("backend").(string)
|
||||
name := d.Get("name").(string)
|
||||
backend := d.Get(consts.FieldBackend).(string)
|
||||
name := d.Get(consts.FieldName).(string)
|
||||
|
||||
path := databaseSecretBackendStaticRolePath(backend, name)
|
||||
|
||||
data := map[string]interface{}{
|
||||
"username": d.Get("username"),
|
||||
"rotation_period": d.Get("rotation_period"),
|
||||
"db_name": d.Get("db_name"),
|
||||
"username": d.Get(consts.FieldUsername),
|
||||
"db_name": d.Get(consts.FieldDBName),
|
||||
"rotation_statements": []string{},
|
||||
}
|
||||
|
||||
if v, ok := d.GetOkExists("rotation_statements"); ok && v != "" {
|
||||
data["rotation_statements"] = v
|
||||
useAPIVer115 := provider.IsAPISupported(meta, provider.VaultVersion115)
|
||||
if useAPIVer115 {
|
||||
if v, ok := d.GetOk(consts.FieldRotationSchedule); ok && v != "" {
|
||||
data[consts.FieldRotationSchedule] = v
|
||||
}
|
||||
if v, ok := d.GetOk(consts.FieldRotationWindow); ok && v != "" {
|
||||
data[consts.FieldRotationWindow] = v
|
||||
}
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk(consts.FieldRotationStatements); ok && v != "" {
|
||||
data[consts.FieldRotationStatements] = v
|
||||
}
|
||||
|
||||
if v, ok := d.GetOk(consts.FieldRotationPeriod); ok && v != "" {
|
||||
data[consts.FieldRotationPeriod] = v
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Creating static role %q on database backend %q", name, backend)
|
||||
_, err := client.Logical().Write(path, data)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error creating static role %q for backend %q: %s", name, backend, err)
|
||||
return diag.Errorf("error creating static role %q for backend %q: %s", name, backend, err)
|
||||
}
|
||||
log.Printf("[DEBUG] Created static role %q on AWS backend %q", name, backend)
|
||||
|
||||
d.SetId(path)
|
||||
return databaseSecretBackendStaticRoleRead(d, meta)
|
||||
return databaseSecretBackendStaticRoleRead(ctx, d, meta)
|
||||
}
|
||||
|
||||
func databaseSecretBackendStaticRoleRead(d *schema.ResourceData, meta interface{}) error {
|
||||
func databaseSecretBackendStaticRoleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
client, e := provider.GetClient(d, meta)
|
||||
if e != nil {
|
||||
return e
|
||||
return diag.FromErr(e)
|
||||
}
|
||||
|
||||
path := d.Id()
|
||||
|
|
@ -123,20 +154,20 @@ func databaseSecretBackendStaticRoleRead(d *schema.ResourceData, meta interface{
|
|||
if err != nil {
|
||||
log.Printf("[WARN] Removing database static role %q because its ID is invalid", path)
|
||||
d.SetId("")
|
||||
return fmt.Errorf("invalid static role ID %q: %s", path, err)
|
||||
return diag.Errorf("invalid static role ID %q: %s", path, err)
|
||||
}
|
||||
|
||||
backend, err := databaseSecretBackendStaticRoleBackendFromPath(path)
|
||||
if err != nil {
|
||||
log.Printf("[WARN] Removing database static role %q because its ID is invalid", path)
|
||||
d.SetId("")
|
||||
return fmt.Errorf("invalid static role ID %q: %s", path, err)
|
||||
return diag.Errorf("invalid static role ID %q: %s", path, err)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] Reading static role from %q", path)
|
||||
role, err := client.Logical().Read(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error reading static role %q: %s", path, err)
|
||||
return diag.Errorf("error reading static role %q: %s", path, err)
|
||||
}
|
||||
log.Printf("[DEBUG] Read static role from %q", path)
|
||||
if role == nil {
|
||||
|
|
@ -145,67 +176,55 @@ func databaseSecretBackendStaticRoleRead(d *schema.ResourceData, meta interface{
|
|||
return nil
|
||||
}
|
||||
|
||||
d.Set("backend", backend)
|
||||
d.Set("name", name)
|
||||
d.Set("username", role.Data["username"])
|
||||
d.Set("db_name", role.Data["db_name"])
|
||||
|
||||
if v, ok := role.Data["rotation_period"]; ok {
|
||||
n, err := v.(json.Number).Int64()
|
||||
if err != nil {
|
||||
return fmt.Errorf("unexpected value %q for rotation_period of %q", v, path)
|
||||
}
|
||||
d.Set("rotation_period", n)
|
||||
if err := d.Set(consts.FieldBackend, backend); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
var rotation []string
|
||||
if rotationStr, ok := role.Data["rotation_statements"].(string); ok {
|
||||
rotation = append(rotation, rotationStr)
|
||||
} else if rotations, ok := role.Data["rotation_statements"].([]interface{}); ok {
|
||||
for _, cr := range rotations {
|
||||
rotation = append(rotation, cr.(string))
|
||||
if err := d.Set(consts.FieldName, name); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
if err := d.Set(consts.FieldUsername, role.Data[consts.FieldUsername]); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
|
||||
useAPIVer115 := provider.IsAPISupported(meta, provider.VaultVersion115)
|
||||
if useAPIVer115 {
|
||||
if err := d.Set(consts.FieldRotationSchedule, role.Data[consts.FieldRotationSchedule]); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
if err := d.Set(consts.FieldRotationWindow, role.Data[consts.FieldRotationWindow]); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
err = d.Set("rotation_statements", rotation)
|
||||
if err != nil {
|
||||
return fmt.Errorf("unexpected value %q for rotation_statements of %s: %s", rotation, path, err)
|
||||
|
||||
for _, k := range staticRoleFields {
|
||||
if v, ok := role.Data[k]; ok {
|
||||
if err := d.Set(k, v); err != nil {
|
||||
return diag.FromErr(err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func databaseSecretBackendStaticRoleDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
func databaseSecretBackendStaticRoleDelete(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
|
||||
client, e := provider.GetClient(d, meta)
|
||||
if e != nil {
|
||||
return e
|
||||
return diag.FromErr(e)
|
||||
}
|
||||
|
||||
path := d.Id()
|
||||
log.Printf("[DEBUG] Deleting static role %q", path)
|
||||
_, err := client.Logical().Delete(path)
|
||||
if err != nil {
|
||||
return fmt.Errorf("error deleting static role %q: %s", path, err)
|
||||
return diag.Errorf("error deleting static role %q: %s", path, err)
|
||||
}
|
||||
log.Printf("[DEBUG] Deleted static role %q", path)
|
||||
return nil
|
||||
}
|
||||
|
||||
func databaseSecretBackendStaticRoleExists(d *schema.ResourceData, meta interface{}) (bool, error) {
|
||||
client, e := provider.GetClient(d, meta)
|
||||
if e != nil {
|
||||
return false, e
|
||||
}
|
||||
|
||||
path := d.Id()
|
||||
log.Printf("[DEBUG] Checking if %q exists", path)
|
||||
role, err := client.Logical().Read(path)
|
||||
if err != nil {
|
||||
return true, fmt.Errorf("error checking if %q exists: %s", path, err)
|
||||
}
|
||||
log.Printf("[DEBUG] Checked if %q exists", path)
|
||||
return role != nil, nil
|
||||
}
|
||||
|
||||
func databaseSecretBackendStaticRolePath(backend, name string) string {
|
||||
return strings.Trim(backend, "/") + "/static-roles/" + strings.Trim(name, "/")
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,14 +20,13 @@ import (
|
|||
)
|
||||
|
||||
func TestAccDatabaseSecretBackendStaticRole_import(t *testing.T) {
|
||||
connURL := os.Getenv("MYSQL_URL")
|
||||
if connURL == "" {
|
||||
t.Skip("MYSQL_URL not set")
|
||||
}
|
||||
connURL := testutil.SkipTestEnvUnset(t, "MYSQL_URL")[0]
|
||||
|
||||
backend := acctest.RandomWithPrefix("tf-test-db")
|
||||
username := acctest.RandomWithPrefix("user")
|
||||
dbName := acctest.RandomWithPrefix("db")
|
||||
name := acctest.RandomWithPrefix("staticrole")
|
||||
resourceName := "vault_database_secret_backend_static_role.test"
|
||||
|
||||
if err := createTestUser(connURL, username); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -39,13 +38,13 @@ func TestAccDatabaseSecretBackendStaticRole_import(t *testing.T) {
|
|||
CheckDestroy: testAccDatabaseSecretBackendStaticRoleCheckDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccDatabaseSecretBackendStaticRoleConfig_basic(name, username, dbName, backend, connURL),
|
||||
Config: testAccDatabaseSecretBackendStaticRoleConfig_rotationPeriod(name, username, dbName, backend, connURL),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "name", name),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "backend", backend),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "username", username),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "db_name", dbName),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "rotation_period", "3600"),
|
||||
resource.TestCheckResourceAttr(resourceName, "name", name),
|
||||
resource.TestCheckResourceAttr(resourceName, "backend", backend),
|
||||
resource.TestCheckResourceAttr(resourceName, "username", username),
|
||||
resource.TestCheckResourceAttr(resourceName, "db_name", dbName),
|
||||
resource.TestCheckResourceAttr(resourceName, "rotation_period", "3600"),
|
||||
),
|
||||
},
|
||||
{
|
||||
|
|
@ -57,15 +56,14 @@ func TestAccDatabaseSecretBackendStaticRole_import(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccDatabaseSecretBackendStaticRole_basic(t *testing.T) {
|
||||
connURL := os.Getenv("MYSQL_URL")
|
||||
if connURL == "" {
|
||||
t.Skip("MYSQL_URL not set")
|
||||
}
|
||||
func TestAccDatabaseSecretBackendStaticRole_rotationPeriod(t *testing.T) {
|
||||
connURL := testutil.SkipTestEnvUnset(t, "MYSQL_URL")[0]
|
||||
|
||||
backend := acctest.RandomWithPrefix("tf-test-db")
|
||||
name := acctest.RandomWithPrefix("staticrole")
|
||||
username := acctest.RandomWithPrefix("user")
|
||||
dbName := acctest.RandomWithPrefix("db")
|
||||
name := acctest.RandomWithPrefix("staticrole")
|
||||
resourceName := "vault_database_secret_backend_static_role.test"
|
||||
|
||||
if err := createTestUser(connURL, username); err != nil {
|
||||
t.Fatal(err)
|
||||
|
|
@ -77,24 +75,74 @@ func TestAccDatabaseSecretBackendStaticRole_basic(t *testing.T) {
|
|||
CheckDestroy: testAccDatabaseSecretBackendStaticRoleCheckDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccDatabaseSecretBackendStaticRoleConfig_basic(name, username, dbName, backend, connURL),
|
||||
Config: testAccDatabaseSecretBackendStaticRoleConfig_rotationPeriod(name, username, dbName, backend, connURL),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "name", name),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "backend", backend),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "username", username),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "db_name", dbName),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "rotation_period", "3600"),
|
||||
resource.TestCheckResourceAttr(resourceName, "name", name),
|
||||
resource.TestCheckResourceAttr(resourceName, "backend", backend),
|
||||
resource.TestCheckResourceAttr(resourceName, "username", username),
|
||||
resource.TestCheckResourceAttr(resourceName, "db_name", dbName),
|
||||
resource.TestCheckResourceAttr(resourceName, "rotation_period", "3600"),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccDatabaseSecretBackendStaticRoleConfig_updated(name, username, dbName, backend, connURL),
|
||||
Config: testAccDatabaseSecretBackendStaticRoleConfig_updatedRotationPeriod(name, username, dbName, backend, connURL),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "name", name),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "backend", backend),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "username", username),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "db_name", dbName),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "rotation_period", "1800"),
|
||||
resource.TestCheckResourceAttr("vault_database_secret_backend_static_role.test", "rotation_statements.0", "SELECT 1;"),
|
||||
resource.TestCheckResourceAttr(resourceName, "name", name),
|
||||
resource.TestCheckResourceAttr(resourceName, "backend", backend),
|
||||
resource.TestCheckResourceAttr(resourceName, "username", username),
|
||||
resource.TestCheckResourceAttr(resourceName, "db_name", dbName),
|
||||
resource.TestCheckResourceAttr(resourceName, "rotation_period", "1800"),
|
||||
resource.TestCheckResourceAttr(resourceName, "rotation_statements.0", "SELECT 1;"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func TestAccDatabaseSecretBackendStaticRole_rotationSchedule(t *testing.T) {
|
||||
connURL := os.Getenv("MYSQL_URL")
|
||||
if connURL == "" {
|
||||
t.Skip("MYSQL_URL not set")
|
||||
}
|
||||
backend := acctest.RandomWithPrefix("tf-test-db")
|
||||
username := acctest.RandomWithPrefix("username")
|
||||
dbName := acctest.RandomWithPrefix("db")
|
||||
name := acctest.RandomWithPrefix("static-role")
|
||||
resourceName := "vault_database_secret_backend_static_role.test"
|
||||
|
||||
if err := createTestUser(connURL, username); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
Providers: testProviders,
|
||||
PreCheck: func() {
|
||||
testutil.TestAccPreCheck(t)
|
||||
SkipIfAPIVersionLT(t, testProvider.Meta(), provider.VaultVersion115)
|
||||
},
|
||||
CheckDestroy: testAccDatabaseSecretBackendStaticRoleCheckDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
{
|
||||
Config: testAccDatabaseSecretBackendStaticRoleConfig_rotationSchedule(name, username, dbName, backend, connURL),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr(resourceName, "name", name),
|
||||
resource.TestCheckResourceAttr(resourceName, "backend", backend),
|
||||
resource.TestCheckResourceAttr(resourceName, "username", username),
|
||||
resource.TestCheckResourceAttr(resourceName, "db_name", dbName),
|
||||
resource.TestCheckResourceAttr(resourceName, "rotation_schedule", "* * * * *"),
|
||||
resource.TestCheckResourceAttr(resourceName, "rotation_window", "3600"),
|
||||
),
|
||||
},
|
||||
{
|
||||
Config: testAccDatabaseSecretBackendStaticRoleConfig_updatedRotationSchedule(name, username, dbName, backend, connURL),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
resource.TestCheckResourceAttr(resourceName, "name", name),
|
||||
resource.TestCheckResourceAttr(resourceName, "backend", backend),
|
||||
resource.TestCheckResourceAttr(resourceName, "username", username),
|
||||
resource.TestCheckResourceAttr(resourceName, "db_name", dbName),
|
||||
resource.TestCheckResourceAttr(resourceName, "rotation_schedule", "*/30 * * * *"),
|
||||
resource.TestCheckResourceAttr(resourceName, "rotation_window", "14400"),
|
||||
resource.TestCheckResourceAttr(resourceName, "rotation_statements.0", "SELECT 1;"),
|
||||
),
|
||||
},
|
||||
},
|
||||
|
|
@ -117,7 +165,7 @@ func testAccDatabaseSecretBackendStaticRoleCheckDestroy(s *terraform.State) erro
|
|||
return err
|
||||
}
|
||||
if secret != nil {
|
||||
return fmt.Errorf("sttatic role %q still exists", rs.Primary.ID)
|
||||
return fmt.Errorf("static role %q still exists", rs.Primary.ID)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
@ -155,7 +203,65 @@ func createTestUser(connURL, username string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func testAccDatabaseSecretBackendStaticRoleConfig_basic(name, username, db, path, connURL string) string {
|
||||
func testAccDatabaseSecretBackendStaticRoleConfig_rotationSchedule(name, username, db, 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 = ["*"]
|
||||
|
||||
mysql {
|
||||
connection_url = "%s"
|
||||
}
|
||||
}
|
||||
|
||||
resource "vault_database_secret_backend_static_role" "test" {
|
||||
backend = vault_mount.db.path
|
||||
db_name = vault_database_secret_backend_connection.test.name
|
||||
name = "%s"
|
||||
username = "%s"
|
||||
rotation_schedule = "* * * * *"
|
||||
rotation_window = 3600
|
||||
rotation_statements = ["ALTER USER '{{username}}'@'localhost' IDENTIFIED BY '{{password}}';"]
|
||||
}
|
||||
`, path, db, connURL, name, username)
|
||||
}
|
||||
|
||||
func testAccDatabaseSecretBackendStaticRoleConfig_updatedRotationSchedule(name, username, db, 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 = ["*"]
|
||||
|
||||
mysql {
|
||||
connection_url = "%s"
|
||||
}
|
||||
}
|
||||
|
||||
resource "vault_database_secret_backend_static_role" "test" {
|
||||
backend = vault_mount.db.path
|
||||
db_name = vault_database_secret_backend_connection.test.name
|
||||
name = "%s"
|
||||
username = "%s"
|
||||
rotation_schedule = "*/30 * * * *"
|
||||
rotation_window = 14400
|
||||
rotation_statements = ["SELECT 1;"]
|
||||
}
|
||||
`, path, db, connURL, name, username)
|
||||
}
|
||||
|
||||
func testAccDatabaseSecretBackendStaticRoleConfig_rotationPeriod(name, username, db, path, connURL string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "vault_mount" "db" {
|
||||
path = "%s"
|
||||
|
|
@ -183,7 +289,7 @@ resource "vault_database_secret_backend_static_role" "test" {
|
|||
`, path, db, connURL, name, username)
|
||||
}
|
||||
|
||||
func testAccDatabaseSecretBackendStaticRoleConfig_updated(name, username, db, path, connURL string) string {
|
||||
func testAccDatabaseSecretBackendStaticRoleConfig_updatedRotationPeriod(name, username, db, path, connURL string) string {
|
||||
return fmt.Sprintf(`
|
||||
resource "vault_mount" "db" {
|
||||
path = "%s"
|
||||
|
|
|
|||
|
|
@ -30,14 +30,26 @@ resource "vault_database_secret_backend_connection" "postgres" {
|
|||
}
|
||||
}
|
||||
|
||||
resource "vault_database_secret_backend_static_role" "static_role" {
|
||||
# configure a static role with period-based rotations
|
||||
resource "vault_database_secret_backend_static_role" "period_role" {
|
||||
backend = vault_mount.db.path
|
||||
name = "my-static-role"
|
||||
name = "my-period-role"
|
||||
db_name = vault_database_secret_backend_connection.postgres.name
|
||||
username = "example"
|
||||
rotation_period = "3600"
|
||||
rotation_statements = ["ALTER USER \"{{name}}\" WITH PASSWORD '{{password}}';"]
|
||||
}
|
||||
|
||||
# configure a static role with schedule-based rotations
|
||||
resource "vault_database_secret_backend_static_role" "schedule_role" {
|
||||
backend = vault_mount.db.path
|
||||
name = "my-schedule-role"
|
||||
db_name = vault_database_secret_backend_connection.postgres.name
|
||||
username = "example"
|
||||
rotation_schedule = "0 0 * * SAT"
|
||||
rotation_window = "172800"
|
||||
rotation_statements = ["ALTER USER \"{{name}}\" WITH PASSWORD '{{password}}';"]
|
||||
}
|
||||
```
|
||||
|
||||
## Argument Reference
|
||||
|
|
@ -57,7 +69,17 @@ The following arguments are supported:
|
|||
|
||||
* `username` - (Required) The database username that this static role corresponds to.
|
||||
|
||||
* `rotation_period` - (Required) The amount of time Vault should wait before rotating the password, in seconds.
|
||||
* `rotation_period` - The amount of time Vault should wait before rotating the password, in seconds.
|
||||
Mutually exclusive with `rotation_schedule`.
|
||||
|
||||
* `rotation_schedule` - A cron-style string that will define the schedule on which rotations should occur.
|
||||
Mutually exclusive with `rotation_period`.
|
||||
|
||||
**Warning**: The `rotation_period` and `rotation_schedule` fields are
|
||||
mutually exclusive. One of them must be set but not both.
|
||||
|
||||
* `rotation_window` - (Optional) The amount of time, in seconds, in which rotations are allowed to occur starting
|
||||
from a given `rotation_schedule`.
|
||||
|
||||
* `rotation_statements` - (Optional) Database statements to execute to rotate the password for the configured database user.
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue