mirror of
				https://github.com/optim-enterprises-bv/vault.git
				synced 2025-10-31 02:28:09 +00:00 
			
		
		
		
	backport of commit 8b15e7d216 (#23766)
				
					
				
			Co-authored-by: davidadeleon <56207066+davidadeleon@users.noreply.github.com>
This commit is contained in:
		 hc-github-team-secure-vault-core
					hc-github-team-secure-vault-core
				
			
				
					committed by
					
						 GitHub
						GitHub
					
				
			
			
				
	
			
			
			 GitHub
						GitHub
					
				
			
						parent
						
							ce0c6f9336
						
					
				
				
					commit
					33edf89a86
				
			| @@ -1,3 +0,0 @@ | ||||
| ```release-note:improvement | ||||
| core: emit logs when user(s) are locked out and when all lockouts have been cleared | ||||
| ``` | ||||
| @@ -3074,7 +3074,6 @@ func createCoreConfig(c *ServerCommand, config *server.Config, backend physical. | ||||
| 		DisableSSCTokens:               config.DisableSSCTokens, | ||||
| 		Experiments:                    config.Experiments, | ||||
| 		AdministrativeNamespacePath:    config.AdministrativeNamespacePath, | ||||
| 		UserLockoutLogInterval:         config.UserLockoutLogInterval, | ||||
| 	} | ||||
|  | ||||
| 	if c.flagDev { | ||||
|   | ||||
| @@ -780,7 +780,6 @@ func testConfig_Sanitized(t *testing.T) { | ||||
| 		"enable_response_header_hostname":     false, | ||||
| 		"enable_response_header_raft_node_id": false, | ||||
| 		"log_requests_level":                  "basic", | ||||
| 		"user_lockout_log_interval":           0 * time.Second, | ||||
| 		"ha_storage": map[string]interface{}{ | ||||
| 			"cluster_addr":       "top_level_cluster_addr", | ||||
| 			"disable_clustering": true, | ||||
|   | ||||
| @@ -167,7 +167,6 @@ func TestSysConfigState_Sanitized(t *testing.T) { | ||||
| 				"enable_response_header_hostname":     false, | ||||
| 				"enable_response_header_raft_node_id": false, | ||||
| 				"log_requests_level":                  "", | ||||
| 				"user_lockout_log_interval":           json.Number("0"), | ||||
| 				"listeners": []interface{}{ | ||||
| 					map[string]interface{}{ | ||||
| 						"config": nil, | ||||
|   | ||||
| @@ -24,8 +24,6 @@ type SharedConfig struct { | ||||
| 	Listeners []*Listener `hcl:"-"` | ||||
|  | ||||
| 	UserLockouts []*UserLockout `hcl:"-"` | ||||
| 	UserLockoutLogInterval    time.Duration  `hcl:"-"` | ||||
| 	UserLockoutLogIntervalRaw interface{}    `hcl:"user_lockout_log_interval"` | ||||
|  | ||||
| 	Seals   []*KMS   `hcl:"-"` | ||||
| 	Entropy *Entropy `hcl:"-"` | ||||
| @@ -89,14 +87,6 @@ func ParseConfig(d string) (*SharedConfig, error) { | ||||
| 		result.DisableMlockRaw = nil | ||||
| 	} | ||||
|  | ||||
| 	if result.UserLockoutLogIntervalRaw != nil { | ||||
| 		if result.UserLockoutLogInterval, err = parseutil.ParseDurationSecond(result.UserLockoutLogIntervalRaw); err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		result.FoundKeys = append(result.FoundKeys, "UserLockoutLogInterval") | ||||
| 		result.UserLockoutLogIntervalRaw = nil | ||||
| 	} | ||||
|  | ||||
| 	list, ok := obj.Node.(*ast.ObjectList) | ||||
| 	if !ok { | ||||
| 		return nil, fmt.Errorf("error parsing: file doesn't contain a root object") | ||||
| @@ -186,7 +176,6 @@ func (c *SharedConfig) Sanitized() map[string]interface{} { | ||||
| 		"pid_file":                      c.PidFile, | ||||
| 		"cluster_name":                  c.ClusterName, | ||||
| 		"administrative_namespace_path": c.AdministrativeNamespacePath, | ||||
| 		"user_lockout_log_interval":     c.UserLockoutLogInterval, | ||||
| 	} | ||||
|  | ||||
| 	// Optional log related settings | ||||
|   | ||||
| @@ -56,11 +56,6 @@ func (c *SharedConfig) Merge(c2 *SharedConfig) *SharedConfig { | ||||
| 		result.DefaultMaxRequestDuration = c2.DefaultMaxRequestDuration | ||||
| 	} | ||||
|  | ||||
| 	result.UserLockoutLogInterval = c.UserLockoutLogInterval | ||||
| 	if c2.UserLockoutLogInterval > result.UserLockoutLogInterval { | ||||
| 		result.UserLockoutLogInterval = c2.UserLockoutLogInterval | ||||
| 	} | ||||
|  | ||||
| 	result.LogLevel = c.LogLevel | ||||
| 	if c2.LogLevel != "" { | ||||
| 		result.LogLevel = c2.LogLevel | ||||
|   | ||||
| @@ -105,11 +105,6 @@ const ( | ||||
| 	// MfaAuthResponse when the value is not specified in the server config | ||||
| 	defaultMFAAuthResponseTTL = 300 * time.Second | ||||
|  | ||||
| 	// defaultUserLockoutLogInterval is the default duration that Vault will | ||||
| 	// emit a log informing that a user lockout is in effect when the value | ||||
| 	// is not specified in the server config | ||||
| 	defaultUserLockoutLogInterval = 1 * time.Minute | ||||
|  | ||||
| 	// defaultMaxTOTPValidateAttempts is the default value for the number | ||||
| 	// of failed attempts to validate a request subject to TOTP MFA. If the | ||||
| 	// number of failed totp passcode validations exceeds this max value, the | ||||
| @@ -667,9 +662,6 @@ type Core struct { | ||||
|  | ||||
| 	updateLockedUserEntriesCancel context.CancelFunc | ||||
|  | ||||
| 	lockoutLoggerCancel    context.CancelFunc | ||||
| 	userLockoutLogInterval time.Duration | ||||
|  | ||||
| 	// number of workers to use for lease revocation in the expiration manager | ||||
| 	numExpirationWorkers int | ||||
|  | ||||
| @@ -885,8 +877,6 @@ type CoreConfig struct { | ||||
| 	AdministrativeNamespacePath string | ||||
|  | ||||
| 	NumRollbackWorkers int | ||||
|  | ||||
| 	UserLockoutLogInterval time.Duration | ||||
| } | ||||
|  | ||||
| // SubloggerHook implements the SubloggerAdder interface. This implementation | ||||
| @@ -934,10 +924,6 @@ func CreateCore(conf *CoreConfig) (*Core, error) { | ||||
| 		return nil, fmt.Errorf("cannot have DefaultLeaseTTL larger than MaxLeaseTTL") | ||||
| 	} | ||||
|  | ||||
| 	if conf.UserLockoutLogInterval == 0 { | ||||
| 		conf.UserLockoutLogInterval = defaultUserLockoutLogInterval | ||||
| 	} | ||||
|  | ||||
| 	// Validate the advertise addr if its given to us | ||||
| 	if conf.RedirectAddr != "" { | ||||
| 		u, err := url.Parse(conf.RedirectAddr) | ||||
| @@ -1062,7 +1048,6 @@ func CreateCore(conf *CoreConfig) (*Core, error) { | ||||
| 		disableSSCTokens:               conf.DisableSSCTokens, | ||||
| 		effectiveSDKVersion:            effectiveSDKVersion, | ||||
| 		userFailedLoginInfo:            make(map[FailedLoginUser]*FailedLoginInfo), | ||||
| 		userLockoutLogInterval:         conf.UserLockoutLogInterval, | ||||
| 		experiments:                    conf.Experiments, | ||||
| 		pendingRemovalMountsAllowed:    conf.PendingRemovalMountsAllowed, | ||||
| 		expirationRevokeRetryBase:      conf.ExpirationRevokeRetryBase, | ||||
| @@ -3677,51 +3662,6 @@ func (c *Core) setupCachedMFAResponseAuth() { | ||||
| 	return | ||||
| } | ||||
|  | ||||
| func (c *Core) startLockoutLogger() { | ||||
| 	// Are we already running a logger | ||||
| 	if c.lockoutLoggerCancel != nil { | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	ctx, cancelFunc := context.WithCancel(c.activeContext) | ||||
| 	c.lockoutLoggerCancel = cancelFunc | ||||
|  | ||||
| 	// Perform first check for lockout entries | ||||
| 	lockedUserCount := c.getUserFailedLoginCount(ctx) | ||||
|  | ||||
| 	if lockedUserCount > 0 { | ||||
| 		c.Logger().Warn("user lockout(s) in effect") | ||||
| 	} else { | ||||
| 		// We shouldn't end up here | ||||
| 		return | ||||
| 	} | ||||
|  | ||||
| 	// Start lockout watcher | ||||
| 	go func() { | ||||
| 		ticker := time.NewTicker(c.userLockoutLogInterval) | ||||
| 		for { | ||||
| 			select { | ||||
| 			case <-ticker.C: | ||||
| 				// Check for lockout entries | ||||
| 				lockedUserCount := c.getUserFailedLoginCount(ctx) | ||||
|  | ||||
| 				if lockedUserCount > 0 { | ||||
| 					c.Logger().Warn("user lockout(s) in effect") | ||||
| 					break | ||||
| 				} | ||||
| 				c.Logger().Info("user lockout(s) cleared") | ||||
| 				ticker.Stop() | ||||
| 				c.lockoutLoggerCancel = nil | ||||
| 				return | ||||
| 			case <-ctx.Done(): | ||||
| 				ticker.Stop() | ||||
| 				c.lockoutLoggerCancel = nil | ||||
| 				return | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
| } | ||||
|  | ||||
| // updateLockedUserEntries runs every 15 mins to remove stale user entries from storage | ||||
| // it also updates the userFailedLoginInfo map with correct information for locked users if incorrect | ||||
| func (c *Core) updateLockedUserEntries() { | ||||
| @@ -3750,13 +3690,7 @@ func (c *Core) updateLockedUserEntries() { | ||||
| 			} | ||||
| 		} | ||||
| 	}() | ||||
| } | ||||
|  | ||||
| func (c *Core) getUserFailedLoginCount(ctx context.Context) int { | ||||
| 	c.userFailedLoginInfoLock.Lock() | ||||
| 	defer c.userFailedLoginInfoLock.Unlock() | ||||
|  | ||||
| 	return len(c.userFailedLoginInfo) | ||||
| 	return | ||||
| } | ||||
|  | ||||
| // runLockedUserEntryUpdates runs updates for locked user storage entries and userFailedLoginInfo map | ||||
|   | ||||
| @@ -51,18 +51,6 @@ func unlockUser(ctx context.Context, core *Core, mountAccessor string, aliasName | ||||
| 		return err | ||||
| 	} | ||||
|  | ||||
| 	if core.lockoutLoggerCancel != nil { | ||||
| 		// Check if we have no more locked users and cancel any running lockout logger | ||||
| 		core.userFailedLoginInfoLock.RLock() | ||||
| 		numLockedUsers := len(core.userFailedLoginInfo) | ||||
| 		core.userFailedLoginInfoLock.RUnlock() | ||||
|  | ||||
| 		if numLockedUsers == 0 { | ||||
| 			core.Logger().Info("user lockout(s) cleared") | ||||
| 			core.lockoutLoggerCancel() | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -1478,7 +1478,6 @@ func (c *Core) handleLoginRequest(ctx context.Context, req *logical.Request) (re | ||||
| 			return nil, nil, err | ||||
| 		} | ||||
| 		if isloginUserLocked { | ||||
| 			c.startLockoutLogger() | ||||
| 			return nil, nil, logical.ErrPermissionDenied | ||||
| 		} | ||||
| 	} | ||||
| @@ -2294,8 +2293,6 @@ func (c *Core) LocalGetUserFailedLoginInfo(ctx context.Context, userKey FailedLo | ||||
| // LocalUpdateUserFailedLoginInfo updates the failed login information for a user based on alias name and mountAccessor | ||||
| func (c *Core) LocalUpdateUserFailedLoginInfo(ctx context.Context, userKey FailedLoginUser, failedLoginInfo *FailedLoginInfo, deleteEntry bool) error { | ||||
| 	c.userFailedLoginInfoLock.Lock() | ||||
| 	defer c.userFailedLoginInfoLock.Unlock() | ||||
|  | ||||
| 	switch deleteEntry { | ||||
| 	case false: | ||||
| 		// update entry in the map | ||||
| @@ -2338,6 +2335,7 @@ func (c *Core) LocalUpdateUserFailedLoginInfo(ctx context.Context, userKey Faile | ||||
| 		// delete the entry from the map, if no key exists it is no-op | ||||
| 		delete(c.userFailedLoginInfo, userKey) | ||||
| 	} | ||||
| 	c.userFailedLoginInfoLock.Unlock() | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user