-
Notifications
You must be signed in to change notification settings - Fork 9.3k
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
update iam password generation #3989
Conversation
There are 2 major issues with the previous generatePassword() function: - It does not use a cryptographically-secure RNG, meaning that its output is not guaranteed to be secret; - It is seeded only from the current time, making it very easy to bruteforce the password for an adversary with (limited) information on the creation time of the account. resource_aws_iam_user_login_profile: Make uniformly random passwords This maximises the entropy of the resulting password, given a fixed charset and length; given that the charset contains 2*26 + 10 + 20 distinct charactes, using length-21 passwords results in password entropy above 128 bits.
@jbardin FWIW, Github has this nice feature where one can allow project maintainers to push to a PR's branch (and that box was ticked) |
@KellerFuchs, thanks for reminding me! I only moved it out of habit, and I need to remember that feature ;) |
|
||
// Check the generated password contains all character classes listed in the | ||
// IAM password policy. | ||
func checkPwdPolicy(pass []byte) bool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is “the password contains all character classes” actually required by AWS?
If not, please do not enforce that, as it reduces password entropy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We also need to consider the requirement that we need prevent breaking existing users configurations, where the profile running terraform may not have access to read the policy.
In practice this rejects very few samples, since the probability of having each of the 4 classes in a given random password is quite high.
If people feel strongly about this we can attempt to request the policy and fall back to this as the default.
// Even in the worst case, this tends to take less than 10 tries to find a | ||
// matching password. Any sufficiently long password is likely to succeed | ||
// on the first try | ||
for n := 0; n < 100000; n++ { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would rather rename the function from the previous commit to generateOnePassword
(or whatever is appropriate), add a datatype describing password policies, and make generatePassword
take a policy argument.
func TestGenerateIAMPassword(t *testing.T) { | ||
p := generatePassword(6) | ||
|
||
if !(strings.ContainsAny(p, charLower) && |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why is the code copied over from checkPwdPolicy
?
Why do you expect checkPwdPolicy(generatePassword(6))
to be a useful test?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, it doesn't check much. It was just a minor addition after verifying that we can generated the worst case password successfully.
Should generatePassword check whether the requested length and policy yield at least a (configurable?) level of entropy, and error-out if not? |
The IAM PasswordPolicy has very few configuration options. The only options relevant to password generation are the boolean fields: |
OK, I did not realise the options in the policy were Booleans, and not arbitrary numbers; should be Good Enough© then, though I would rather run the numbers on the entropy of generated passwords, but I am not doing that at 1am. |
@@ -20,6 +21,17 @@ import ( | |||
"github.com/hashicorp/vault/helper/pgpkeys" | |||
) | |||
|
|||
func TestGenerateIAMPassword(t *testing.T) { | |||
p := generatePassword(6) | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
add a check here that it is actually 6 chars :)
Check that generated IAM passwords pass any specified iam.PasswordPolicy. IAM password policies cannot set specific numbers of each characters classes, nor can the forbid specific characters. Since the policy restrictions are minimal, rejection sampling will quickly find even the shortest passwords containing all characters classes. This can be extended to lookup the account policy, but in practice that is probably not required. The only real unknown in this case is the minimum password length, which will be validated when setting the password, and catching it earlier won't do any good. Update the validation for password length, since the minimum is 6 characters.
7ce1ea3
to
74334db
Compare
This has been released in version 1.14.0 of the AWS provider. Please see the Terraform documentation on provider versioning or reach out if you need any assistance upgrading. |
@jbardin @paultyng Thanks for getting this finished while I was unavailable :) FYI, I did a back-of-the-enveloppe computation, and the entropy of the generated passwords (with the policy) should be >= 6 bits/character, which isn't much lower than when generating without constraints (where it's ≃6.36b/char) |
I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues. If you feel this issue should be reopened, we encourage creating a new issue linking back to this one for added context. Thanks! |
There are 2 major issues with the previous generatePassword() function:
is not guaranteed to be secret;
the password for an adversary with (limited) information on the creation
time of the account.
resource_aws_iam_user_login_profile: Make uniformly random passwords
This maximises the entropy of the resulting password, given a fixed
charset and length; given that the charset contains 2*26 + 10 + 20
distinct charactes, using length-21 passwords results in password
entropy above 128 bits.
Check that generated IAM passwords pass any specified
iam.PasswordPolicy. IAM password policies cannot set specific numbers of each characters
classes, nor can the forbid specific characters. Since the policy
restrictions are minimal, rejection sampling will quickly find even the
shortest passwords containning all characters classes. This can be
extended to lookup the account policy, but in practice that is probably
not required. The only real unknown in this case is the minimum password
length, which will be validated when setting the password, and catching
it earlier won't do any good.
Update the validation for password length, since the minimum is 6
characters.