Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Vault 8305 Prevent Brute Forcing in Auth methods : Setting user lockout configuration #17338

Merged
merged 27 commits into from
Nov 1, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
fixing github comments
  • Loading branch information
akshya96 committed Oct 6, 2022
commit 30769563bd1056478d62169ad772a154ba6bbef4
24 changes: 12 additions & 12 deletions api/sys_mounts.go
Original file line number Diff line number Diff line change
Expand Up @@ -289,17 +289,17 @@ type MountOutput struct {
}

type MountConfigOutput struct {
DefaultLeaseTTL int `json:"default_lease_ttl" mapstructure:"default_lease_ttl"`
MaxLeaseTTL int `json:"max_lease_ttl" mapstructure:"max_lease_ttl"`
ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"`
AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"`
AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"`
ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"`
PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"`
AllowedResponseHeaders []string `json:"allowed_response_headers,omitempty" mapstructure:"allowed_response_headers"`
TokenType string `json:"token_type,omitempty" mapstructure:"token_type"`
AllowedManagedKeys []string `json:"allowed_managed_keys,omitempty" mapstructure:"allowed_managed_keys"`
UserLockoutConfig UserLockoutConfigOutput `json:"user_lockout_config"`
DefaultLeaseTTL int `json:"default_lease_ttl" mapstructure:"default_lease_ttl"`
MaxLeaseTTL int `json:"max_lease_ttl" mapstructure:"max_lease_ttl"`
ForceNoCache bool `json:"force_no_cache" mapstructure:"force_no_cache"`
AuditNonHMACRequestKeys []string `json:"audit_non_hmac_request_keys,omitempty" mapstructure:"audit_non_hmac_request_keys"`
AuditNonHMACResponseKeys []string `json:"audit_non_hmac_response_keys,omitempty" mapstructure:"audit_non_hmac_response_keys"`
ListingVisibility string `json:"listing_visibility,omitempty" mapstructure:"listing_visibility"`
PassthroughRequestHeaders []string `json:"passthrough_request_headers,omitempty" mapstructure:"passthrough_request_headers"`
AllowedResponseHeaders []string `json:"allowed_response_headers,omitempty" mapstructure:"allowed_response_headers"`
TokenType string `json:"token_type,omitempty" mapstructure:"token_type"`
AllowedManagedKeys []string `json:"allowed_managed_keys,omitempty" mapstructure:"allowed_managed_keys"`
UserLockoutConfig *UserLockoutConfigOutput `json:"user_lockout_config,,omitempty"`
// Deprecated: This field will always be blank for newer server responses.
PluginName string `json:"plugin_name,omitempty" mapstructure:"plugin_name"`
}
Expand All @@ -312,7 +312,7 @@ type UserLockoutConfigInput struct {
}

