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

Add a hash to random_password with StateUpgrader #254

Merged
merged 10 commits into from
May 18, 2022

Conversation

bendbennett
Copy link
Contributor

@bendbennett bendbennett commented May 13, 2022

This is evaluating whether the changes proposed in #73 can be combined with a StateUpgrader to avoid the situation where including the bcrypt_hash field generates an empty value in state on first use.

Closes #73
Closes #102

return diags
}

if d.Get("bcrypt_hash") == "" {
Copy link
Contributor

Choose a reason for hiding this comment

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

This attribute will always be empty on creation, so the conditional is 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.

Removed conditional.

internal/provider/resource_password.go Show resolved Hide resolved

hash, err := generateHash(result)
if err != nil {
return nil, fmt.Errorf("resource password state upgrade failed, generate hash error: %v", err)
Copy link
Contributor

Choose a reason for hiding this comment

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

Conventionally after Go 1.13, it is recommended to use the %w (wrapped error) formatter for errors.

This does leave an interesting question though, what errors can be generated and are they recoverable? If they are not recoverable (e.g. cannot be fixed by retrying), practitioners will be forever stuck with an unusable resource unless they pin to an older provider version or the state upgrade code is "fixed" or updated to skip on the generation error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Have wrapped the error.

The errors that can be generated relate to:

  • checkCost - this should never return an error as we're using DefaultCost.
  • io.ReadFull - this will return an error if maxSaltSize bytes cannot be read from rand.Reader.
  • bcrypt - can return error if underlying cipher funcs return error.

)

func resourcePassword() *schema.Resource {
passwordSchema := stringSchemaV1(true)
passwordSchema["bcrypt_hash"] = &schema.Schema{
Copy link
Contributor

Choose a reason for hiding this comment

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

Since this new attribute is only handled on Create, e.g. not during Read, it will also need to be handled during Import.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Have added handling of bcrypt_hash to import.

Copy link
Contributor

@detro detro left a comment

Choose a reason for hiding this comment

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

Some nitpicks in regards to "function returning functions" that seems unnecessary, but seems like it's pretty much on the finish line.

)

func resourcePassword() *schema.Resource {
create := func(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nitpick: Why is this function defined inside inside the other function (lamba)?

I can't spot anything that would require this approach ❓

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Have removed.

}
}

func importPasswordFunc() schema.StateContextFunc {
Copy link
Contributor

Choose a reason for hiding this comment

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

Why do you need a function that returns a function here?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Have removed.

},
}
}

func importStringFunc() schema.StateContextFunc {
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as above: having this function returning another function seem not necessary.

But I might be missing something.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Have removed.

Comment on lines +18 to +52
// passwordSchemaV1 uses passwordSchemaV0 to obtain the V0 version of the Schema key-value entries but requires that
// the bcrypt_hash entry be configured.
func passwordSchemaV1() map[string]*schema.Schema {
passwordSchema := passwordSchemaV0()
passwordSchema["bcrypt_hash"] = &schema.Schema{
Description: "A bcrypt hash of the generated random string.",
Type: schema.TypeString,
Computed: true,
Sensitive: true,
}

return passwordSchema
}

// passwordSchemaV0 uses passwordStringSchema to obtain the default Schema key-value entries but requires that the id
// description, result sensitive and bcrypt_hash entries be configured.
func passwordSchemaV0() map[string]*schema.Schema {
passwordSchema := passwordStringSchema()
passwordSchema["id"].Description = "A static value used internally by Terraform, this should not be referenced in configurations."
passwordSchema["result"].Sensitive = true

return passwordSchema
}

// stringSchemaV1 uses passwordStringSchema to obtain the default Schema key-value entries but requires that the id
// description be configured.
func stringSchemaV1() map[string]*schema.Schema {
stringSchema := passwordStringSchema()
stringSchema["id"].Description = "The generated random string."

return stringSchema
}

// passwordStringSchema returns map[string]*schema.Schema with all keys and values that are common to both the
// password and string resources.
Copy link
Contributor

Choose a reason for hiding this comment

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

I like that all the schemas are now next to each other.

Copy link
Contributor

@detro detro left a comment

Choose a reason for hiding this comment

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

After discussing the questions I had in my previous review, I'm providing an approval so you can proceed while you tweak those functions.

@bendbennett bendbennett added this to the v3.2.0 milestone May 17, 2022
Co-authored-by: Ramon Rüttimann <[email protected]>
@bendbennett bendbennett marked this pull request as ready for review May 17, 2022 08:40
@bendbennett bendbennett requested a review from a team as a code owner May 17, 2022 08:40
Copy link
Contributor

@detro detro left a comment

Choose a reason for hiding this comment

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

👩‍🍳 😘

@bendbennett bendbennett requested a review from bflad May 18, 2022 10:34
Copy link
Contributor

@bflad bflad 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 to me 🚀 If you haven't already, I'd suggest running one last manual test using a real Terraform configuration that creates a password via 3.1.0, then uses development overrides with this branch to ensure the state upgrade goes smoothly.

@bendbennett bendbennett merged commit 7d4676c into main May 18, 2022
@bendbennett bendbennett deleted the add_hash_to_random_password branch May 18, 2022 14:27
Copy link

I'm going to lock this pull request because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active contributions.
If you have found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators May 27, 2024
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add random_password.bcrypt attribute
3 participants