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

Conversation

akshya96
Copy link
Contributor

@akshya96 akshya96 commented Sep 27, 2022

Jira: https://hashicorp.atlassian.net/browse/VAULT-8305
RFC: https://docs.google.com/document/d/1ypCRDMrjmKkElN51PcRSHJtyYNmolhdTu_M_EkPPv5U/edit?usp=sharing
Includes:
Adding user lockout configuration for each auth method using config file
Modifying user lockout configuration for each auth mount using auth tune cli and api

Example of user lockout in config file:
user_lockout "all" {
lockout_threshold = "25"
lockout_duration = "40m"
lockout_counter_reset = "45m"
disable_lockout = "false"
}
user_lockout "userpass" {
lockout_threshold = "100"
lockout_duration = "20m"
}

@akshya96 akshya96 changed the title Vault 8305 lockout config Vault 8305 Prevent Brute Forcing in Auth methods : Add user lockout in config Sep 28, 2022
@akshya96 akshya96 changed the title Vault 8305 Prevent Brute Forcing in Auth methods : Add user lockout in config Vault 8305 Prevent Brute Forcing in Auth methods : Setting user lockout configuration Sep 28, 2022
@akshya96 akshya96 marked this pull request as ready for review September 28, 2022 23:22
Copy link
Contributor

@hghaf099 hghaf099 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have not gone through the entire review yet. It is a nice work! Some comments and questions.

api/sys_mounts.go Outdated Show resolved Hide resolved
command/auth_tune.go Show resolved Hide resolved
command/auth_tune.go Outdated Show resolved Hide resolved
internalshared/configutil/userlockout.go Outdated Show resolved Hide resolved
internalshared/configutil/userlockout_test.go Show resolved Hide resolved
vault/mount.go Outdated Show resolved Hide resolved
vault/logical_system_paths.go Outdated Show resolved Hide resolved
vault/logical_system.go Outdated Show resolved Hide resolved
vault/logical_system.go Outdated Show resolved Hide resolved
vault/logical_system.go Outdated Show resolved Hide resolved
changelog/17338.txt Outdated Show resolved Hide resolved
internalshared/configutil/userlockout.go Show resolved Hide resolved
internalshared/configutil/userlockout.go Show resolved Hide resolved
sdk/helper/consts/consts.go Show resolved Hide resolved
@akshya96 akshya96 requested a review from hghaf099 October 4, 2022 18:11
@akshya96 akshya96 requested a review from ccapurso October 4, 2022 18:11
api/sys_mounts.go Outdated Show resolved Hide resolved
changelog/17338.txt Show resolved Hide resolved
command/auth_tune.go Outdated Show resolved Hide resolved
internalshared/configutil/userlockout.go Outdated Show resolved Hide resolved
}

}
if userLockoutConfig.DisableLockoutRaw != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The raw entries in this function are parsed if they are non-nil. I believe we have this practice in parsing config options that if a raw entry is parsed, it is being set to nil afterwards. Would you think doing the same would be better for consistency? I do notice that these raw values are relied upon to set default values in setMissingUserLockoutValuesInMap function. But, those logics could be changed to checking the non-raw entries and if they have not set before, setting them to the default values.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I agree that the usual way is to set nil for 'raw' values as soon as they are parsed. The issue with checking non-raw entries is because of fields lockout threshold (uint) and disable lockout (bool). It will be difficult to figure out if the user configured lockout threshold with value 0 or if the user did not configure this value at all. In case of other configurations like Listeners, we append values after the parse but in this case, we parse through the map values to set default values for each "type" mentioned in config in result.UserLockouts.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One way to get away from this is set these values to defaults before parsing raw values. But, I guess then there are values that are populated by all type.

