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

issue #4353 implement generate_random_password attribute #5091

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
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
105 changes: 102 additions & 3 deletions aws/resource_aws_secretsmanager_secret_version.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/secretsmanager"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/helper/validation"
)

func resourceAwsSecretsManagerSecretVersion() *schema.Resource {
Expand All @@ -28,9 +29,15 @@ func resourceAwsSecretsManagerSecretVersion() *schema.Resource {
},
"secret_string": {
Type: schema.TypeString,
Required: true,
Optional: true,
ForceNew: true,
Sensitive: true,
DiffSuppressFunc: func(k, old, new string, d *schema.ResourceData) bool {
if d.HasChange("generate_random_password") {
return false
}
return true
},
},
"version_id": {
Type: schema.TypeString,
Expand All @@ -42,6 +49,60 @@ func resourceAwsSecretsManagerSecretVersion() *schema.Resource {
Computed: true,
Elem: &schema.Schema{Type: schema.TypeString},
},
"generate_random_password": {
Type: schema.TypeList,
Optional: true,
Computed: true,
MaxItems: 1,
ConflictsWith: []string{"secret_string"},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"exclude_characters": {
Type: schema.TypeString,
Optional: true,
ForceNew: true,
},
"exclude_lowercase": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
},
"exclude_numbers": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
},
"exclude_punctuation": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
},
"exclude_uppercase": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
},
"include_space": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
},
"password_length": {
Type: schema.TypeInt,
Optional: true,
ForceNew: true,
Default: 32,
ValidateFunc: validation.IntBetween(1, 4096),
},
"require_each_included_type": {
Type: schema.TypeBool,
Optional: true,
ForceNew: true,
Default: true,
},
},
},
},
},
}
}
Expand All @@ -51,8 +112,46 @@ func resourceAwsSecretsManagerSecretVersionCreate(d *schema.ResourceData, meta i
secretID := d.Get("secret_id").(string)

input := &secretsmanager.PutSecretValueInput{
SecretId: aws.String(secretID),
SecretString: aws.String(d.Get("secret_string").(string)),
SecretId: aws.String(secretID),
}

if v, ok := d.GetOk("secret_string"); ok {
input.SecretString = aws.String(v.(string))
} else if v, ok := d.GetOk("generate_random_password"); ok {

generate_random_password := v.([]interface{})[0].(map[string]interface{})

param := &secretsmanager.GetRandomPasswordInput{
RequireEachIncludedType: aws.Bool(generate_random_password["require_each_included_type"].(bool)),
PasswordLength: aws.Int64(int64(generate_random_password["password_length"].(int))),
}

if v, ok := generate_random_password["exclude_characters"]; ok {
param.ExcludeCharacters = aws.String(v.(string))
}
if v, ok := generate_random_password["exclude_lowercase"]; ok {
param.ExcludeLowercase = aws.Bool(v.(bool))
}
if v, ok := generate_random_password["exclude_numbers"]; ok {
param.ExcludeNumbers = aws.Bool(v.(bool))
}
if v, ok := generate_random_password["exclude_punctuation"]; ok {
param.ExcludePunctuation = aws.Bool(v.(bool))
}
if v, ok := generate_random_password["exclude_uppercase"]; ok {
param.ExcludeUppercase = aws.Bool(v.(bool))
}
if v, ok := generate_random_password["include_space"]; ok {
param.IncludeSpace = aws.Bool(v.(bool))
}

resp, err := conn.GetRandomPassword(param)
if err != nil {
return fmt.Errorf("error getting random password: %s", err)
}
randomPassword := aws.StringValue(resp.RandomPassword)
log.Printf("[DEBUG] Generated random password : %s", randomPassword)
input.SecretString = aws.String(randomPassword)
}

if v, ok := d.GetOk("version_stages"); ok {
Expand Down
38 changes: 38 additions & 0 deletions aws/resource_aws_secretsmanager_secret_version_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,28 @@ func TestAccAwsSecretsManagerSecretVersion_Basic(t *testing.T) {
})
}

func TestAccAwsSecretsManagerSecretVersion_generateRandomPassword(t *testing.T) {
var version secretsmanager.GetSecretValueOutput
rName := acctest.RandomWithPrefix("tf-acc-test")
resourceName := "aws_secretsmanager_secret_version.test"

resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAwsSecretsManagerSecretVersionDestroy,
Steps: []resource.TestStep{
{
Config: testAccAwsSecretsManagerSecretVersionConfig_generateRandomPassword(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsSecretsManagerSecretVersionExists(resourceName, &version),
resource.TestCheckResourceAttrSet(resourceName, "version_id"),
resource.TestCheckResourceAttr(resourceName, "version_stages.#", "1"),
),
},
},
})
}

