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 #6054 Add name_prefix attribute to aws_secretsmanager_secret #6277

Merged
merged 3 commits into from
Oct 26, 2018
Merged
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
28 changes: 24 additions & 4 deletions aws/resource_aws_secretsmanager_secret.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,9 +37,20 @@ func resourceAwsSecretsManagerSecret() *schema.Resource {
Optional: true,
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ConflictsWith: []string{"name_prefix"},
ValidateFunc: validateSecretManagerSecretName,
},
"name_prefix": {
Type: schema.TypeString,
Optional: true,
Computed: true,
ForceNew: true,
ConflictsWith: []string{"name"},
ValidateFunc: validateSecretManagerSecretNamePrefix,
},
"policy": {
Type: schema.TypeString,
Expand Down Expand Up @@ -92,9 +103,18 @@ func resourceAwsSecretsManagerSecret() *schema.Resource {
func resourceAwsSecretsManagerSecretCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).secretsmanagerconn

var secretName string
if v, ok := d.GetOk("name"); ok {
secretName = v.(string)
} else if v, ok := d.GetOk("name_prefix"); ok {
secretName = resource.PrefixedUniqueId(v.(string))
} else {
secretName = resource.UniqueId()
}

input := &secretsmanager.CreateSecretInput{
Description: aws.String(d.Get("description").(string)),
Name: aws.String(d.Get("name").(string)),
Name: aws.String(secretName),
}

if v, ok := d.GetOk("kms_key_id"); ok && v.(string) != "" {
Expand Down
36 changes: 36 additions & 0 deletions aws/resource_aws_secretsmanager_secret_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,34 @@ func TestAccAwsSecretsManagerSecret_Basic(t *testing.T) {
})
}

func TestAccAwsSecretsManagerSecret_withNamePrefix(t *testing.T) {
var secret secretsmanager.DescribeSecretOutput
rName := "tf-acc-test-"
resourceName := "aws_secretsmanager_secret.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckAwsSecretsManagerSecretDestroy,
Steps: []resource.TestStep{
{
Config: testAccAwsSecretsManagerSecretConfig_withNamePrefix(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAwsSecretsManagerSecretExists(resourceName, &secret),
resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile(fmt.Sprintf("^arn:[^:]+:secretsmanager:[^:]+:[^:]+:secret:%s.+$", rName))),
resource.TestMatchResourceAttr(resourceName, "name", regexp.MustCompile(fmt.Sprintf("^%s", rName))),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"recovery_window_in_days", "name_prefix"},
},
},
})
}