type UserLockoutConfigOutput struct {
LockoutThreshold int `json:"lockout_threshold,omitempty" structs:"lockout_threshold" mapstructure:"lockout_threshold"`
LockoutThreshold uint `json:"lockout_threshold,omitempty" structs:"lockout_threshold" mapstructure:"lockout_threshold"`
LockoutDuration int `json:"lockout_duration,omitempty" structs:"lockout_duration" mapstructure:"lockout_duration"`
LockoutCounterReset int `json:"lockout_counter_reset,omitempty" structs:"lockout_counter_reset" mapstructure:"lockout_counter_reset"`
DisableLockout bool `json:"disable_lockout,omitempty" structs:"disable_lockout" mapstructure:"disable_lockout"`
Expand Down
6 changes: 3 additions & 3 deletions command/auth_tune.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ type AuthTuneCommand struct {
flagTokenType string
flagVersion int
flagPluginVersion string
flagUserLockoutThreshold int
flagUserLockoutThreshold uint
flagUserLockoutDuration time.Duration
flagUserLockoutCounterResetDuration time.Duration
flagUserLockoutDisable bool
Expand Down Expand Up @@ -149,7 +149,7 @@ func (c *AuthTuneCommand) Flags() *FlagSets {
Usage: "Select the version of the auth method to run. Not supported by all auth methods.",
})

f.IntVar(&IntVar{
f.UintVar(&UintVar{
Name: flagNameUserLockoutThreshold,
Target: &c.flagUserLockoutThreshold,
Usage: "The threshold for user lockout for this auth method. If unspecified, this " +
Expand Down Expand Up @@ -277,7 +277,7 @@ func (c *AuthTuneCommand) Run(args []string) int {
}
if fl.Name == flagNameUserLockoutThreshold {
if c.flagUserLockoutThreshold > 0 {
akshya96 marked this conversation as resolved.
Show resolved Hide resolved
mountConfigInput.UserLockoutConfig.LockoutThreshold = strconv.Itoa(c.flagUserLockoutThreshold)
mountConfigInput.UserLockoutConfig.LockoutThreshold = strconv.FormatUint(uint64(c.flagUserLockoutThreshold), 10)
}
}
if fl.Name == flagNameUserLockoutDuration {
Expand Down
27 changes: 10 additions & 17 deletions vault/logical_system.go
Original file line number Diff line number Diff line change
Expand Up @@ -1739,7 +1739,6 @@ func (b *SystemBackend) handleTuneWriteCommon(ctx context.Context, path string,

userLockoutConfigMap := data.Get("user_lockout_config").(map[string]interface{})
hghaf099 marked this conversation as resolved.
Show resolved Hide resolved
var err error
// Augmenting userLockoutConfigMap for some config options to treat them as comma separated entries
if userLockoutConfigMap != nil && len(userLockoutConfigMap) != 0 {
hghaf099 marked this conversation as resolved.
Show resolved Hide resolved
err := mapstructure.Decode(userLockoutConfigMap, &apiuserLockoutConfig)
if err != nil {
Expand All @@ -1749,9 +1748,8 @@ func (b *SystemBackend) handleTuneWriteCommon(ctx context.Context, path string,
}

// Supported auth methods for user lockout configuration: ldap, approle, userpass
// "all" is used to apply the configuration to all supported auth methods
switch strings.ToLower(mountEntry.Type) {
case "all", "ldap", "approle", "userpass":
case "ldap", "approle", "userpass":
default:
return logical.ErrorResponse("tuning of user lockout configuration for auth type %q not allowed", mountEntry.Type),
logical.ErrInvalidRequest
Expand All @@ -1763,26 +1761,21 @@ func (b *SystemBackend) handleTuneWriteCommon(ctx context.Context, path string,
mountEntry.Config.UserLockoutConfig = &UserLockoutConfig{}
}

var oldUserLockoutThreshold int64
var oldUserLockoutThreshold uint64
var newUserLockoutDuration, oldUserLockoutDuration time.Duration
var newUserLockoutCounterReset, oldUserLockoutCounterReset time.Duration
var oldUserLockoutDisable bool

if _, ok := userLockoutConfigMap["lockout_threshold"]; ok {
userLockoutThreshold, err := parseutil.ParseInt(apiuserLockoutConfig.LockoutThreshold)
if apiuserLockoutConfig.LockoutThreshold != "" {
userLockoutThreshold, err := strconv.ParseUint(apiuserLockoutConfig.LockoutThreshold, 10, 64)
if err != nil {
return nil, fmt.Errorf("unable to parse user lockout threshold: %w", err)
}
oldUserLockoutThreshold = mountEntry.Config.UserLockoutConfig.LockoutThreshold
switch {
case userLockoutThreshold < 0:
mountEntry.Config.UserLockoutConfig.LockoutThreshold = oldUserLockoutThreshold
default:
mountEntry.Config.UserLockoutConfig.LockoutThreshold = userLockoutThreshold
}
mountEntry.Config.UserLockoutConfig.LockoutThreshold = userLockoutThreshold
}

if _, ok := userLockoutConfigMap["lockout_duration"]; ok {
if apiuserLockoutConfig.LockoutDuration != "" {
oldUserLockoutDuration = mountEntry.Config.UserLockoutConfig.LockoutDuration
switch apiuserLockoutConfig.LockoutDuration {
case "":
Expand All @@ -1800,7 +1793,7 @@ func (b *SystemBackend) handleTuneWriteCommon(ctx context.Context, path string,
mountEntry.Config.UserLockoutConfig.LockoutDuration = newUserLockoutDuration
}

if _, ok := userLockoutConfigMap["lockout_counter_reset_duration"]; ok {
if apiuserLockoutConfig.LockoutCounterResetDuration != "" {
oldUserLockoutCounterReset = mountEntry.Config.UserLockoutConfig.LockoutCounterReset
switch apiuserLockoutConfig.LockoutCounterResetDuration {
case "":
Expand All @@ -1818,10 +1811,10 @@ func (b *SystemBackend) handleTuneWriteCommon(ctx context.Context, path string,
mountEntry.Config.UserLockoutConfig.LockoutCounterReset = newUserLockoutCounterReset
}

if rawVal, ok := userLockoutConfigMap["lockout_disable"]; ok {
userLockoutDisable := rawVal.(bool)
if apiuserLockoutConfig.DisableLockout != nil {
oldUserLockoutDisable = mountEntry.Config.UserLockoutConfig.DisableLockout
mountEntry.Config.UserLockoutConfig.DisableLockout = userLockoutDisable
userLockoutDisable := apiuserLockoutConfig.DisableLockout
mountEntry.Config.UserLockoutConfig.DisableLockout = *userLockoutDisable
}

// Update the mount table
Expand Down
4 changes: 2 additions & 2 deletions vault/mount.go
Original file line number Diff line number Diff line change
Expand Up @@ -360,7 +360,7 @@ type MountConfig struct {
}

type UserLockoutConfig struct {
LockoutThreshold int64 `json:"lockout_threshold,omitempty" structs:"lockout_threshold" mapstructure:"lockout_threshold"`
LockoutThreshold uint64 `json:"lockout_threshold,omitempty" structs:"lockout_threshold" mapstructure:"lockout_threshold"`
LockoutDuration time.Duration `json:"lockout_duration,omitempty" structs:"lockout_duration" mapstructure:"lockout_duration"`
LockoutCounterReset time.Duration `json:"lockout_counter_reset,omitempty" structs:"lockout_counter_reset" mapstructure:"lockout_counter_reset"`
DisableLockout bool `json:"disable_lockout,omitempty" structs:"disable_lockout" mapstructure:"disable_lockout"`
Expand All @@ -370,7 +370,7 @@ type APIUserLockoutConfig struct {
LockoutThreshold string `json:"lockout_threshold,omitempty" structs:"lockout_threshold" mapstructure:"lockout_threshold"`
LockoutDuration string `json:"lockout_duration,omitempty" structs:"lockout_duration" mapstructure:"lockout_duration"`
LockoutCounterResetDuration string `json:"lockout_counter_reset_duration,omitempty" structs:"lockout_counter_reset_duration" mapstructure:"lockout_counter_reset_duration"`
DisableLockout bool `json:"lockout_disable,omitempty" structs:"lockout_disable" mapstructure:"lockout_disable"`
DisableLockout *bool `json:"lockout_disable,omitempty" structs:"lockout_disable" mapstructure:"lockout_disable"`
}

// APIMountConfig is an embedded struct of api.MountConfigInput
Expand Down
32 changes: 0 additions & 32 deletions vault/request_handling.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,6 @@ import (
"github.com/hashicorp/go-secure-stdlib/strutil"
"github.com/hashicorp/go-sockaddr"
"github.com/hashicorp/go-uuid"
"github.com/hashicorp/vault/command/server"
"github.com/hashicorp/vault/helper/identity"
"github.com/hashicorp/vault/helper/identity/mfa"
"github.com/hashicorp/vault/helper/metricsutil"
Expand Down Expand Up @@ -1993,34 +1992,3 @@ func (c *Core) checkSSCTokenInternal(ctx context.Context, token string, isPerfSt
// status code.
return "", logical.ErrMissingRequiredState
}

func (c *Core) GetUserLockoutFromConfig(logicalType string) UserLockoutConfig {
conf := c.rawConfig.Load()
if conf == nil {
return UserLockoutConfig{}
}
userlockouts := conf.(*server.Config).UserLockouts

if userlockouts == nil {
return UserLockoutConfig{}
}

var commonUserLockoutConfig UserLockoutConfig
var authUserLockoutConfig UserLockoutConfig
for _, userLockoutConfig := range userlockouts {
if userLockoutConfig.Type == logicalType {
authUserLockoutConfig.LockoutThreshold = userLockoutConfig.LockoutThreshold
authUserLockoutConfig.LockoutDuration = userLockoutConfig.LockoutDuration
authUserLockoutConfig.LockoutCounterReset = userLockoutConfig.LockoutCounterReset
authUserLockoutConfig.DisableLockout = userLockoutConfig.DisableLockout
return authUserLockoutConfig
}
if userLockoutConfig.Type == "all" {
commonUserLockoutConfig.LockoutThreshold = userLockoutConfig.LockoutThreshold
commonUserLockoutConfig.LockoutDuration = userLockoutConfig.LockoutDuration
commonUserLockoutConfig.LockoutCounterReset = userLockoutConfig.LockoutCounterReset
commonUserLockoutConfig.DisableLockout = userLockoutConfig.DisableLockout
}
}
return commonUserLockoutConfig
}