func TestAccAwsSecretsManagerSecretVersion_VersionStages(t *testing.T) {
var version secretsmanager.GetSecretValueOutput
rName := acctest.RandomWithPrefix("tf-acc-test")
Expand Down Expand Up @@ -187,6 +209,22 @@ resource "aws_secretsmanager_secret_version" "test" {
`, rName)
}

func testAccAwsSecretsManagerSecretVersionConfig_generateRandomPassword(rName string) string {
return fmt.Sprintf(`
resource "aws_secretsmanager_secret" "test" {
name = "%s"
}

resource "aws_secretsmanager_secret_version" "test" {
secret_id = "${aws_secretsmanager_secret.test.id}"
generate_random_password {
exclude_characters = "aed"
exclude_punctuation = true
}
}
`, rName)
}

func testAccAwsSecretsManagerSecretVersionConfig_VersionStages_Single(rName string) string {
return fmt.Sprintf(`
resource "aws_secretsmanager_secret" "test" {
Expand Down
35 changes: 34 additions & 1 deletion website/docs/r/secretsmanager_secret_version.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -50,11 +50,44 @@ resource "aws_secretsmanager_secret_version" "example" {
The following arguments are supported:

* `secret_id` - (Required) Specifies the secret to which you want to add a new version. You can specify either the Amazon Resource Name (ARN) or the friendly name of the secret. The secret must already exist.
* `secret_string` - (Required) Specifies text data that you want to encrypt and store in this version of the secret.
* `secret_string` - (Optional) Specifies text data that you want to encrypt and store in this version of the secret.
* `generate_random_password` - (Optional) You can use this to generate random text data instead of specifying the text data in `secret_string`. Defined below
~> **NOTE:** You should use either one between `secret_string` and `generate_random_password`.
* `version_stages` - (Optional) Specifies a list of staging labels that are attached to this version of the secret. A staging label must be unique to a single version of the secret. If you specify a staging label that's already associated with a different version of the same secret then that staging label is automatically removed from the other version and attached to this version. If you do not specify a value, then AWS Secrets Manager automatically moves the staging label `AWSCURRENT` to this new version on creation.

~> **NOTE:** If `version_stages` is configured, you must include the `AWSCURRENT` staging label if this secret version is the only version or if the label is currently present on this secret version, otherwise Terraform will show a perpetual difference.


## generate_random_password

Full details on the core parameters and impacts are in the API Docs: [GetRandomPassword](https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetRandomPassword.html)

```hcl
resource "aws_secretsmanager_secret_version" "example" {
secret_id = "${aws_secretsmanager_secret.example.id}"
generate_random_password {
exclude_characters = false
exclude_lowercase = false
exclude_numbers = false
exclude_punctuation = false
exclude_uppercase = false
include_space = false
password_length = 32
require_each_included_type = true
}
}
```

* `exclude_characters` - (Optional) A string that includes characters that should not be included in the generated password. The default is that all characters from the included sets can be used.
* `exclude_lowercase` - (Optional) Specifies that the generated password should not include lowercase letters. The default if you do not include this switch parameter is that lowercase letters can be included.
* `exclude_numbers` - (Optional) Specifies that the generated password should not include digits. The default if you do not include this switch parameter is that digits can be included.
* `exclude_punctuation` - (Optional) Specifies that the generated password should not include punctuation characters. The default if you do not include this switch parameter is that punctuation characters can be included.
* `exclude_uppercase` - (Optional) Specifies that the generated password should not include uppercase letters. The default if you do not include this switch parameter is that uppercase letters can be included.
* `include_space` - (Optional) Specifies that the generated password can include the space character. The default if you do not include this switch parameter is that the space character is not included.
* `password_length` - (Optional) The desired length of the generated password. The default value if you do not include this parameter is 32 characters.
* `require_each_included_type` - (Optional) A boolean value that specifies whether the generated password must include at least one of every allowed character type. The default value is True and the operation requires at least one of every character type.


## Attribute Reference

* `id` - A pipe delimited combination of secret ID and version ID
Expand Down