func TestAccAwsSecretsManagerSecret_Description(t *testing.T) {
var secret secretsmanager.DescribeSecretOutput
rName := acctest.RandomWithPrefix("tf-acc-test")
Expand Down Expand Up @@ -495,6 +523,14 @@ resource "aws_secretsmanager_secret" "test" {
`, rName)
}

func testAccAwsSecretsManagerSecretConfig_withNamePrefix(rName string) string {
return fmt.Sprintf(`
resource "aws_secretsmanager_secret" "test" {
name_prefix = "%s"
}
`, rName)
}

func testAccAwsSecretsManagerSecretConfig_KmsKeyID(rName string) string {
return fmt.Sprintf(`
resource "aws_kms_key" "test1" {
Expand Down
27 changes: 27 additions & 0 deletions aws/validators.go
Original file line number Diff line number Diff line change
Expand Up @@ -2014,6 +2014,19 @@ func validateLbTargetGroupName(v interface{}, k string) (ws []string, errors []e
return
}

func validateSecretManagerSecretName(v interface{}, k string) (ws []string, errors []error) {
bflad marked this conversation as resolved.
Show resolved Hide resolved
value := v.(string)
if !regexp.MustCompile(`^[0-9A-Za-z/_+=.@-]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"only alphanumeric characters and /_+=.@- special characters are allowed in %q", k))
}
if len(value) > 512 {
errors = append(errors, fmt.Errorf(
"%q cannot be greater than 512 characters", k))
}
return
}

func validateLbTargetGroupNamePrefix(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
prefixMaxLength := 32 - resource.UniqueIDSuffixLength
Expand All @@ -2031,3 +2044,17 @@ func validateLbTargetGroupNamePrefix(v interface{}, k string) (ws []string, erro
}
return
}

func validateSecretManagerSecretNamePrefix(v interface{}, k string) (ws []string, errors []error) {
value := v.(string)
if !regexp.MustCompile(`^[0-9A-Za-z/_+=.@-]+$`).MatchString(value) {
errors = append(errors, fmt.Errorf(
"only alphanumeric characters and /_+=.@- special characters are allowed in %q", k))
}
prefixMaxLength := 512 - resource.UniqueIDSuffixLength
if len(value) > prefixMaxLength {
errors = append(errors, fmt.Errorf(
"%q cannot be greater than %d characters", k, prefixMaxLength))
}
return
}
54 changes: 52 additions & 2 deletions aws/validators_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2890,7 +2890,6 @@ func TestValidateLbTargetGroupName(t *testing.T) {
ErrCount: 1,
},
}

for _, tc := range cases {
_, errors := validateLbTargetGroupName(tc.Value, "aws_lb_target_group")
if len(errors) != tc.ErrCount {
Expand All @@ -2917,11 +2916,62 @@ func TestValidateLbTargetGroupNamePrefix(t *testing.T) {
ErrCount: 1,
},
}

for _, tc := range cases {
_, errors := validateLbTargetGroupNamePrefix(tc.Value, "aws_lb_target_group")
if len(errors) != tc.ErrCount {
t.Fatalf("Expected the AWS LB Target Group Name to trigger a validation error for %q", tc.Value)
}
}
}

func TestValidateSecretManagerSecretName(t *testing.T) {
cases := []struct {
Value string
ErrCount int
}{
{
Value: "testing123!",
ErrCount: 1,
},
{
Value: "testing 123",
ErrCount: 1,
},
{
Value: randomString(513),
ErrCount: 1,
},
}
for _, tc := range cases {
_, errors := validateSecretManagerSecretName(tc.Value, "aws_secretsmanager_secret")
if len(errors) != tc.ErrCount {
t.Fatalf("Expected the AWS Secretsmanager Secret Name to not trigger a validation error for %q", tc.Value)
}
}
}

func TestValidateSecretManagerSecretNamePrefix(t *testing.T) {
cases := []struct {
Value string
ErrCount int
}{
{
Value: "testing123!",
ErrCount: 1,
},
{
Value: "testing 123",
ErrCount: 1,
},
{
Value: randomString(512),
ErrCount: 1,
},
}
for _, tc := range cases {
_, errors := validateSecretManagerSecretNamePrefix(tc.Value, "aws_secretsmanager_secret")
if len(errors) != tc.ErrCount {
t.Fatalf("Expected the AWS Secretsmanager Secret Name to not trigger a validation error for %q", tc.Value)
}
}
}
3 changes: 2 additions & 1 deletion website/docs/r/secretsmanager_secret.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,8 @@ resource "aws_secretsmanager_secret" "rotation-example" {

The following arguments are supported:

* `name` - (Required) Specifies the friendly name of the new secret. The secret name can consist of uppercase letters, lowercase letters, digits, and any of the following characters: `/_+=.@-` Spaces are not permitted.
* `name` - (Optional) Specifies the friendly name of the new secret. The secret name can consist of uppercase letters, lowercase letters, digits, and any of the following characters: `/_+=.@-` Conflicts with `name_prefix`.
* `name_prefix` - (Optional) Creates a unique name beginning with the specified prefix. Conflicts with `name`.
* `description` - (Optional) A description of the secret.
* `kms_key_id` - (Optional) Specifies the ARN or alias of the AWS KMS customer master key (CMK) to be used to encrypt the secret values in the versions stored in this secret. If you don't specify this value, then Secrets Manager defaults to using the AWS account's default CMK (the one named `aws/secretsmanager`). If the default KMS CMK with that name doesn't yet exist, then AWS Secrets Manager creates it for you automatically the first time.
* `policy` - (Optional) A valid JSON document representing a [resource policy](https://docs.aws.amazon.com/secretsmanager/latest/userguide/auth-and-access_resource-based-policies.html). For more information about building AWS IAM policy documents with Terraform, see the [AWS IAM Policy Document Guide](/docs/providers/aws/guides/iam-policy-documents.html).
Expand Down