From 1e4de5c0f01c076c2368ffebb1edc79a629761e3 Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Mon, 30 Sep 2024 17:40:10 -0700 Subject: [PATCH 1/4] deprecate tune block and update auth backend resources with mount fields --- internal/consts/consts.go | 2 + vault/auth_mount.go | 284 ++++++++++++++++++++++++-- vault/resource_auth_backend.go | 120 ++--------- vault/resource_gcp_auth_backend.go | 119 ++--------- vault/resource_github_auth_backend.go | 75 ++----- vault/resource_jwt_auth_backend.go | 88 +++----- vault/resource_ldap_auth_backend.go | 59 +++--- vault/resource_okta_auth_backend.go | 60 ++---- vault/resource_saml_auth_backend.go | 39 ++-- 9 files changed, 420 insertions(+), 426 deletions(-) diff --git a/internal/consts/consts.go b/internal/consts/consts.go index cb271ad565..c34ead7c79 100644 --- a/internal/consts/consts.go +++ b/internal/consts/consts.go @@ -437,6 +437,8 @@ const ( FieldTune = "tune" FieldMaxRetries = "max_retries" FieldSessionTags = "session_tags" + FieldTokenType = "token_type" + FieldUserLockoutConfig = "user_lockout_config" /* common environment variables diff --git a/vault/auth_mount.go b/vault/auth_mount.go index dfe3fb8a9b..2bd5f94a13 100644 --- a/vault/auth_mount.go +++ b/vault/auth_mount.go @@ -5,18 +5,28 @@ package vault import ( "context" - - "log" - + "fmt" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-vault/internal/consts" "github.com/hashicorp/terraform-provider-vault/internal/provider" + "github.com/hashicorp/terraform-provider-vault/util/mountutil" "github.com/hashicorp/vault/api" + "github.com/mitchellh/mapstructure" + "log" +) + +const ( + fieldLockoutThreshold = "lockout_threshold" + fieldLockoutDuration = "lockout_duration" + fieldLockoutCounterResetDuration = "lockout_counter_reset_duration" + fieldLockoutDisable = "lockout_disable" ) func authMountTuneSchema() *schema.Schema { return &schema.Schema{ + Deprecated: `Deprecated. Please use dedicated schema fields instead. Will be removed in next major release`, Type: schema.TypeSet, Optional: true, Computed: true, @@ -77,28 +87,274 @@ func authMountTuneSchema() *schema.Schema { } } -func authMountTune(ctx context.Context, client *api.Client, path string, configured interface{}) error { - input := expandAuthMethodTune(configured.(*schema.Set).List()) +func getAuthMountSchema(excludes ...string) schemaMap { + s := schemaMap{ + consts.FieldTokenType: { + Type: schema.TypeString, + Optional: true, + Computed: true, + Description: "Specifies the type of tokens that should be returned by the mount.", + ValidateFunc: validation.StringInSlice([]string{"default-service", "default-batch", "service", "batch"}, false), + }, + consts.FieldUserLockoutConfig: { + Type: schema.TypeMap, + Optional: true, + Description: "Specifies the user lockout configuration for the mount. Requires Vault 1.13+.", + }, + } + + for k, v := range getMountSchema( + // not used by auth engines + consts.FieldDelegatedAuthAccessors, + consts.FieldExternalEntropyAccess, + consts.FieldAllowedManagedKeys, + consts.FieldOptions, + ) { + s[k] = v + } - return tuneMount(ctx, client, path, input) + for _, v := range excludes { + delete(s, v) + } + return s } -func tuneMount(ctx context.Context, client *api.Client, path string, input api.MountConfigInput) error { - err := client.Sys().TuneMountWithContext(ctx, path, input) +func createAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{}, client *api.Client, path string, mountType string) error { + options := &api.EnableAuthOptions{ + Type: mountType, + Description: d.Get(consts.FieldDescription).(string), + Local: d.Get(consts.FieldLocal).(bool), + SealWrap: d.Get(consts.FieldSealWrap).(bool), + Config: api.MountConfigInput{ + DefaultLeaseTTL: fmt.Sprintf("%ds", d.Get(consts.FieldDefaultLeaseTTL)), + MaxLeaseTTL: fmt.Sprintf("%ds", d.Get(consts.FieldMaxLeaseTTL)), + }, + } + + if v, ok := d.GetOk(consts.FieldAuditNonHMACRequestKeys); ok { + options.Config.AuditNonHMACRequestKeys = expandStringSlice(v.([]interface{})) + } + if v, ok := d.GetOk(consts.FieldAuditNonHMACResponseKeys); ok { + options.Config.AuditNonHMACResponseKeys = expandStringSlice(v.([]interface{})) + } + + if v, ok := d.GetOk(consts.FieldPassthroughRequestHeaders); ok { + options.Config.PassthroughRequestHeaders = expandStringSlice(v.([]interface{})) + } + + if v, ok := d.GetOk(consts.FieldAllowedResponseHeaders); ok { + options.Config.AllowedResponseHeaders = expandStringSlice(v.([]interface{})) + } + + if v, ok := d.GetOk(consts.FieldListingVisibility); ok { + options.Config.ListingVisibility = v.(string) + } + + if v, ok := d.GetOk(consts.FieldPluginVersion); ok { + options.Config.PluginVersion = v.(string) + } + + if d.HasChange(consts.FieldTokenType) { + options.Config.TokenType = d.Get(consts.FieldTokenType).(string) + } + + if d.HasChange(consts.FieldUserLockoutConfig) { + userLockoutCfg, err := getUserLockoutConfig(d.Get(consts.FieldUserLockoutConfig).(map[string]string)) + if err != nil { + return fmt.Errorf("error reading '%s': %s", consts.FieldUserLockoutConfig, err) + } + + options.Config.UserLockoutConfig = userLockoutCfg + } + + useAPIVer116Ent := provider.IsAPISupported(meta, provider.VaultVersion116) && provider.IsEnterpriseSupported(meta) + if useAPIVer116Ent { + if d.HasChange(consts.FieldIdentityTokenKey) { + options.Config.IdentityTokenKey = d.Get(consts.FieldIdentityTokenKey).(string) + } + } + + log.Printf("[DEBUG] Creating auth mount %s in Vault", path) + + err := client.Sys().EnableAuthWithOptionsWithContext(ctx, path, options) if err != nil { - return err + return fmt.Errorf("error writing to Vault: %s", err) } + return nil } -func authMountTuneGet(ctx context.Context, client *api.Client, path string) (map[string]interface{}, error) { - tune, err := client.Sys().MountConfigWithContext(ctx, path) +func updateAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{}, excludeType bool) error { + client, err := provider.GetClient(d, meta) if err != nil { - log.Printf("[ERROR] Error when reading tune config from path %q: %s", path+"/tune", err) - return nil, err + return err + } + + config := api.MountConfigInput{ + DefaultLeaseTTL: fmt.Sprintf("%ds", d.Get(consts.FieldDefaultLeaseTTL)), + MaxLeaseTTL: fmt.Sprintf("%ds", d.Get(consts.FieldMaxLeaseTTL)), + } + + if d.HasChange(consts.FieldAuditNonHMACRequestKeys) { + config.AuditNonHMACRequestKeys = expandStringSlice(d.Get(consts.FieldAuditNonHMACRequestKeys).([]interface{})) + } + + if d.HasChange(consts.FieldAuditNonHMACResponseKeys) { + config.AuditNonHMACResponseKeys = expandStringSlice(d.Get(consts.FieldAuditNonHMACResponseKeys).([]interface{})) + } + + if d.HasChange(consts.FieldDescription) { + description := fmt.Sprintf("%s", d.Get(consts.FieldDescription)) + config.Description = &description + } + + path := d.Id() + authPath := "auth/" + path + + if d.HasChange(consts.FieldPassthroughRequestHeaders) { + config.PassthroughRequestHeaders = expandStringSlice(d.Get(consts.FieldPassthroughRequestHeaders).([]interface{})) + } + + if d.HasChange(consts.FieldAllowedResponseHeaders) { + config.AllowedResponseHeaders = expandStringSlice(d.Get(consts.FieldAllowedResponseHeaders).([]interface{})) + } + + if d.HasChange(consts.FieldListingVisibility) { + config.ListingVisibility = d.Get(consts.FieldListingVisibility).(string) + } + + if d.HasChange(consts.FieldPluginVersion) { + config.PluginVersion = d.Get(consts.FieldPluginVersion).(string) + } + + if d.HasChange(consts.FieldTokenType) { + config.TokenType = d.Get(consts.FieldTokenType).(string) + } + + if d.HasChange(consts.FieldUserLockoutConfig) { + userLockoutCfg, err := getUserLockoutConfig(d.Get(consts.FieldUserLockoutConfig).(map[string]string)) + if err != nil { + return fmt.Errorf("error reading '%s': %s", consts.FieldUserLockoutConfig, err) + } + + config.UserLockoutConfig = userLockoutCfg + } + + useAPIVer116Ent := provider.IsAPISupported(meta, provider.VaultVersion116) && provider.IsEnterpriseSupported(meta) + if useAPIVer116Ent { + if d.HasChange(consts.FieldIdentityTokenKey) { + config.IdentityTokenKey = d.Get(consts.FieldIdentityTokenKey).(string) + } + } + + log.Printf("[DEBUG] Updating auth mount %s in Vault", path) + + if err := client.Sys().TuneMountWithContext(ctx, authPath, config); err != nil { + return fmt.Errorf("error updating Vault: %s", err) + } + + return readAuthMount(ctx, d, meta, excludeType) +} + +func readAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{}, excludeType bool) error { + client, e := provider.GetClient(d, meta) + if e != nil { + return e + } + + path := d.Id() + + log.Printf("[DEBUG] Reading auth mount %s from Vault", path) + + mount, err := mountutil.GetAuthMount(ctx, client, path) + if err != nil { + if mountutil.IsMountNotFoundError(err) { + log.Printf("[WARN] Mount %q not found, removing from state.", path) + d.SetId("") + return nil + } + return err + } + + if !excludeType { + if err := d.Set(consts.FieldType, mount.Type); err != nil { + return err + } + } + + if err := d.Set(consts.FieldPath, path); err != nil { + return err + } + if err := d.Set(consts.FieldDescription, mount.Description); err != nil { + return err + } + if err := d.Set(consts.FieldDefaultLeaseTTL, mount.Config.DefaultLeaseTTL); err != nil { + return err + } + if err := d.Set(consts.FieldMaxLeaseTTL, mount.Config.MaxLeaseTTL); err != nil { + return err + } + if err := d.Set(consts.FieldAuditNonHMACRequestKeys, mount.Config.AuditNonHMACRequestKeys); err != nil { + return err + } + if err := d.Set(consts.FieldAuditNonHMACResponseKeys, mount.Config.AuditNonHMACResponseKeys); err != nil { + return err + } + if err := d.Set(consts.FieldAccessor, mount.Accessor); err != nil { + return err + } + if err := d.Set(consts.FieldLocal, mount.Local); err != nil { + return err + } + if err := d.Set(consts.FieldSealWrap, mount.SealWrap); err != nil { + return err + } + + if err := d.Set(consts.FieldPassthroughRequestHeaders, mount.Config.PassthroughRequestHeaders); err != nil { + return err + } + if err := d.Set(consts.FieldAllowedResponseHeaders, mount.Config.AllowedResponseHeaders); err != nil { + return err + } + + if err := d.Set(consts.FieldListingVisibility, mount.Config.ListingVisibility); err != nil { + return err + } + if err := d.Set(consts.FieldIdentityTokenKey, mount.Config.IdentityTokenKey); err != nil { + return err + } + + if err := d.Set(consts.FieldTokenType, mount.Config.TokenType); err != nil { + return err + } + + if err := d.Set(consts.FieldUserLockoutConfig, flattenUserLockoutConfig(mount.Config.UserLockoutConfig)); err != nil { + return err + } + + return nil +} + +func getUserLockoutConfig(m map[string]string) (*api.UserLockoutConfigInput, error) { + result := &api.UserLockoutConfigInput{} + if err := mapstructure.Decode(m, result); err != nil { + return nil, fmt.Errorf("invalid format for user_lockout_config: %s", err) + } + + return result, nil +} + +func flattenUserLockoutConfig(output *api.UserLockoutConfigOutput) map[string]string { + m := make(map[string]string) + + if output != nil { + m[fieldLockoutThreshold] = fmt.Sprintf("%d", output.LockoutThreshold) + m[fieldLockoutDisable] = fmt.Sprintf("%t", *output.DisableLockout) + m[fieldLockoutDuration] = fmt.Sprintf("%d", output.LockoutDuration) + m[fieldLockoutCounterResetDuration] = fmt.Sprintf("%d", output.LockoutCounterReset) } - return flattenAuthMethodTune(tune), nil + return m } func authMountDisable(ctx context.Context, client *api.Client, path string) diag.Diagnostics { diff --git a/vault/resource_auth_backend.go b/vault/resource_auth_backend.go index 5d28679ba3..3b95caf2bd 100644 --- a/vault/resource_auth_backend.go +++ b/vault/resource_auth_backend.go @@ -9,16 +9,13 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/vault/api" - "github.com/hashicorp/terraform-provider-vault/internal/consts" "github.com/hashicorp/terraform-provider-vault/internal/provider" "github.com/hashicorp/terraform-provider-vault/util" - "github.com/hashicorp/terraform-provider-vault/util/mountutil" ) func AuthBackendResource() *schema.Resource { - return provider.MustAddMountMigrationSchema(&schema.Resource{ + r := provider.MustAddMountMigrationSchema(&schema.Resource{ SchemaVersion: 1, CreateContext: authBackendWrite, @@ -78,6 +75,18 @@ func AuthBackendResource() *schema.Resource { consts.FieldTune: authMountTuneSchema(), }, }, false) + + // Add common mount schema to the resource + provider.MustAddSchema(r, getAuthMountSchema( + consts.FieldPath, + consts.FieldType, + consts.FieldDescription, + consts.FieldAccessor, + consts.FieldLocal, + consts.FieldIdentityTokenKey, + )) + + return r } func authBackendWrite(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -93,26 +102,10 @@ func authBackendWrite(ctx context.Context, d *schema.ResourceData, meta interfac path = mountType } - config := &api.MountConfigInput{} - useAPIver117Ent := provider.IsAPISupported(meta, provider.VaultVersion117) && provider.IsEnterpriseSupported(meta) - if useAPIver117Ent { - if v, ok := d.GetOk(consts.FieldIdentityTokenKey); ok { - config.IdentityTokenKey = v.(string) - } - } - - options := &api.EnableAuthOptions{ - Type: mountType, - Description: d.Get(consts.FieldDescription).(string), - Local: d.Get(consts.FieldLocal).(bool), - Config: *config, - } - log.Printf("[DEBUG] Writing auth %q to Vault", path) - if err := client.Sys().EnableAuthWithOptionsWithContext(ctx, path, options); err != nil { - return diag.Errorf("error writing to Vault: %s", err) + if err := createAuthMount(ctx, d, meta, client, path, mountType); err != nil { + return diag.FromErr(err) } - d.SetId(path) return authBackendUpdate(ctx, d, meta) @@ -123,56 +116,13 @@ func authBackendDelete(ctx context.Context, d *schema.ResourceData, meta interfa if e != nil { return diag.FromErr(e) } - - path := d.Id() - - log.Printf("[DEBUG] Deleting auth %s from Vault", path) - - if err := client.Sys().DisableAuthWithContext(ctx, path); err != nil { - return diag.Errorf("error disabling auth from Vault: %s", err) - } - - return nil + return authMountDisable(ctx, client, d.Id()) } func authBackendRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - client, e := provider.GetClient(d, meta) - if e != nil { - return diag.FromErr(e) - } - - path := d.Id() - - mount, err := mountutil.GetAuthMount(ctx, client, path) - if err != nil { - if mountutil.IsMountNotFoundError(err) { - log.Printf("[WARN] Mount %q not found, removing from state.", path) - d.SetId("") - return nil - } - return diag.FromErr(err) - } - - if err := d.Set(consts.FieldType, mount.Type); err != nil { - return diag.FromErr(err) - } - if err := d.Set(consts.FieldPath, path); err != nil { + if err := readAuthMount(ctx, d, meta, true); err != nil { return diag.FromErr(err) } - if err := d.Set(consts.FieldDescription, mount.Description); err != nil { - return diag.FromErr(err) - } - if err := d.Set(consts.FieldLocal, mount.Local); err != nil { - return diag.FromErr(err) - } - if err := d.Set(consts.FieldAccessor, mount.Accessor); err != nil { - return diag.FromErr(err) - } - // TODO: uncomment when identity token key is being returned on the read mount endpoint - // if err := d.Set(consts.FieldIdentityTokenKey, mount.Config.IdentityTokenKey); err != nil { - // return diag.FromErr(err) - // } - return nil } @@ -190,41 +140,11 @@ func authBackendUpdate(ctx context.Context, d *schema.ResourceData, meta interfa if e != nil { return diag.FromErr(e) } - } - - backendType := d.Get(consts.FieldType).(string) - var config api.MountConfigInput - var callTune bool - if d.HasChange(consts.FieldTune) { - log.Printf("[INFO] Auth '%q' tune configuration changed", path) - - if raw, ok := d.GetOk(consts.FieldTune); ok { - log.Printf("[DEBUG] Writing %s auth tune to '%q'", backendType, path) - - config = expandAuthMethodTune(raw.(*schema.Set).List()) - } - callTune = true - } - - if d.HasChanges(consts.FieldIdentityTokenKey, consts.FieldDescription) && !d.IsNewResource() { - desc := d.Get(consts.FieldDescription).(string) - config.Description = &desc - - useAPIVer117Ent := provider.IsAPISupported(meta, provider.VaultVersion117) && provider.IsEnterpriseSupported(meta) - if useAPIVer117Ent { - config.IdentityTokenKey = d.Get(consts.FieldIdentityTokenKey).(string) + // tune auth mount if needed + if err := updateAuthMount(ctx, d, meta, true); err != nil { + return diag.FromErr(err) } - - callTune = true - } - - if callTune { - if err := tuneMount(ctx, client, "auth/"+path, config); err != nil { - return diag.FromErr(e) - } - - log.Printf("[INFO] Written %s auth tune to '%q'", backendType, path) } return authBackendRead(ctx, d, meta) diff --git a/vault/resource_gcp_auth_backend.go b/vault/resource_gcp_auth_backend.go index f4db02170e..7acb767706 100644 --- a/vault/resource_gcp_auth_backend.go +++ b/vault/resource_gcp_auth_backend.go @@ -12,12 +12,9 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/vault/api" - "github.com/hashicorp/terraform-provider-vault/internal/consts" "github.com/hashicorp/terraform-provider-vault/internal/provider" "github.com/hashicorp/terraform-provider-vault/util" - "github.com/hashicorp/terraform-provider-vault/util/mountutil" ) const ( @@ -31,7 +28,7 @@ const ( ) func gcpAuthBackendResource() *schema.Resource { - return provider.MustAddMountMigrationSchema(&schema.Resource{ + r := provider.MustAddMountMigrationSchema(&schema.Resource{ CreateContext: gcpAuthBackendWrite, UpdateContext: gcpAuthBackendUpdate, ReadContext: provider.ReadContextWrapper(gcpAuthBackendRead), @@ -123,6 +120,18 @@ func gcpAuthBackendResource() *schema.Resource { consts.FieldTune: authMountTuneSchema(), }, }, false) + + // Add common mount schema to the resource + provider.MustAddSchema(r, getAuthMountSchema( + consts.FieldPath, + consts.FieldType, + consts.FieldDescription, + consts.FieldAccessor, + consts.FieldLocal, + consts.FieldIdentityTokenKey, + )) + + return r } func gcpAuthCustomEndpointSchema() map[string]*schema.Schema { @@ -195,28 +204,11 @@ func gcpAuthBackendWrite(ctx context.Context, d *schema.ResourceData, meta inter return diag.FromErr(e) } - authType := gcpAuthType path := d.Get(consts.FieldPath).(string) - desc := d.Get(consts.FieldDescription).(string) - local := d.Get(consts.FieldLocal).(bool) - - config := &api.MountConfigInput{} - useAPIver117Ent := provider.IsAPISupported(meta, provider.VaultVersion117) && provider.IsEnterpriseSupported(meta) - if useAPIver117Ent { - if v, ok := d.GetOk(consts.FieldIdentityTokenKey); ok { - config.IdentityTokenKey = v.(string) - } - } log.Printf("[DEBUG] Enabling gcp auth backend %q", path) - err := client.Sys().EnableAuthWithOptionsWithContext(ctx, path, &api.EnableAuthOptions{ - Type: authType, - Description: desc, - Local: local, - Config: *config, - }) - if err != nil { - return diag.Errorf("error enabling gcp auth backend %q: %s", path, err) + if err := createAuthMount(ctx, d, meta, client, path, gcpAuthType); err != nil { + return diag.FromErr(err) } log.Printf("[DEBUG] Enabled gcp auth backend %q", path) @@ -232,7 +224,6 @@ func gcpAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta inte } gcpPath := d.Id() - gcpAuthPath := "auth/" + gcpPath path := gcpAuthBackendConfigPath(gcpPath) if !d.IsNewResource() { @@ -241,21 +232,11 @@ func gcpAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta inte return diag.FromErr(err) } - gcpAuthPath = "auth/" + newMount path = gcpAuthBackendConfigPath(newMount) - if d.HasChanges(consts.FieldIdentityTokenKey, consts.FieldDescription) { - desc := d.Get(consts.FieldDescription).(string) - config := api.MountConfigInput{ - Description: &desc, - } - useAPIVer117Ent := provider.IsAPISupported(meta, provider.VaultVersion117) && provider.IsEnterpriseSupported(meta) - if useAPIVer117Ent { - config.IdentityTokenKey = d.Get(consts.FieldIdentityTokenKey).(string) - } - if err := client.Sys().TuneMountWithContext(ctx, path, config); err != nil { - return diag.FromErr(err) - } + // tune auth mount if needed + if err := updateAuthMount(ctx, d, meta, true); err != nil { + return diag.FromErr(err) } } @@ -277,27 +258,6 @@ func gcpAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta inte data[consts.FieldCustomEndpoint] = endpoints } - if d.HasChange(consts.FieldTune) { - log.Printf("[INFO] %s Auth %q tune configuration changed", gcpAuthType, gcpAuthPath) - if raw, ok := d.GetOk(consts.FieldTune); ok { - log.Printf("[DEBUG] Writing %s auth tune to %q", gcpAuthType, gcpAuthPath) - err := authMountTune(ctx, client, gcpAuthPath, raw) - if err != nil { - return nil - } - } - } - - if d.HasChange(consts.FieldDescription) { - description := d.Get(consts.FieldDescription).(string) - tune := api.MountConfigInput{Description: &description} - err := client.Sys().TuneMountWithContext(ctx, gcpAuthPath, tune) - if err != nil { - log.Printf("[ERROR] Error updating %s auth description at %q", gcpAuthType, gcpAuthPath) - return diag.FromErr(err) - } - } - useAPIver117Ent := provider.IsAPISupported(meta, provider.VaultVersion117) && provider.IsEnterpriseSupported(meta) if useAPIver117Ent { fields := []string{ @@ -332,7 +292,6 @@ func gcpAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta interf } gcpPath := d.Id() - gcpAuthPath := "auth/" + gcpPath path := gcpAuthBackendConfigPath(gcpPath) log.Printf("[DEBUG] Reading gcp auth backend config %q", path) @@ -381,35 +340,7 @@ func gcpAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta interf } } - mount, err := mountutil.GetAuthMount(ctx, client, gcpPath) - if err != nil { - if mountutil.IsMountNotFoundError(err) { - log.Printf("[WARN] Mount %q not found, removing from state.", gcpPath) - d.SetId("") - return nil - } - return diag.FromErr(err) - } - - log.Printf("[DEBUG] Reading %s auth tune from '%s/tune'", gcpAuthType, gcpAuthPath) - rawTune, err := authMountTuneGet(ctx, client, gcpAuthPath) - if err != nil { - return diag.Errorf("error reading tune information from Vault: %s", err) - } - data := map[string]interface{}{} - data[consts.FieldTune] = []map[string]interface{}{rawTune} - if err := util.SetResourceData(d, data); err != nil { - return diag.FromErr(err) - } - - if err := d.Set(consts.FieldAccessor, mount.Accessor); err != nil { - return diag.FromErr(err) - } - if err := d.Set(consts.FieldDescription, mount.Description); err != nil { - return diag.FromErr(err) - } - // set the auth backend's path - if err := d.Set(consts.FieldPath, gcpPath); err != nil { + if err := readAuthMount(ctx, d, meta, true); err != nil { return diag.FromErr(err) } @@ -421,15 +352,5 @@ func gcpAuthBackendDelete(ctx context.Context, d *schema.ResourceData, meta inte if e != nil { return diag.FromErr(e) } - - path := d.Id() - - log.Printf("[DEBUG] Deleting gcp auth backend %q", path) - err := client.Sys().DisableAuthWithContext(ctx, path) - if err != nil { - return diag.Errorf("error deleting gcp auth backend %q: %q", path, err) - } - log.Printf("[DEBUG] Deleted gcp auth backend %q", path) - - return nil + return authMountDisable(ctx, client, d.Id()) } diff --git a/vault/resource_github_auth_backend.go b/vault/resource_github_auth_backend.go index edf83442c5..cf1db67e1f 100644 --- a/vault/resource_github_auth_backend.go +++ b/vault/resource_github_auth_backend.go @@ -10,12 +10,9 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/vault/api" - "github.com/hashicorp/terraform-provider-vault/internal/consts" "github.com/hashicorp/terraform-provider-vault/internal/provider" "github.com/hashicorp/terraform-provider-vault/util" - "github.com/hashicorp/terraform-provider-vault/util/mountutil" ) func githubAuthBackendResource() *schema.Resource { @@ -62,7 +59,7 @@ func githubAuthBackendResource() *schema.Resource { addTokenFields(fields, &addTokenFieldsConfig{}) - return provider.MustAddMountMigrationSchema(&schema.Resource{ + r := provider.MustAddMountMigrationSchema(&schema.Resource{ CreateContext: githubAuthBackendCreate, ReadContext: provider.ReadContextWrapper(githubAuthBackendRead), UpdateContext: githubAuthBackendUpdate, @@ -73,6 +70,17 @@ func githubAuthBackendResource() *schema.Resource { Schema: fields, CustomizeDiff: getMountCustomizeDiffFunc(consts.FieldPath), }, false) + + // Add common mount schema to the resource + provider.MustAddSchema(r, getAuthMountSchema( + consts.FieldPath, + consts.FieldType, + consts.FieldDescription, + consts.FieldAccessor, + consts.FieldTokenType, + )) + + return r } func githubAuthBackendCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -80,21 +88,12 @@ func githubAuthBackendCreate(ctx context.Context, d *schema.ResourceData, meta i if e != nil { return diag.FromErr(e) } - var description string path := strings.Trim(d.Get(consts.FieldPath).(string), "/") - if v, ok := d.GetOk("description"); ok { - description = v.(string) - } - log.Printf("[DEBUG] Enabling github auth backend at '%s'", path) - err := client.Sys().EnableAuthWithOptionsWithContext(ctx, path, &api.EnableAuthOptions{ - Type: consts.MountTypeGitHub, - Description: description, - }) - if err != nil { - return diag.Errorf("error enabling github auth backend at '%s': %s", path, err) + if err := createAuthMount(ctx, d, meta, client, path, consts.MountTypeGitHub); err != nil { + return diag.FromErr(err) } log.Printf("[INFO] Enabled github auth backend at '%s'", path) @@ -120,6 +119,11 @@ func githubAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta i path = "auth/" + mount configPath = path + "/config" + + // tune auth mount if needed + if err := updateAuthMount(ctx, d, meta, true); err != nil { + return diag.FromErr(err) + } } data := map[string]interface{}{} @@ -144,30 +148,6 @@ func githubAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta i } log.Printf("[INFO] Github auth config successfully written to '%q'", configPath) - if d.HasChange("tune") { - log.Printf("[INFO] Github Auth '%q' tune configuration changed", d.Id()) - if raw, ok := d.GetOk("tune"); ok { - log.Printf("[DEBUG] Writing github auth tune to '%q'", path) - - err := authMountTune(ctx, client, path, raw) - if err != nil { - return nil - } - - log.Printf("[INFO] Written github auth tune to '%q'", path) - } - } - - if d.HasChange("description") { - description := d.Get("description").(string) - tune := api.MountConfigInput{Description: &description} - err := client.Sys().TuneMountWithContext(ctx, path, tune) - if err != nil { - log.Printf("[ERROR] Error updating github auth description to '%q'", path) - return diag.FromErr(err) - } - } - d.Partial(false) return githubAuthBackendRead(ctx, d, meta) } @@ -182,13 +162,7 @@ func githubAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta int configPath := path + "/config" log.Printf("[DEBUG] Reading github auth mount from '%q'", path) - mount, err := mountutil.GetAuthMount(ctx, client, d.Id()) - if err != nil { - if mountutil.IsMountNotFoundError(err) { - log.Printf("[WARN] Mount %q not found, removing from state.", path) - d.SetId("") - return nil - } + if err := readAuthMount(ctx, d, meta, true); err != nil { return diag.FromErr(err) } @@ -207,19 +181,10 @@ func githubAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta int return nil } - log.Printf("[DEBUG] Reading github auth tune from '%q/tune'", path) - rawTune, err := authMountTuneGet(ctx, client, path) - if err != nil { - return diag.Errorf("error reading tune information from Vault: %s", err) - } - data := getCommonTokenFieldMap(resp) data["path"] = d.Id() data["organization"] = resp.Data["organization"] data["base_url"] = resp.Data["base_url"] - data["description"] = mount.Description - data["accessor"] = mount.Accessor - data["tune"] = []map[string]interface{}{rawTune} if orgID, ok := resp.Data["organization_id"]; ok { data["organization_id"] = orgID diff --git a/vault/resource_jwt_auth_backend.go b/vault/resource_jwt_auth_backend.go index a0a61da3c5..a7afaee067 100644 --- a/vault/resource_jwt_auth_backend.go +++ b/vault/resource_jwt_auth_backend.go @@ -13,16 +13,13 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" - "github.com/hashicorp/vault/api" - "github.com/hashicorp/terraform-provider-vault/internal/consts" "github.com/hashicorp/terraform-provider-vault/internal/provider" "github.com/hashicorp/terraform-provider-vault/util" - "github.com/hashicorp/terraform-provider-vault/util/mountutil" ) func jwtAuthBackendResource() *schema.Resource { - return provider.MustAddMountMigrationSchema(&schema.Resource{ + r := provider.MustAddMountMigrationSchema(&schema.Resource{ Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, @@ -170,6 +167,17 @@ func jwtAuthBackendResource() *schema.Resource { "tune": authMountTuneSchema(), }, }, false) + + // Add common mount schema to the resource + provider.MustAddSchema(r, getAuthMountSchema( + consts.FieldPath, + consts.FieldType, + consts.FieldDescription, + consts.FieldAccessor, + consts.FieldLocal, + )) + + return r } func jwtCustomizeDiff(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error { @@ -220,19 +228,10 @@ func jwtAuthBackendWrite(ctx context.Context, d *schema.ResourceData, meta inter return diag.FromErr(e) } - authType := d.Get("type").(string) path := getJwtPath(d) - options := &api.EnableAuthOptions{ - Type: authType, - Description: d.Get("description").(string), - Local: d.Get("local").(bool), - } - - log.Printf("[DEBUG] Writing auth %s to Vault", authType) - err := client.Sys().EnableAuthWithOptionsWithContext(ctx, path, options) - if err != nil { - return diag.Errorf("error writing to Vault: %s", err) + if err := createAuthMount(ctx, d, meta, client, path, d.Get(consts.FieldType).(string)); err != nil { + return diag.FromErr(err) } d.SetId(path) @@ -245,17 +244,7 @@ func jwtAuthBackendDelete(ctx context.Context, d *schema.ResourceData, meta inte if e != nil { return diag.FromErr(e) } - - path := getJwtPath(d) - - log.Printf("[DEBUG] Deleting auth %s from Vault", path) - - err := client.Sys().DisableAuthWithContext(ctx, path) - if err != nil { - return diag.Errorf("error disabling auth from Vault: %s", err) - } - - return nil + return authMountDisable(ctx, client, d.Id()) } func jwtAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -274,15 +263,8 @@ func jwtAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta interf // use the ID value path = d.Id() } - d.Set("path", path) - mount, err := mountutil.GetAuthMount(ctx, client, path) - if err != nil { - if mountutil.IsMountNotFoundError(err) { - log.Printf("[WARN] Mount %q not found, removing from state.", path) - d.SetId("") - return nil - } + if err := readAuthMount(ctx, d, meta, true); err != nil { return diag.FromErr(err) } @@ -297,10 +279,6 @@ func jwtAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta interf return nil } - d.Set("type", mount.Type) - d.Set("local", mount.Local) - - d.Set("accessor", mount.Accessor) for _, configOption := range matchingJwtMountConfigOptions { // The oidc_client_secret is sensitive so it will not be in the response // Our options are to always assume it must be updated or always assume it @@ -314,17 +292,9 @@ func jwtAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta interf if configOption == "oidc_client_secret" { continue } - d.Set(configOption, config.Data[configOption]) - } - - log.Printf("[DEBUG] Reading jwt auth tune from %q", path+"/tune") - rawTune, err := authMountTuneGet(ctx, client, "auth/"+path) - if err != nil { - return diag.Errorf("error reading tune information from Vault: %s", err) - } - if err := d.Set("tune", []map[string]interface{}{rawTune}); err != nil { - log.Printf("[ERROR] Error when setting tune config from path %q to state: %s", path+"/tune", err) - return diag.FromErr(err) + if err := d.Set(configOption, config.Data[configOption]); err != nil { + return diag.FromErr(err) + } } return nil @@ -368,6 +338,11 @@ func jwtAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta inte if e != nil { return diag.FromErr(e) } + + // tune auth mount if needed + if err := updateAuthMount(ctx, d, meta, true); err != nil { + return diag.FromErr(err) + } } configuration := map[string]interface{}{} @@ -391,21 +366,6 @@ func jwtAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta inte return diag.Errorf("error updating configuration to Vault for path %s: %s", path, err) } - if d.HasChange("tune") { - log.Printf("[INFO] JWT/OIDC Auth '%q' tune configuration changed", d.Id()) - if raw, ok := d.GetOk("tune"); ok { - backendType := d.Get("type") - log.Printf("[DEBUG] Writing %s auth tune to '%q'", backendType, path) - - err := authMountTune(ctx, client, "auth/"+path, raw) - if err != nil { - return nil - } - - log.Printf("[INFO] Written %s auth tune to %q", backendType, path) - } - } - return jwtAuthBackendRead(ctx, d, meta) } diff --git a/vault/resource_ldap_auth_backend.go b/vault/resource_ldap_auth_backend.go index 497e07d5fc..4960032a1b 100644 --- a/vault/resource_ldap_auth_backend.go +++ b/vault/resource_ldap_auth_backend.go @@ -11,12 +11,9 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/vault/api" - "github.com/hashicorp/terraform-provider-vault/internal/consts" "github.com/hashicorp/terraform-provider-vault/internal/provider" "github.com/hashicorp/terraform-provider-vault/util" - "github.com/hashicorp/terraform-provider-vault/util/mountutil" ) const ldapAuthType string = "ldap" @@ -197,7 +194,7 @@ func ldapAuthBackendResource() *schema.Resource { addTokenFields(fields, &addTokenFieldsConfig{}) - return provider.MustAddMountMigrationSchema(&schema.Resource{ + r := provider.MustAddMountMigrationSchema(&schema.Resource{ SchemaVersion: 2, // Handle custom state upgrade case since schema version was already 1 StateUpgraders: []schema.StateUpgrader{ @@ -217,6 +214,18 @@ func ldapAuthBackendResource() *schema.Resource { CustomizeDiff: getMountCustomizeDiffFunc(consts.FieldPath), Schema: fields, }, true) + + // Add common mount schema to the resource + provider.MustAddSchema(r, getAuthMountSchema( + consts.FieldPath, + consts.FieldType, + consts.FieldDescription, + consts.FieldAccessor, + consts.FieldLocal, + consts.FieldTokenType, + )) + + return r } func ldapAuthBackendConfigPath(path string) string { @@ -230,16 +239,9 @@ func ldapAuthBackendWrite(ctx context.Context, d *schema.ResourceData, meta inte } path := d.Get("path").(string) - options := &api.EnableAuthOptions{ - Type: ldapAuthType, - Description: d.Get("description").(string), - Local: d.Get("local").(bool), - } - log.Printf("[DEBUG] Enabling LDAP auth backend %q", path) - err := client.Sys().EnableAuthWithOptions(path, options) - if err != nil { - return diag.Errorf("error enabling ldap auth backend %q: %s", path, err) + if err := createAuthMount(ctx, d, meta, client, path, ldapAuthType); err != nil { + return diag.FromErr(err) } log.Printf("[DEBUG] Enabled LDAP auth backend %q", path) @@ -263,6 +265,11 @@ func ldapAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta int } path = ldapAuthBackendConfigPath(newMount) + + // tune auth mount if needed + if err := updateAuthMount(ctx, d, meta, true); err != nil { + return diag.FromErr(err) + } } data := map[string]interface{}{} @@ -318,21 +325,10 @@ func ldapAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta inter path := d.Id() - mount, err := mountutil.GetAuthMount(ctx, client, path) - if err != nil { - if mountutil.IsMountNotFoundError(err) { - log.Printf("[WARN] Mount %q not found, removing from state.", path) - d.SetId("") - return nil - } + if err := readAuthMount(ctx, d, meta, true); err != nil { return diag.FromErr(err) } - d.Set(consts.FieldPath, path) - d.Set(consts.FieldDescription, mount.Description) - d.Set(consts.FieldAccessor, mount.Accessor) - d.Set(consts.FieldLocal, mount.Local) - path = ldapAuthBackendConfigPath(path) log.Printf("[DEBUG] Reading LDAP auth backend config %q", path) @@ -384,19 +380,10 @@ func ldapAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta inter return diags } -func ldapAuthBackendDelete(_ context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { +func ldapAuthBackendDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { client, e := provider.GetClient(d, meta) if e != nil { return diag.FromErr(e) } - path := d.Id() - - log.Printf("[DEBUG] Deleting LDAP auth backend %q", path) - err := client.Sys().DisableAuth(path) - if err != nil { - return diag.Errorf("error deleting ldap auth backend %q: %q", path, err) - } - log.Printf("[DEBUG] Deleted LDAP auth backend %q", path) - - return nil + return authMountDisable(ctx, client, d.Id()) } diff --git a/vault/resource_okta_auth_backend.go b/vault/resource_okta_auth_backend.go index 697f5e78ae..8c8f35d951 100644 --- a/vault/resource_okta_auth_backend.go +++ b/vault/resource_okta_auth_backend.go @@ -20,7 +20,6 @@ import ( "github.com/hashicorp/terraform-provider-vault/internal/consts" "github.com/hashicorp/terraform-provider-vault/internal/provider" "github.com/hashicorp/terraform-provider-vault/util" - "github.com/hashicorp/terraform-provider-vault/util/mountutil" ) var oktaAuthType = "okta" @@ -221,7 +220,7 @@ func oktaAuthBackendResource() *schema.Resource { addTokenFields(fields, &addTokenFieldsConfig{}) - return provider.MustAddMountMigrationSchema(&schema.Resource{ + r := provider.MustAddMountMigrationSchema(&schema.Resource{ CreateContext: oktaAuthBackendWrite, DeleteContext: oktaAuthBackendDelete, ReadContext: provider.ReadContextWrapper(oktaAuthBackendRead), @@ -232,6 +231,17 @@ func oktaAuthBackendResource() *schema.Resource { CustomizeDiff: getMountCustomizeDiffFunc(consts.FieldPath), Schema: fields, }, false) + + // Add common mount schema to the resource + provider.MustAddSchema(r, getAuthMountSchema( + consts.FieldPath, + consts.FieldType, + consts.FieldDescription, + consts.FieldAccessor, + consts.FieldTokenType, + )) + + return r } func normalizeOktaTTL(i interface{}) string { @@ -269,18 +279,14 @@ func oktaAuthBackendWrite(ctx context.Context, d *schema.ResourceData, meta inte } authType := oktaAuthType - desc := d.Get(consts.FieldDescription).(string) path := d.Get(consts.FieldPath).(string) log.Printf("[DEBUG] Writing auth %s to Vault", authType) - err := client.Sys().EnableAuthWithOptions(path, &api.EnableAuthOptions{ - Type: authType, - Description: desc, - }) - if err != nil { - return diag.Errorf("error writing to Vault: %s", err) + if err := createAuthMount(ctx, d, meta, client, path, oktaAuthType); err != nil { + return diag.FromErr(err) } + log.Printf("[INFO] Enabled okta auth backend at '%s'", path) d.SetId(path) @@ -292,17 +298,7 @@ func oktaAuthBackendDelete(ctx context.Context, d *schema.ResourceData, meta int if e != nil { return diag.FromErr(e) } - - path := d.Id() - - log.Printf("[DEBUG] Deleting auth %s from Vault", path) - - err := client.Sys().DisableAuthWithContext(ctx, path) - if err != nil { - return diag.Errorf("error disabling auth from Vault: %s", err) - } - - return nil + return authMountDisable(ctx, client, d.Id()) } func oktaAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -314,24 +310,7 @@ func oktaAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta inter path := d.Id() log.Printf("[DEBUG] Reading auth %s from Vault", path) - mount, err := mountutil.GetAuthMount(ctx, client, path) - if err != nil { - if mountutil.IsMountNotFoundError(err) { - log.Printf("[WARN] Mount %q not found, removing from state.", path) - d.SetId("") - return nil - } - return diag.FromErr(err) - } - - if err := d.Set(consts.FieldPath, path); err != nil { - return diag.FromErr(err) - } - - if err := d.Set(consts.FieldAccessor, mount.Accessor); err != nil { - return diag.FromErr(err) - } - if err := d.Set(consts.FieldDescription, mount.Description); err != nil { + if err := readAuthMount(ctx, d, meta, true); err != nil { return diag.FromErr(err) } @@ -398,6 +377,11 @@ func oktaAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta int if e != nil { return diag.FromErr(e) } + + // tune auth mount if needed + if err := updateAuthMount(ctx, d, meta, true); err != nil { + return diag.FromErr(err) + } } log.Printf("[DEBUG] Updating auth %s in Vault", path) diff --git a/vault/resource_saml_auth_backend.go b/vault/resource_saml_auth_backend.go index 4cf9b962d1..4aa7314d48 100644 --- a/vault/resource_saml_auth_backend.go +++ b/vault/resource_saml_auth_backend.go @@ -10,8 +10,6 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/vault/api" - "github.com/hashicorp/terraform-provider-vault/internal/consts" "github.com/hashicorp/terraform-provider-vault/internal/provider" "github.com/hashicorp/terraform-provider-vault/util" @@ -45,7 +43,7 @@ var ( ) func samlAuthBackendResource() *schema.Resource { - return provider.MustAddMountMigrationSchema(&schema.Resource{ + r := provider.MustAddMountMigrationSchema(&schema.Resource{ CreateContext: provider.MountCreateContextWrapper(samlAuthBackendWrite, provider.VaultVersion115), ReadContext: provider.ReadContextWrapper(samlAuthBackendRead), UpdateContext: samlAuthBackendUpdate, @@ -119,6 +117,14 @@ func samlAuthBackendResource() *schema.Resource { }, }, }, true) + + // Add common mount schema to the resource + provider.MustAddSchema(r, getAuthMountSchema( + consts.FieldPath, + consts.FieldType, + )) + + return r } func samlAuthBackendWrite(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { @@ -130,12 +136,10 @@ func samlAuthBackendWrite(ctx context.Context, d *schema.ResourceData, meta inte path := d.Get(consts.FieldPath).(string) log.Printf("[DEBUG] Enabling SAML auth backend %q", path) - err := client.Sys().EnableAuthWithOptions(path, &api.EnableAuthOptions{ - Type: consts.MountTypeSAML, - }) - if err != nil { - return diag.Errorf("error enabling SAML auth backend %q: %s", path, err) + if err := createAuthMount(ctx, d, meta, client, path, consts.MountTypeSAML); err != nil { + return diag.FromErr(err) } + log.Printf("[DEBUG] Enabled SAML auth backend %q", path) // set ID to where engine is mounted @@ -159,6 +163,11 @@ func samlAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta int } path = newMount + + // tune auth mount if needed + if err := updateAuthMount(ctx, d, meta, true); err != nil { + return diag.FromErr(err) + } } configPath := samlAuthBackendConfigPath(path) @@ -207,7 +216,7 @@ func samlAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta inter return nil } - if err := d.Set(consts.FieldPath, id); err != nil { + if err := readAuthMount(ctx, d, meta, true); err != nil { return diag.FromErr(err) } @@ -229,17 +238,7 @@ func samlAuthBackendDelete(ctx context.Context, d *schema.ResourceData, meta int if e != nil { return diag.FromErr(e) } - - path := d.Id() - - log.Printf("[DEBUG] Deleting SAML auth backend %q", path) - err := client.Sys().DisableAuth(path) - if err != nil { - return diag.Errorf("error deleting SAML auth backend %q: %q", path, err) - } - log.Printf("[DEBUG] Deleted SAML auth backend %q", path) - - return nil + return authMountDisable(ctx, client, d.Id()) } func samlAuthBackendConfigPath(path string) string { From 3c5228ecc4d3a2d7df922543be3c215c93811320 Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Mon, 7 Oct 2024 11:54:06 -0700 Subject: [PATCH 2/4] refactor --- vault/auth_mount.go | 65 ++++++++++------- vault/resource_ldap_auth_backend.go | 12 ++- vault/resource_ldap_auth_backend_test.go | 93 ++++++++++++++++++++++++ 3 files changed, 140 insertions(+), 30 deletions(-) diff --git a/vault/auth_mount.go b/vault/auth_mount.go index 2bd5f94a13..b84e9f9389 100644 --- a/vault/auth_mount.go +++ b/vault/auth_mount.go @@ -13,7 +13,6 @@ import ( "github.com/hashicorp/terraform-provider-vault/internal/provider" "github.com/hashicorp/terraform-provider-vault/util/mountutil" "github.com/hashicorp/vault/api" - "github.com/mitchellh/mapstructure" "log" ) @@ -87,12 +86,20 @@ func authMountTuneSchema() *schema.Schema { } } +type createMountRequestParams struct { + path string + mountType string + + // some auth engines manage the token type separately + skipTokenType bool +} + func getAuthMountSchema(excludes ...string) schemaMap { s := schemaMap{ consts.FieldTokenType: { - Type: schema.TypeString, - Optional: true, - Computed: true, + Type: schema.TypeString, + Optional: true, + //Computed: true, Description: "Specifies the type of tokens that should be returned by the mount.", ValidateFunc: validation.StringInSlice([]string{"default-service", "default-batch", "service", "batch"}, false), }, @@ -119,9 +126,9 @@ func getAuthMountSchema(excludes ...string) schemaMap { return s } -func createAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{}, client *api.Client, path string, mountType string) error { +func createAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{}, client *api.Client, params *createMountRequestParams) error { options := &api.EnableAuthOptions{ - Type: mountType, + Type: params.mountType, Description: d.Get(consts.FieldDescription).(string), Local: d.Get(consts.FieldLocal).(bool), SealWrap: d.Get(consts.FieldSealWrap).(bool), @@ -154,17 +161,8 @@ func createAuthMount(ctx context.Context, d *schema.ResourceData, meta interface options.Config.PluginVersion = v.(string) } - if d.HasChange(consts.FieldTokenType) { - options.Config.TokenType = d.Get(consts.FieldTokenType).(string) - } - - if d.HasChange(consts.FieldUserLockoutConfig) { - userLockoutCfg, err := getUserLockoutConfig(d.Get(consts.FieldUserLockoutConfig).(map[string]string)) - if err != nil { - return fmt.Errorf("error reading '%s': %s", consts.FieldUserLockoutConfig, err) - } - - options.Config.UserLockoutConfig = userLockoutCfg + if v, ok := d.GetOk(consts.FieldTokenType); ok { + options.Config.TokenType = v.(string) } useAPIVer116Ent := provider.IsAPISupported(meta, provider.VaultVersion116) && provider.IsEnterpriseSupported(meta) @@ -174,9 +172,9 @@ func createAuthMount(ctx context.Context, d *schema.ResourceData, meta interface } } - log.Printf("[DEBUG] Creating auth mount %s in Vault", path) + log.Printf("[DEBUG] Creating auth mount %s in Vault", params.path) - err := client.Sys().EnableAuthWithOptionsWithContext(ctx, path, options) + err := client.Sys().EnableAuthWithOptionsWithContext(ctx, params.path, options) if err != nil { return fmt.Errorf("error writing to Vault: %s", err) } @@ -232,7 +230,7 @@ func updateAuthMount(ctx context.Context, d *schema.ResourceData, meta interface } if d.HasChange(consts.FieldUserLockoutConfig) { - userLockoutCfg, err := getUserLockoutConfig(d.Get(consts.FieldUserLockoutConfig).(map[string]string)) + userLockoutCfg, err := getUserLockoutConfig(d.Get(consts.FieldUserLockoutConfig).(map[string]interface{})) if err != nil { return fmt.Errorf("error reading '%s': %s", consts.FieldUserLockoutConfig, err) } @@ -328,17 +326,32 @@ func readAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{} return err } - if err := d.Set(consts.FieldUserLockoutConfig, flattenUserLockoutConfig(mount.Config.UserLockoutConfig)); err != nil { - return err - } + // TODO uncomment after fixing bug in vault/api package — user_lockout_config can not be read + // drifts currently can not be managed + //if err := d.Set(consts.FieldUserLockoutConfig, flattenUserLockoutConfig(mount.Config.UserLockoutConfig)); err != nil { + // return err + //} return nil } -func getUserLockoutConfig(m map[string]string) (*api.UserLockoutConfigInput, error) { +func getUserLockoutConfig(m map[string]interface{}) (*api.UserLockoutConfigInput, error) { result := &api.UserLockoutConfigInput{} - if err := mapstructure.Decode(m, result); err != nil { - return nil, fmt.Errorf("invalid format for user_lockout_config: %s", err) + + if v, ok := m[fieldLockoutDuration]; ok && v != nil { + result.LockoutDuration = v.(string) + } + + if v, ok := m[fieldLockoutCounterResetDuration]; ok && v != nil { + result.LockoutCounterResetDuration = v.(string) + } + + if v, ok := m[fieldLockoutThreshold]; ok && v != nil { + result.LockoutThreshold = v.(string) + } + + if v, ok := m[fieldLockoutDisable]; ok && v != nil { + result.DisableLockout = v.(*bool) } return result, nil diff --git a/vault/resource_ldap_auth_backend.go b/vault/resource_ldap_auth_backend.go index 4960032a1b..7ac6704995 100644 --- a/vault/resource_ldap_auth_backend.go +++ b/vault/resource_ldap_auth_backend.go @@ -266,10 +266,14 @@ func ldapAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta int path = ldapAuthBackendConfigPath(newMount) - // tune auth mount if needed - if err := updateAuthMount(ctx, d, meta, true); err != nil { - return diag.FromErr(err) - } + } + + // for LDAP, user_lockout_config can only be configured on tune calls + // we always check if we need to tune the mount, even if it's a new resource + + // tune auth mount if needed + if err := updateAuthMount(ctx, d, meta, true); err != nil { + return diag.FromErr(err) } data := map[string]interface{}{} diff --git a/vault/resource_ldap_auth_backend_test.go b/vault/resource_ldap_auth_backend_test.go index 4687deab2b..a94e59d0fd 100644 --- a/vault/resource_ldap_auth_backend_test.go +++ b/vault/resource_ldap_auth_backend_test.go @@ -117,6 +117,99 @@ func TestLDAPAuthBackend_remount(t *testing.T) { }) } +func TestLDAPAuthBackend_authMountSchema(t *testing.T) { + t.Parallel() + path := acctest.RandomWithPrefix("tf-test-auth-ldap") + + resourceName := "vault_ldap_auth_backend.test" + + resource.Test(t, resource.TestCase{ + ProviderFactories: providerFactories, + PreCheck: func() { testutil.TestAccPreCheck(t) }, + Steps: []resource.TestStep{ + { + Config: testAccLDAPAuthBackendConfig_authMountSchema(path, false), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "path", path), + resource.TestCheckResourceAttr(resourceName, "description", "test desc"), + resource.TestCheckResourceAttr(resourceName, "url", "ldaps://example.org"), + resource.TestCheckResourceAttr(resourceName, "default_lease_ttl_seconds", "3600"), + resource.TestCheckResourceAttr(resourceName, "max_lease_ttl_seconds", "36000"), + resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.#", "2"), + resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.0", "header1"), + resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.1", "header2"), + resource.TestCheckResourceAttr(resourceName, "user_lockout_config.lockout_threshold", "20"), + resource.TestCheckResourceAttr(resourceName, "user_lockout_config.lockout_duration", "5m"), + resource.TestCheckResourceAttr(resourceName, "user_lockout_config.lockout_counter_reset_duration", "5m"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.#", "2"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.0", "header1"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.1", "header2"), + resource.TestCheckResourceAttr(resourceName, "listing_visibility", "hidden"), + ), + }, + //{ + // Config: testAccJWTAuthBackendConfig_authMountSchema(path, true), + // Check: resource.ComposeTestCheckFunc( + // resource.TestCheckResourceAttr(resourceName, "path", path), + // resource.TestCheckResourceAttr(resourceName, "description", "ldap backend"), + // resource.TestCheckResourceAttr(resourceName, "oidc_discovery_url", "https://myco.auth0.com/"), + // resource.TestCheckResourceAttr(resourceName, "default_lease_ttl_seconds", "7200"), + // resource.TestCheckResourceAttr(resourceName, "max_lease_ttl_seconds", "48000"), + // resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.#", "2"), + // resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.0", "header1"), + // resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.1", "header2"), + // resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.#", "3"), + // resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.0", "header1"), + // resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.1", "header2"), + // resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.1", "header2"), + // resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.2", "header3"), + // resource.TestCheckResourceAttr(resourceName, "listing_visibility", "unauth"), + // ), + //}, + //testutil.GetImportTestStep(resourceName, false, nil, "description", "disable_remount"), + }, + }) +} + +func testAccLDAPAuthBackendConfig_authMountSchema(path string, isUpdate bool) string { + if !isUpdate { + + return fmt.Sprintf(` +resource "vault_ldap_auth_backend" "test" { + path = "%s" + description = "test desc" + url = "ldaps://example.org" + default_lease_ttl_seconds = 3600 + max_lease_ttl_seconds = 36000 + passthrough_request_headers = ["header1", "header2"] + allowed_response_headers = ["header1", "header2"] + listing_visibility = "hidden" + user_lockout_config = { + lockout_threshold = "20", + lockout_duration = "5m", + lockout_counter_reset_duration = "5m" + } +}`, path) + } else { + return fmt.Sprintf(` +resource "vault_ldap_auth_backend" "test" { + path = "%s" + description = "test desc updated" + url = "ldaps://example.org" + default_lease_ttl_seconds = 7200 + max_lease_ttl_seconds = 48000 + passthrough_request_headers = ["header1", "header2"] + allowed_response_headers = ["header1", "header2", "header3"] + listing_visibility = "unauth" + user_lockout_config = { + lockout_threshold = "30", + lockout_duration = "10m", + lockout_counter_reset_duration = "10m" + } +}`, path) + } +} + func testLDAPAuthBackendDestroy(s *terraform.State) error { for _, rs := range s.RootModule().Resources { if rs.Type != "vault_ldap_auth_backend" { From e98b72d87484a47e1e93b38a6ceac32bc476e58d Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Mon, 7 Oct 2024 12:15:00 -0700 Subject: [PATCH 3/4] add mount fields and tests --- vault/auth_mount.go | 36 +++++++++------- vault/resource_auth_backend.go | 10 +++-- vault/resource_gcp_auth_backend.go | 10 +++-- vault/resource_github_auth_backend.go | 10 +++-- vault/resource_jwt_auth_backend.go | 10 +++-- vault/resource_ldap_auth_backend.go | 10 +++-- vault/resource_ldap_auth_backend_test.go | 54 +++++++++++++++--------- vault/resource_okta_auth_backend.go | 10 +++-- vault/resource_saml_auth_backend.go | 10 +++-- 9 files changed, 104 insertions(+), 56 deletions(-) diff --git a/vault/auth_mount.go b/vault/auth_mount.go index b84e9f9389..adae5be984 100644 --- a/vault/auth_mount.go +++ b/vault/auth_mount.go @@ -87,11 +87,11 @@ func authMountTuneSchema() *schema.Schema { } type createMountRequestParams struct { - path string - mountType string + Path string + MountType string // some auth engines manage the token type separately - skipTokenType bool + SkipTokenType bool } func getAuthMountSchema(excludes ...string) schemaMap { @@ -128,7 +128,7 @@ func getAuthMountSchema(excludes ...string) schemaMap { func createAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{}, client *api.Client, params *createMountRequestParams) error { options := &api.EnableAuthOptions{ - Type: params.mountType, + Type: params.MountType, Description: d.Get(consts.FieldDescription).(string), Local: d.Get(consts.FieldLocal).(bool), SealWrap: d.Get(consts.FieldSealWrap).(bool), @@ -161,8 +161,10 @@ func createAuthMount(ctx context.Context, d *schema.ResourceData, meta interface options.Config.PluginVersion = v.(string) } - if v, ok := d.GetOk(consts.FieldTokenType); ok { - options.Config.TokenType = v.(string) + if !params.SkipTokenType { + if v, ok := d.GetOk(consts.FieldTokenType); ok { + options.Config.TokenType = v.(string) + } } useAPIVer116Ent := provider.IsAPISupported(meta, provider.VaultVersion116) && provider.IsEnterpriseSupported(meta) @@ -172,9 +174,9 @@ func createAuthMount(ctx context.Context, d *schema.ResourceData, meta interface } } - log.Printf("[DEBUG] Creating auth mount %s in Vault", params.path) + log.Printf("[DEBUG] Creating auth mount %s in Vault", params.Path) - err := client.Sys().EnableAuthWithOptionsWithContext(ctx, params.path, options) + err := client.Sys().EnableAuthWithOptionsWithContext(ctx, params.Path, options) if err != nil { return fmt.Errorf("error writing to Vault: %s", err) } @@ -182,7 +184,7 @@ func createAuthMount(ctx context.Context, d *schema.ResourceData, meta interface return nil } -func updateAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{}, excludeType bool) error { +func updateAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{}, excludeType bool, skipTokenType bool) error { client, err := provider.GetClient(d, meta) if err != nil { return err @@ -225,8 +227,10 @@ func updateAuthMount(ctx context.Context, d *schema.ResourceData, meta interface config.PluginVersion = d.Get(consts.FieldPluginVersion).(string) } - if d.HasChange(consts.FieldTokenType) { - config.TokenType = d.Get(consts.FieldTokenType).(string) + if !skipTokenType { + if d.HasChange(consts.FieldTokenType) { + config.TokenType = d.Get(consts.FieldTokenType).(string) + } } if d.HasChange(consts.FieldUserLockoutConfig) { @@ -251,10 +255,10 @@ func updateAuthMount(ctx context.Context, d *schema.ResourceData, meta interface return fmt.Errorf("error updating Vault: %s", err) } - return readAuthMount(ctx, d, meta, excludeType) + return readAuthMount(ctx, d, meta, excludeType, skipTokenType) } -func readAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{}, excludeType bool) error { +func readAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{}, excludeType bool, skipTokenType bool) error { client, e := provider.GetClient(d, meta) if e != nil { return e @@ -322,8 +326,10 @@ func readAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{} return err } - if err := d.Set(consts.FieldTokenType, mount.Config.TokenType); err != nil { - return err + if !skipTokenType { + if err := d.Set(consts.FieldTokenType, mount.Config.TokenType); err != nil { + return err + } } // TODO uncomment after fixing bug in vault/api package — user_lockout_config can not be read diff --git a/vault/resource_auth_backend.go b/vault/resource_auth_backend.go index 3b95caf2bd..d6fdac220a 100644 --- a/vault/resource_auth_backend.go +++ b/vault/resource_auth_backend.go @@ -103,7 +103,11 @@ func authBackendWrite(ctx context.Context, d *schema.ResourceData, meta interfac } log.Printf("[DEBUG] Writing auth %q to Vault", path) - if err := createAuthMount(ctx, d, meta, client, path, mountType); err != nil { + if err := createAuthMount(ctx, d, meta, client, &createMountRequestParams{ + Path: path, + MountType: mountType, + SkipTokenType: false, + }); err != nil { return diag.FromErr(err) } d.SetId(path) @@ -120,7 +124,7 @@ func authBackendDelete(ctx context.Context, d *schema.ResourceData, meta interfa } func authBackendRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { - if err := readAuthMount(ctx, d, meta, true); err != nil { + if err := readAuthMount(ctx, d, meta, true, false); err != nil { return diag.FromErr(err) } return nil @@ -142,7 +146,7 @@ func authBackendUpdate(ctx context.Context, d *schema.ResourceData, meta interfa } // tune auth mount if needed - if err := updateAuthMount(ctx, d, meta, true); err != nil { + if err := updateAuthMount(ctx, d, meta, true, false); err != nil { return diag.FromErr(err) } } diff --git a/vault/resource_gcp_auth_backend.go b/vault/resource_gcp_auth_backend.go index 7acb767706..153f42b70f 100644 --- a/vault/resource_gcp_auth_backend.go +++ b/vault/resource_gcp_auth_backend.go @@ -207,7 +207,11 @@ func gcpAuthBackendWrite(ctx context.Context, d *schema.ResourceData, meta inter path := d.Get(consts.FieldPath).(string) log.Printf("[DEBUG] Enabling gcp auth backend %q", path) - if err := createAuthMount(ctx, d, meta, client, path, gcpAuthType); err != nil { + if err := createAuthMount(ctx, d, meta, client, &createMountRequestParams{ + Path: path, + MountType: gcpAuthType, + SkipTokenType: false, + }); err != nil { return diag.FromErr(err) } log.Printf("[DEBUG] Enabled gcp auth backend %q", path) @@ -235,7 +239,7 @@ func gcpAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta inte path = gcpAuthBackendConfigPath(newMount) // tune auth mount if needed - if err := updateAuthMount(ctx, d, meta, true); err != nil { + if err := updateAuthMount(ctx, d, meta, true, false); err != nil { return diag.FromErr(err) } } @@ -340,7 +344,7 @@ func gcpAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta interf } } - if err := readAuthMount(ctx, d, meta, true); err != nil { + if err := readAuthMount(ctx, d, meta, true, false); err != nil { return diag.FromErr(err) } diff --git a/vault/resource_github_auth_backend.go b/vault/resource_github_auth_backend.go index cf1db67e1f..8dfe9be6eb 100644 --- a/vault/resource_github_auth_backend.go +++ b/vault/resource_github_auth_backend.go @@ -92,7 +92,11 @@ func githubAuthBackendCreate(ctx context.Context, d *schema.ResourceData, meta i path := strings.Trim(d.Get(consts.FieldPath).(string), "/") log.Printf("[DEBUG] Enabling github auth backend at '%s'", path) - if err := createAuthMount(ctx, d, meta, client, path, consts.MountTypeGitHub); err != nil { + if err := createAuthMount(ctx, d, meta, client, &createMountRequestParams{ + Path: path, + MountType: consts.MountTypeGitHub, + SkipTokenType: true, + }); err != nil { return diag.FromErr(err) } log.Printf("[INFO] Enabled github auth backend at '%s'", path) @@ -121,7 +125,7 @@ func githubAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta i configPath = path + "/config" // tune auth mount if needed - if err := updateAuthMount(ctx, d, meta, true); err != nil { + if err := updateAuthMount(ctx, d, meta, true, true); err != nil { return diag.FromErr(err) } } @@ -162,7 +166,7 @@ func githubAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta int configPath := path + "/config" log.Printf("[DEBUG] Reading github auth mount from '%q'", path) - if err := readAuthMount(ctx, d, meta, true); err != nil { + if err := readAuthMount(ctx, d, meta, true, true); err != nil { return diag.FromErr(err) } diff --git a/vault/resource_jwt_auth_backend.go b/vault/resource_jwt_auth_backend.go index a7afaee067..2d67cae285 100644 --- a/vault/resource_jwt_auth_backend.go +++ b/vault/resource_jwt_auth_backend.go @@ -230,7 +230,11 @@ func jwtAuthBackendWrite(ctx context.Context, d *schema.ResourceData, meta inter path := getJwtPath(d) - if err := createAuthMount(ctx, d, meta, client, path, d.Get(consts.FieldType).(string)); err != nil { + if err := createAuthMount(ctx, d, meta, client, &createMountRequestParams{ + Path: path, + MountType: d.Get(consts.FieldType).(string), + SkipTokenType: false, + }); err != nil { return diag.FromErr(err) } @@ -264,7 +268,7 @@ func jwtAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta interf path = d.Id() } - if err := readAuthMount(ctx, d, meta, true); err != nil { + if err := readAuthMount(ctx, d, meta, true, false); err != nil { return diag.FromErr(err) } @@ -340,7 +344,7 @@ func jwtAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta inte } // tune auth mount if needed - if err := updateAuthMount(ctx, d, meta, true); err != nil { + if err := updateAuthMount(ctx, d, meta, true, false); err != nil { return diag.FromErr(err) } } diff --git a/vault/resource_ldap_auth_backend.go b/vault/resource_ldap_auth_backend.go index 7ac6704995..c781ca57ee 100644 --- a/vault/resource_ldap_auth_backend.go +++ b/vault/resource_ldap_auth_backend.go @@ -240,7 +240,11 @@ func ldapAuthBackendWrite(ctx context.Context, d *schema.ResourceData, meta inte path := d.Get("path").(string) log.Printf("[DEBUG] Enabling LDAP auth backend %q", path) - if err := createAuthMount(ctx, d, meta, client, path, ldapAuthType); err != nil { + if err := createAuthMount(ctx, d, meta, client, &createMountRequestParams{ + Path: path, + MountType: ldapAuthType, + SkipTokenType: true, + }); err != nil { return diag.FromErr(err) } log.Printf("[DEBUG] Enabled LDAP auth backend %q", path) @@ -272,7 +276,7 @@ func ldapAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta int // we always check if we need to tune the mount, even if it's a new resource // tune auth mount if needed - if err := updateAuthMount(ctx, d, meta, true); err != nil { + if err := updateAuthMount(ctx, d, meta, true, true); err != nil { return diag.FromErr(err) } @@ -329,7 +333,7 @@ func ldapAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta inter path := d.Id() - if err := readAuthMount(ctx, d, meta, true); err != nil { + if err := readAuthMount(ctx, d, meta, true, true); err != nil { return diag.FromErr(err) } diff --git a/vault/resource_ldap_auth_backend_test.go b/vault/resource_ldap_auth_backend_test.go index a94e59d0fd..d7f114ddfe 100644 --- a/vault/resource_ldap_auth_backend_test.go +++ b/vault/resource_ldap_auth_backend_test.go @@ -5,6 +5,7 @@ package vault import ( "fmt" + "github.com/hashicorp/terraform-provider-vault/internal/consts" "strings" "testing" @@ -135,6 +136,7 @@ func TestLDAPAuthBackend_authMountSchema(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "url", "ldaps://example.org"), resource.TestCheckResourceAttr(resourceName, "default_lease_ttl_seconds", "3600"), resource.TestCheckResourceAttr(resourceName, "max_lease_ttl_seconds", "36000"), + resource.TestCheckResourceAttr(resourceName, "token_type", "default"), resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.#", "2"), resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.0", "header1"), resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.1", "header2"), @@ -147,26 +149,37 @@ func TestLDAPAuthBackend_authMountSchema(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "listing_visibility", "hidden"), ), }, - //{ - // Config: testAccJWTAuthBackendConfig_authMountSchema(path, true), - // Check: resource.ComposeTestCheckFunc( - // resource.TestCheckResourceAttr(resourceName, "path", path), - // resource.TestCheckResourceAttr(resourceName, "description", "ldap backend"), - // resource.TestCheckResourceAttr(resourceName, "oidc_discovery_url", "https://myco.auth0.com/"), - // resource.TestCheckResourceAttr(resourceName, "default_lease_ttl_seconds", "7200"), - // resource.TestCheckResourceAttr(resourceName, "max_lease_ttl_seconds", "48000"), - // resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.#", "2"), - // resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.0", "header1"), - // resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.1", "header2"), - // resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.#", "3"), - // resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.0", "header1"), - // resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.1", "header2"), - // resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.1", "header2"), - // resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.2", "header3"), - // resource.TestCheckResourceAttr(resourceName, "listing_visibility", "unauth"), - // ), - //}, - //testutil.GetImportTestStep(resourceName, false, nil, "description", "disable_remount"), + { + Config: testAccLDAPAuthBackendConfig_authMountSchema(path, true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "path", path), + resource.TestCheckResourceAttr(resourceName, "description", "test desc updated"), + resource.TestCheckResourceAttr(resourceName, "url", "ldaps://example.org"), + resource.TestCheckResourceAttr(resourceName, "default_lease_ttl_seconds", "7200"), + resource.TestCheckResourceAttr(resourceName, "max_lease_ttl_seconds", "48000"), + resource.TestCheckResourceAttr(resourceName, "token_type", "batch"), + resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.#", "2"), + resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.0", "header1"), + resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.1", "header2"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.#", "3"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.0", "header1"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.1", "header2"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.1", "header2"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.2", "header3"), + resource.TestCheckResourceAttr(resourceName, "user_lockout_config.lockout_threshold", "30"), + resource.TestCheckResourceAttr(resourceName, "user_lockout_config.lockout_duration", "10m"), + resource.TestCheckResourceAttr(resourceName, "user_lockout_config.lockout_counter_reset_duration", "10m"), + resource.TestCheckResourceAttr(resourceName, "listing_visibility", "unauth"), + ), + }, + // TODO + testutil.GetImportTestStep(resourceName, false, nil, + consts.FieldDisableRemount, + "user_lockout_config.%", + "user_lockout_config.lockout_counter_reset_duration", + "user_lockout_config.lockout_duration", + "user_lockout_config.lockout_threshold", + ), }, }) } @@ -201,6 +214,7 @@ resource "vault_ldap_auth_backend" "test" { passthrough_request_headers = ["header1", "header2"] allowed_response_headers = ["header1", "header2", "header3"] listing_visibility = "unauth" + token_type = "batch" user_lockout_config = { lockout_threshold = "30", lockout_duration = "10m", diff --git a/vault/resource_okta_auth_backend.go b/vault/resource_okta_auth_backend.go index 8c8f35d951..44046c943b 100644 --- a/vault/resource_okta_auth_backend.go +++ b/vault/resource_okta_auth_backend.go @@ -283,7 +283,11 @@ func oktaAuthBackendWrite(ctx context.Context, d *schema.ResourceData, meta inte log.Printf("[DEBUG] Writing auth %s to Vault", authType) - if err := createAuthMount(ctx, d, meta, client, path, oktaAuthType); err != nil { + if err := createAuthMount(ctx, d, meta, client, &createMountRequestParams{ + Path: path, + MountType: oktaAuthType, + SkipTokenType: false, + }); err != nil { return diag.FromErr(err) } @@ -310,7 +314,7 @@ func oktaAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta inter path := d.Id() log.Printf("[DEBUG] Reading auth %s from Vault", path) - if err := readAuthMount(ctx, d, meta, true); err != nil { + if err := readAuthMount(ctx, d, meta, true, false); err != nil { return diag.FromErr(err) } @@ -379,7 +383,7 @@ func oktaAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta int } // tune auth mount if needed - if err := updateAuthMount(ctx, d, meta, true); err != nil { + if err := updateAuthMount(ctx, d, meta, true, false); err != nil { return diag.FromErr(err) } } diff --git a/vault/resource_saml_auth_backend.go b/vault/resource_saml_auth_backend.go index 4aa7314d48..87026a9c03 100644 --- a/vault/resource_saml_auth_backend.go +++ b/vault/resource_saml_auth_backend.go @@ -136,7 +136,11 @@ func samlAuthBackendWrite(ctx context.Context, d *schema.ResourceData, meta inte path := d.Get(consts.FieldPath).(string) log.Printf("[DEBUG] Enabling SAML auth backend %q", path) - if err := createAuthMount(ctx, d, meta, client, path, consts.MountTypeSAML); err != nil { + if err := createAuthMount(ctx, d, meta, client, &createMountRequestParams{ + Path: path, + MountType: consts.MountTypeSAML, + SkipTokenType: false, + }); err != nil { return diag.FromErr(err) } @@ -165,7 +169,7 @@ func samlAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta int path = newMount // tune auth mount if needed - if err := updateAuthMount(ctx, d, meta, true); err != nil { + if err := updateAuthMount(ctx, d, meta, true, false); err != nil { return diag.FromErr(err) } } @@ -216,7 +220,7 @@ func samlAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta inter return nil } - if err := readAuthMount(ctx, d, meta, true); err != nil { + if err := readAuthMount(ctx, d, meta, true, false); err != nil { return diag.FromErr(err) } From ebda2701ee744313308f45a3cc444f4bd0ced2aa Mon Sep 17 00:00:00 2001 From: Vinay Gopalan Date: Mon, 7 Oct 2024 12:51:53 -0700 Subject: [PATCH 4/4] add test for jwt auth backend --- vault/auth_mount.go | 7 +- vault/resource_jwt_auth_backend.go | 4 +- vault/resource_jwt_auth_backend_test.go | 90 ++++++++++++++++++++++++ vault/resource_ldap_auth_backend_test.go | 2 +- 4 files changed, 96 insertions(+), 7 deletions(-) diff --git a/vault/auth_mount.go b/vault/auth_mount.go index adae5be984..4f4881636d 100644 --- a/vault/auth_mount.go +++ b/vault/auth_mount.go @@ -97,9 +97,9 @@ type createMountRequestParams struct { func getAuthMountSchema(excludes ...string) schemaMap { s := schemaMap{ consts.FieldTokenType: { - Type: schema.TypeString, - Optional: true, - //Computed: true, + Type: schema.TypeString, + Optional: true, + Computed: true, Description: "Specifies the type of tokens that should be returned by the mount.", ValidateFunc: validation.StringInSlice([]string{"default-service", "default-batch", "service", "batch"}, false), }, @@ -333,7 +333,6 @@ func readAuthMount(ctx context.Context, d *schema.ResourceData, meta interface{} } // TODO uncomment after fixing bug in vault/api package — user_lockout_config can not be read - // drifts currently can not be managed //if err := d.Set(consts.FieldUserLockoutConfig, flattenUserLockoutConfig(mount.Config.UserLockoutConfig)); err != nil { // return err //} diff --git a/vault/resource_jwt_auth_backend.go b/vault/resource_jwt_auth_backend.go index 2d67cae285..e211bef214 100644 --- a/vault/resource_jwt_auth_backend.go +++ b/vault/resource_jwt_auth_backend.go @@ -268,7 +268,7 @@ func jwtAuthBackendRead(ctx context.Context, d *schema.ResourceData, meta interf path = d.Id() } - if err := readAuthMount(ctx, d, meta, true, false); err != nil { + if err := readAuthMount(ctx, d, meta, false, false); err != nil { return diag.FromErr(err) } @@ -344,7 +344,7 @@ func jwtAuthBackendUpdate(ctx context.Context, d *schema.ResourceData, meta inte } // tune auth mount if needed - if err := updateAuthMount(ctx, d, meta, true, false); err != nil { + if err := updateAuthMount(ctx, d, meta, false, false); err != nil { return diag.FromErr(err) } } diff --git a/vault/resource_jwt_auth_backend_test.go b/vault/resource_jwt_auth_backend_test.go index 04c8a76781..f9e9eaf02c 100644 --- a/vault/resource_jwt_auth_backend_test.go +++ b/vault/resource_jwt_auth_backend_test.go @@ -295,6 +295,96 @@ func TestJWTAuthBackend_remount(t *testing.T) { }) } +func TestJWTAuthBackend_authMountSchema(t *testing.T) { + t.Parallel() + path := acctest.RandomWithPrefix("tf-test-auth-jwt") + + resourceName := "vault_jwt_auth_backend.test" + + resource.Test(t, resource.TestCase{ + ProviderFactories: providerFactories, + PreCheck: func() { testutil.TestAccPreCheck(t) }, + Steps: []resource.TestStep{ + { + Config: testAccJWTAuthBackendConfig_authMountSchema(path, false), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "path", path), + resource.TestCheckResourceAttr(resourceName, "description", "test desc"), + resource.TestCheckResourceAttr(resourceName, "oidc_discovery_url", "https://myco.auth0.com/"), + resource.TestCheckResourceAttr(resourceName, "default_lease_ttl_seconds", "3600"), + resource.TestCheckResourceAttr(resourceName, "max_lease_ttl_seconds", "36000"), + resource.TestCheckResourceAttr(resourceName, "token_type", "default-service"), + resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.#", "2"), + resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.0", "header1"), + resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.1", "header2"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.#", "2"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.0", "header1"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.1", "header2"), + resource.TestCheckResourceAttr(resourceName, "listing_visibility", "hidden"), + ), + }, + { + Config: testAccJWTAuthBackendConfig_authMountSchema(path, true), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "path", path), + resource.TestCheckResourceAttr(resourceName, "description", "test desc updated"), + resource.TestCheckResourceAttr(resourceName, "oidc_discovery_url", "https://myco.auth0.com/"), + resource.TestCheckResourceAttr(resourceName, "default_lease_ttl_seconds", "7200"), + resource.TestCheckResourceAttr(resourceName, "max_lease_ttl_seconds", "48000"), + resource.TestCheckResourceAttr(resourceName, "token_type", "batch"), + resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.#", "2"), + resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.0", "header1"), + resource.TestCheckResourceAttr(resourceName, "passthrough_request_headers.1", "header2"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.#", "3"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.0", "header1"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.1", "header2"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.1", "header2"), + resource.TestCheckResourceAttr(resourceName, "allowed_response_headers.2", "header3"), + resource.TestCheckResourceAttr(resourceName, "listing_visibility", "unauth"), + ), + }, + // TODO user_lockout_config can not be read + testutil.GetImportTestStep(resourceName, false, nil, + consts.FieldDisableRemount, + "user_lockout_config.%", + "user_lockout_config.lockout_counter_reset_duration", + "user_lockout_config.lockout_duration", + "user_lockout_config.lockout_threshold", + ), + }, + }) +} + +func testAccJWTAuthBackendConfig_authMountSchema(path string, isUpdate bool) string { + if !isUpdate { + + return fmt.Sprintf(` +resource "vault_jwt_auth_backend" "test" { + path = "%s" + description = "test desc" + oidc_discovery_url = "https://myco.auth0.com/" + default_lease_ttl_seconds = 3600 + max_lease_ttl_seconds = 36000 + passthrough_request_headers = ["header1", "header2"] + allowed_response_headers = ["header1", "header2"] + listing_visibility = "hidden" +}`, path) + } else { + return fmt.Sprintf(` +resource "vault_jwt_auth_backend" "test" { + path = "%s" + description = "test desc updated" + oidc_discovery_url = "https://myco.auth0.com/" + default_lease_ttl_seconds = 7200 + max_lease_ttl_seconds = 48000 + passthrough_request_headers = ["header1", "header2"] + allowed_response_headers = ["header1", "header2", "header3"] + listing_visibility = "unauth" + token_type = "batch" +}`, path) + } +} + func testAccJWTAuthBackendConfig(path, ns string, local bool) string { c := fmt.Sprintf(` resource "vault_jwt_auth_backend" "jwt" { diff --git a/vault/resource_ldap_auth_backend_test.go b/vault/resource_ldap_auth_backend_test.go index d7f114ddfe..76a54d4e3f 100644 --- a/vault/resource_ldap_auth_backend_test.go +++ b/vault/resource_ldap_auth_backend_test.go @@ -172,7 +172,7 @@ func TestLDAPAuthBackend_authMountSchema(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "listing_visibility", "unauth"), ), }, - // TODO + // TODO user_lockout_config can not be read testutil.GetImportTestStep(resourceName, false, nil, consts.FieldDisableRemount, "user_lockout_config.%",