From 7efa7d82ca9880043091b58cff472f94409270ff Mon Sep 17 00:00:00 2001 From: kpcraig <3031348+kpcraig@users.noreply.github.com> Date: Wed, 21 Feb 2024 11:14:09 -0500 Subject: [PATCH] ldap rotation import skip parameter (#2128) --------- Co-authored-by: John-Michael Faircloth --- CHANGELOG.md | 1 + internal/consts/consts.go | 2 ++ ...ata_source_ldap_static_role_credentials.go | 5 +++ ...ource_ldap_static_role_credentials_test.go | 36 +++++++++++++++++++ vault/resource_ldap_secret_backend.go | 13 +++++++ ...esource_ldap_secret_backend_static_role.go | 14 ++++++++ ...ce_ldap_secret_backend_static_role_test.go | 29 +++++++++++++++ vault/resource_ldap_secret_backend_test.go | 18 ++++++++++ .../d/ldap_static_role_credentials.html.md | 3 ++ website/docs/r/ldap_secret_backend.html.md | 3 ++ .../r/ldap_secret_backend_static_role.html.md | 3 ++ 11 files changed, 127 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index e7e8a70d9..76269efd3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,7 @@ FEATURES: * Add destination and association resources to support Secrets Sync. Requires Vault 1.16+ ([#2098](https://github.com/hashicorp/terraform-provider-vault/pull/2098)). * Add support for configuration of plugin WIF to the AWS Secret Backend. Requires Vault 1.16+ ([#2138](https://github.com/hashicorp/terraform-provider-vault/pull/2138)). * Add support for Oracle database plugin configuration options `split_statements` and `disconnect_sessions`: ([#2085](https://github.com/hashicorp/terraform-provider-vault/pull/2085)) +* Add support for `skip_import_rotation` and `skip_static_role_import_rotation` in `ldap_secret_backend_static_role` and `ldap_secret_backend` respectively. Requires Vault 1.16+ ([#2128](https://github.com/hashicorp/terraform-provider-vault/pull/2128)). IMPROVEMENTS: * Add an API client lock to the `vault_identity_group_alias` resource: ([#2140](https://github.com/hashicorp/terraform-provider-vault/pull/2140)) diff --git a/internal/consts/consts.go b/internal/consts/consts.go index 9f72f0f34..119b28dfe 100644 --- a/internal/consts/consts.go +++ b/internal/consts/consts.go @@ -373,6 +373,8 @@ const ( FieldPermanentlyDelete = "permanently_delete" FieldSignInAudience = "sign_in_audience" FieldTags = "tags" + FieldSkipStaticRoleImportRotation = "skip_static_role_import_rotation" + FieldSkipImportRotation = "skip_import_rotation" FieldCustomTags = "custom_tags" FieldSecretNameTemplate = "secret_name_template" FieldIAMEndpoint = "iam_endpoint" diff --git a/vault/data_source_ldap_static_role_credentials.go b/vault/data_source_ldap_static_role_credentials.go index e2b1fdf85..49f838547 100644 --- a/vault/data_source_ldap_static_role_credentials.go +++ b/vault/data_source_ldap_static_role_credentials.go @@ -69,6 +69,11 @@ func ldapStaticCredDataSource() *schema.Resource { Computed: true, Description: "Name of the static role.", }, + consts.FieldSkipImportRotation: { + Type: schema.TypeBool, + Optional: true, + Description: "Skip rotation of the password on import.", + }, }, } } diff --git a/vault/data_source_ldap_static_role_credentials_test.go b/vault/data_source_ldap_static_role_credentials_test.go index 261da5f54..e842f8484 100644 --- a/vault/data_source_ldap_static_role_credentials_test.go +++ b/vault/data_source_ldap_static_role_credentials_test.go @@ -39,6 +39,16 @@ func TestAccDataSourceLDAPStaticRoleCredentials(t *testing.T) { resource.TestCheckResourceAttrSet(dataName, consts.FieldLastVaultRotation), ), }, + // second 1.16 gated check + { + SkipFunc: func() (bool, error) { + return !testProvider.Meta().(*provider.ProviderMeta).IsAPISupported(provider.VaultVersion116), nil + }, + Config: testLDAPStaticRoleDataSourceWithSkipImportRotation(backend, bindDN, bindPass, url, username, dn), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr("vault_ldap_secret_backend_static_role_with_skip", consts.FieldSkipImportRotation, "true"), + ), + }, }, }) } @@ -67,3 +77,29 @@ data "vault_ldap_static_credentials" "creds" { } `, path, bindDN, bindPass, url, username, dn, username) } + +func testLDAPStaticRoleDataSourceWithSkipImportRotation(path, bindDN, bindPass, url, username, dn string) string { + return fmt.Sprintf(` +resource "vault_ldap_secret_backend" "test" { + path = "%s" + description = "test description" + binddn = "%s" + bindpass = "%s" + url = "%s" +} + +resource "vault_ldap_secret_backend_static_role_with_skip" "role" { + mount = vault_ldap_secret_backend.test.path + username = "%s" + dn = "%s" + role_name = "%s" + rotation_period = 60 + skip_import_rotation = true +} + +data "vault_ldap_static_credentials" "creds" { + mount = vault_ldap_secret_backend.test.path + role_name = vault_ldap_secret_backend_static_role.role.role_name +} +`, path, bindDN, bindPass, url, username, dn, username) +} diff --git a/vault/resource_ldap_secret_backend.go b/vault/resource_ldap_secret_backend.go index 87a2bca11..fd69bf19f 100644 --- a/vault/resource_ldap_secret_backend.go +++ b/vault/resource_ldap_secret_backend.go @@ -119,6 +119,11 @@ func ldapSecretBackendResource() *schema.Resource { Optional: true, Description: "LDAP domain to use for users (eg: ou=People,dc=example,dc=org)", }, + consts.FieldSkipStaticRoleImportRotation: { + Type: schema.TypeBool, + Optional: true, + Description: "Skip rotation of static role secrets on import.", + }, } resource := provider.MustAddMountMigrationSchema(&schema.Resource{ CreateContext: provider.MountCreateContextWrapper(createUpdateLDAPConfigResource, provider.VaultVersion112), @@ -181,6 +186,11 @@ func createUpdateLDAPConfigResource(ctx context.Context, d *schema.ResourceData, consts.FieldStartTLS, } + // add skip_static_role_import_rotation if after vault 1.16 + if provider.IsAPISupported(meta, provider.VaultVersion116) { + booleanFields = append(booleanFields, consts.FieldSkipStaticRoleImportRotation) + } + // use d.Get() for boolean fields for _, field := range booleanFields { data[field] = d.Get(field) @@ -245,6 +255,9 @@ func readLDAPConfigResource(ctx context.Context, d *schema.ResourceData, meta in consts.FieldUserAttr, consts.FieldUserDN, } + if provider.IsAPISupported(meta, provider.VaultVersion116) { + fields = append(fields, consts.FieldSkipStaticRoleImportRotation) + } for _, field := range fields { if val, ok := resp.Data[field]; ok { diff --git a/vault/resource_ldap_secret_backend_static_role.go b/vault/resource_ldap_secret_backend_static_role.go index fda6cb183..0785d8ae3 100644 --- a/vault/resource_ldap_secret_backend_static_role.go +++ b/vault/resource_ldap_secret_backend_static_role.go @@ -47,6 +47,11 @@ func ldapSecretBackendStaticRoleResource() *schema.Resource { Required: true, Description: "How often Vault should rotate the password of the user entry.", }, + consts.FieldSkipImportRotation: { + Type: schema.TypeBool, + Optional: true, + Description: "Skip rotation of the password on import.", + }, } return &schema.Resource{ CreateContext: createUpdateLDAPStaticRoleResource, @@ -64,6 +69,7 @@ var ldapSecretBackendStaticRoleFields = []string{ consts.FieldUsername, consts.FieldDN, consts.FieldRotationPeriod, + consts.FieldSkipImportRotation, } func createUpdateLDAPStaticRoleResource(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -78,6 +84,11 @@ func createUpdateLDAPStaticRoleResource(ctx context.Context, d *schema.ResourceD log.Printf("[DEBUG] Creating LDAP static role at %q", rolePath) data := map[string]interface{}{} for _, field := range ldapSecretBackendStaticRoleFields { + // omit skip_import_rotation if vault version is less that 1.16 or if this is an update + // (alternately, only include skip_import_rotation on new resources created on 1.16 + if field == consts.FieldSkipImportRotation && (!provider.IsAPISupported(meta, provider.VaultVersion116) || !d.IsNewResource()) { + continue + } if v, ok := d.GetOk(field); ok { data[field] = v } @@ -109,6 +120,9 @@ func readLDAPStaticRoleResource(ctx context.Context, d *schema.ResourceData, met } for _, field := range ldapSecretBackendStaticRoleFields { + if field == consts.FieldSkipImportRotation && !provider.IsAPISupported(meta, provider.VaultVersion116) { + continue + } if val, ok := resp.Data[field]; ok { if err := d.Set(field, val); err != nil { return diag.FromErr(fmt.Errorf("error setting state key '%s': %s", field, err)) diff --git a/vault/resource_ldap_secret_backend_static_role_test.go b/vault/resource_ldap_secret_backend_static_role_test.go index 6b6a28608..c966b48d1 100644 --- a/vault/resource_ldap_secret_backend_static_role_test.go +++ b/vault/resource_ldap_secret_backend_static_role_test.go @@ -43,6 +43,13 @@ func TestAccLDAPSecretBackendStaticRole(t *testing.T) { resource.TestCheckResourceAttr(resourceName, consts.FieldRotationPeriod, rotationPeriod), ), }, + { + SkipFunc: func() (bool, error) { + return !testProvider.Meta().(*provider.ProviderMeta).IsAPISupported(provider.VaultVersion116), nil + }, + Config: testLDAPSecretBackendStaticRoleConfig_withSkip(path, bindDN, bindPass, url, username, dn, username, rotationPeriod), + Check: resource.TestCheckResourceAttr(resourceName, consts.FieldSkipImportRotation, "true"), + }, { Config: testLDAPSecretBackendStaticRoleConfig(path, bindDN, bindPass, url, updatedUsername, updatedDN, updatedUsername, updatedRotationPeriod), Check: resource.ComposeTestCheckFunc( @@ -76,3 +83,25 @@ resource "vault_ldap_secret_backend_static_role" "role" { } `, mount, bindDN, bindPass, url, username, dn, role, rotationPeriod) } + +func testLDAPSecretBackendStaticRoleConfig_withSkip(mount, bindDN, bindPass, url, username, dn, role, rotationPeriod string) string { + return fmt.Sprintf(` +resource "vault_ldap_secret_backend" "test" { + path = "%s" + description = "test description" + binddn = "%s" + bindpass = "%s" + url = "%s" + userdn = "CN=Users,DC=corp,DC=example,DC=net" +} + +resource "vault_ldap_secret_backend_static_role" "role" { + mount = vault_ldap_secret_backend.test.path + username = "%s" + dn = "%s" + role_name = "%s" + rotation_period = %s + skip_import_rotation = true +} +`, mount, bindDN, bindPass, url, username, dn, role, rotationPeriod) +} diff --git a/vault/resource_ldap_secret_backend_test.go b/vault/resource_ldap_secret_backend_test.go index 4dff1d0e2..7cda89bff 100644 --- a/vault/resource_ldap_secret_backend_test.go +++ b/vault/resource_ldap_secret_backend_test.go @@ -61,6 +61,13 @@ func TestLDAPSecretBackend(t *testing.T) { resource.TestCheckResourceAttr(resourceName, consts.FieldConnectionTimeout, "30"), ), }, + { + SkipFunc: func() (bool, error) { + return !testProvider.Meta().(*provider.ProviderMeta).IsAPISupported(provider.VaultVersion116), nil + }, + Config: testLDAPSecretBackendConfig_withSkip(path, bindDN, bindPass), + Check: resource.TestCheckResourceAttr(resourceName, consts.FieldSkipStaticRoleImportRotation, "true"), + }, { Config: testLDAPSecretBackendConfig(path, updatedDescription, bindDN, bindPass, url, updatedUserDN, "openldap", false), Check: resource.ComposeTestCheckFunc( @@ -190,6 +197,17 @@ resource "vault_ldap_secret_backend" "test" { }`, path, bindDN, bindPass) } +func testLDAPSecretBackendConfig_withSkip(path, bindDN, bindPass string) string { + return fmt.Sprintf(` +resource "vault_ldap_secret_backend" "test" { + path = "%s" + description = "test description" + binddn = "%s" + bindpass = "%s" + skip_static_role_import_rotation = true +}`, path, bindDN, bindPass) +} + func testLDAPSecretBackendConfig(mount, description, bindDN, bindPass, url, userDN, schema string, insecureTLS bool) string { return fmt.Sprintf(` resource "vault_ldap_secret_backend" "test" { diff --git a/website/docs/d/ldap_static_role_credentials.html.md b/website/docs/d/ldap_static_role_credentials.html.md index dd2b5f25f..0a0f2de9a 100644 --- a/website/docs/d/ldap_static_role_credentials.html.md +++ b/website/docs/d/ldap_static_role_credentials.html.md @@ -72,3 +72,6 @@ In addition to the arguments above, the following attributes are exported: * `ttl` - Duration in seconds after which the issued credential should expire. * `username` - The name of the static role. + +* `skip_import_rotation` - (Optional) Causes vault to skip the initial rotation on import. Not applicable on updates. + Requires Vault 1.16 or above. diff --git a/website/docs/r/ldap_secret_backend.html.md b/website/docs/r/ldap_secret_backend.html.md index add2c9de9..61252adcd 100644 --- a/website/docs/r/ldap_secret_backend.html.md +++ b/website/docs/r/ldap_secret_backend.html.md @@ -90,6 +90,9 @@ The following arguments are supported: * `userdn` - (Optional) LDAP domain to use for users (eg: ou=People,dc=example,dc=org)`. +* `skip_static_role_import_rotation` - (Optional) If set to true, static roles will not be rotated during import. + Defaults to false. Requires Vault 1.16 or above. + ## Attributes Reference No additional attributes are exported by this resource. diff --git a/website/docs/r/ldap_secret_backend_static_role.html.md b/website/docs/r/ldap_secret_backend_static_role.html.md index 36dc2a6a7..46cdd387d 100644 --- a/website/docs/r/ldap_secret_backend_static_role.html.md +++ b/website/docs/r/ldap_secret_backend_static_role.html.md @@ -61,6 +61,9 @@ The following arguments are supported: * `rotation_period` - (Required) How often Vault should rotate the password of the user entry. +* `skip_import_rotation` - (Optional) Causes vault to skip the initial secret rotation on import. Not applicable to updates. + Requires Vault 1.16 or above. + ## Attributes Reference No additional attributes are exported by this resource.