diff --git a/aws/resource_aws_secretsmanager_secret_version.go b/aws/resource_aws_secretsmanager_secret_version.go index a65065f0338..99aa6705d98 100644 --- a/aws/resource_aws_secretsmanager_secret_version.go +++ b/aws/resource_aws_secretsmanager_secret_version.go @@ -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 { @@ -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, @@ -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, + }, + }, + }, + }, }, } } @@ -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 { diff --git a/aws/resource_aws_secretsmanager_secret_version_test.go b/aws/resource_aws_secretsmanager_secret_version_test.go index adbcfec3360..7b08e65ce35 100644 --- a/aws/resource_aws_secretsmanager_secret_version_test.go +++ b/aws/resource_aws_secretsmanager_secret_version_test.go @@ -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") @@ -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" { diff --git a/website/docs/r/secretsmanager_secret_version.html.markdown b/website/docs/r/secretsmanager_secret_version.html.markdown index de1d4239594..f6c2edec8f7 100644 --- a/website/docs/r/secretsmanager_secret_version.html.markdown +++ b/website/docs/r/secretsmanager_secret_version.html.markdown @@ -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