switch apiuserLockoutConfig.LockoutCounterResetDuration {
case "":
newUserLockoutCounterReset = oldUserLockoutCounterReset
case "system":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just out of curiosity, what does "system" mean here? Why would the value for counter reset be passed in as system?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And, Is there a default value for the counter reset? or time.Duration(0) is the default value?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In command/auth_tune.go , we set lockout duration as LockoutDuration = ttlToAPI(c.flagUserLockoutDuration). ttlToApi converts user-supplied ttl into an API-compatible string. If the TTL is 0, this returns the empty string. If the TTL is negative, this returns "system" to indicate to use the system values. Otherwise, the time.Duration ttl is used. In the api part, if we do not have any values for this string, we use the already existing values that is present in the entry. If the string is system, we set time.Duration(0) else we use the input ttl.

Copy link
Contributor Author

@akshya96 akshya96 Oct 7, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, we have a default value of 15 minutes for lockout duration and lockout counter reset if not configured by the user using config file / auth tune.

vault/logical_system.go Outdated Show resolved Hide resolved
vault/mount.go Outdated Show resolved Hide resolved
vault/request_handling.go Outdated Show resolved Hide resolved
vault/request_handling.go Outdated Show resolved Hide resolved
Copy link
Contributor

@ccapurso ccapurso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have similar thoughts to some of the comments that @hghaf099 made. Will keep an eye on those threads. Looks good though.

Copy link
Contributor

@hghaf099 hghaf099 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some minor follow ups. Nice work!

internalshared/configutil/config.go Show resolved Hide resolved
changelog/17338.txt Show resolved Hide resolved
internalshared/configutil/config.go Show resolved Hide resolved
}

}
if userLockoutConfig.DisableLockoutRaw != nil {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One way to get away from this is set these values to defaults before parsing raw values. But, I guess then there are values that are populated by all type.

internalshared/configutil/userlockout.go Outdated Show resolved Hide resolved
Copy link
Contributor

@hghaf099 hghaf099 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some minor comments. The code looks good to me!

{
Type: "all",
LockoutThreshold: 5,
LockoutThresholdRaw: nil,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: Would you think removing the nil values here would help readability? Seems like they are unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test would failed if we remove this as it compares with what the values in SharedConfig would look like.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see. I am curious to know what is the failure. The zero value for an interface is nil, so if you don't set it nil explicitly, it should still be nil, no?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, the test was flaky before and the comparison failed for config and expected config sometimes due to arrangement of array elements. When I removed raw entries then, the comparison failed and I felt it was because of that. I think the flaky test fix fixed that and on removing the nil fields, the comparison is successful.

internalshared/configutil/userlockout.go Show resolved Hide resolved
vault/logical_system.go Show resolved Hide resolved
Copy link
Contributor

@ccapurso ccapurso left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

@akshya96 akshya96 merged commit 746b089 into main Nov 1, 2022
@@ -0,0 +1,3 @@
```release-note:feature
core: Add user lockout field to config and configuring this for auth mount using auth tune to prevent brute forcing in auth methods
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@akshya96 - I left a comment on the enterprise PR as well - for new features, they only need one changelog entry per new feature. If you want to make separate changelog entries per PR, those entries shouldn't be in the "features" section (and you may or may not need to make separate additional changelog entries).

For new features, they have a different format for changelog entries. Could you please open a new PR (or use the enterprise PR) to consolidate the changelog entries for this feature and change the formatting?

jayant07-yb pushed a commit to jayant07-yb/hashicorp-vault-integrations that referenced this pull request Mar 15, 2023
…ut configuration (hashicorp#17338)

* config file changes

* lockout config changes

* auth tune r/w and auth tune

* removing changes at enable

* removing q.Q

* go mod tidy

* removing comments

* changing struct name for config file

* fixing mount tune

* adding test file for user lockout

* fixing comments and add changelog

* addressing comments

* fixing mount table updates

* updating consts in auth_tune

* small fixes

* adding hcl parse test

* fixing config compare

* fixing github comments

* optimize userlockouts.go

* fixing test

* minor changes

* adding comments

* adding sort to flaky test

* fix flaky test
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants