diff --git a/.changelog/19254.txt b/.changelog/19254.txt new file mode 100644 index 00000000000..59395ea1a74 --- /dev/null +++ b/.changelog/19254.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_macie2_custom_data_identifier +``` diff --git a/aws/provider.go b/aws/provider.go index 1ab2062f9f1..b4d55694e3d 100644 --- a/aws/provider.go +++ b/aws/provider.go @@ -843,6 +843,7 @@ func Provider() *schema.Provider { "aws_lb_ssl_negotiation_policy": resourceAwsLBSSLNegotiationPolicy(), "aws_macie2_account": resourceAwsMacie2Account(), "aws_macie2_classification_job": resourceAwsMacie2ClassificationJob(), + "aws_macie2_custom_data_identifier": resourceAwsMacie2CustomDataIdentifier(), "aws_macie_member_account_association": resourceAwsMacieMemberAccountAssociation(), "aws_macie_s3_bucket_association": resourceAwsMacieS3BucketAssociation(), "aws_main_route_table_association": resourceAwsMainRouteTableAssociation(), diff --git a/aws/resource_aws_macie2_custom_data_identifier.go b/aws/resource_aws_macie2_custom_data_identifier.go new file mode 100644 index 00000000000..0c5c2e2fe1b --- /dev/null +++ b/aws/resource_aws_macie2_custom_data_identifier.go @@ -0,0 +1,228 @@ +package aws + +import ( + "context" + "fmt" + "log" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/macie2" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/keyvaluetags" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" +) + +func resourceAwsMacie2CustomDataIdentifier() *schema.Resource { + return &schema.Resource{ + CreateWithoutTimeout: resourceMacie2CustomDataIdentifierCreate, + ReadWithoutTimeout: resourceMacie2CustomDataIdentifierRead, + DeleteWithoutTimeout: resourceMacie2CustomDataIdentifierDelete, + Importer: &schema.ResourceImporter{ + StateContext: schema.ImportStatePassthroughContext, + }, + Schema: map[string]*schema.Schema{ + "regex": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "keywords": { + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + MinItems: 1, + MaxItems: 50, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(3, 90), + }, + }, + "ignore_words": { + Type: schema.TypeSet, + Optional: true, + ForceNew: true, + MinItems: 1, + MaxItems: 10, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringLenBetween(4, 90), + }, + }, + "name": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"name_prefix"}, + ValidateFunc: validation.StringLenBetween(0, 128), + }, + "name_prefix": { + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ConflictsWith: []string{"name"}, + ValidateFunc: validation.StringLenBetween(0, 128-resource.UniqueIDSuffixLength), + }, + "description": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(0, 512), + }, + "maximum_match_distance": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ForceNew: true, + ValidateFunc: validation.IntBetween(1, 300), + }, + "tags": tagsSchemaForceNew(), + "tags_all": tagsSchemaComputed(), + "created_at": { + Type: schema.TypeString, + Computed: true, + }, + "arn": { + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceMacie2CustomDataIdentifierCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).macie2conn + + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + tags := defaultTagsConfig.MergeTags(keyvaluetags.New(d.Get("tags").(map[string]interface{}))) + + input := &macie2.CreateCustomDataIdentifierInput{ + ClientToken: aws.String(resource.UniqueId()), + } + + if v, ok := d.GetOk("regex"); ok { + input.Regex = aws.String(v.(string)) + } + if v, ok := d.GetOk("keywords"); ok { + input.Keywords = expandStringSet(v.(*schema.Set)) + } + if v, ok := d.GetOk("ignore_words"); ok { + input.IgnoreWords = expandStringSet(v.(*schema.Set)) + } + input.Name = aws.String(naming.Generate(d.Get("name").(string), d.Get("name_prefix").(string))) + if v, ok := d.GetOk("description"); ok { + input.Description = aws.String(v.(string)) + } + if v, ok := d.GetOk("maximum_match_distance"); ok { + input.MaximumMatchDistance = aws.Int64(int64(v.(int))) + } + if len(tags) > 0 { + input.Tags = tags.IgnoreAws().Macie2Tags() + } + + var err error + var output *macie2.CreateCustomDataIdentifierOutput + err = resource.RetryContext(ctx, 4*time.Minute, func() *resource.RetryError { + output, err = conn.CreateCustomDataIdentifierWithContext(ctx, input) + if err != nil { + if tfawserr.ErrCodeEquals(err, macie2.ErrorCodeClientError) { + return resource.RetryableError(err) + } + + return resource.NonRetryableError(err) + } + + return nil + }) + + if isResourceTimeoutError(err) { + output, err = conn.CreateCustomDataIdentifierWithContext(ctx, input) + } + + if err != nil { + return diag.FromErr(fmt.Errorf("error creating Macie CustomDataIdentifier: %w", err)) + } + + d.SetId(aws.StringValue(output.CustomDataIdentifierId)) + + return resourceMacie2CustomDataIdentifierRead(ctx, d, meta) +} + +func resourceMacie2CustomDataIdentifierRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).macie2conn + + defaultTagsConfig := meta.(*AWSClient).DefaultTagsConfig + ignoreTagsConfig := meta.(*AWSClient).IgnoreTagsConfig + input := &macie2.GetCustomDataIdentifierInput{ + Id: aws.String(d.Id()), + } + + resp, err := conn.GetCustomDataIdentifierWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, macie2.ErrCodeResourceNotFoundException) || + tfawserr.ErrMessageContains(err, macie2.ErrCodeAccessDeniedException, "Macie is not enabled") { + log.Printf("[WARN] Macie CustomDataIdentifier (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil + } + + if err != nil { + return diag.FromErr(fmt.Errorf("error reading Macie CustomDataIdentifier (%s): %w", d.Id(), err)) + } + + d.Set("regex", resp.Regex) + if err = d.Set("keywords", flattenStringList(resp.Keywords)); err != nil { + return diag.FromErr(fmt.Errorf("error setting `%s` for Macie CustomDataIdentifier (%s): %w", "keywords", d.Id(), err)) + } + if err = d.Set("ignore_words", flattenStringList(resp.IgnoreWords)); err != nil { + return diag.FromErr(fmt.Errorf("error setting `%s` for Macie CustomDataIdentifier (%s): %w", "ignore_words", d.Id(), err)) + } + d.Set("name", resp.Name) + d.Set("name_prefix", naming.NamePrefixFromName(aws.StringValue(resp.Name))) + d.Set("description", resp.Description) + d.Set("maximum_match_distance", resp.MaximumMatchDistance) + tags := keyvaluetags.Macie2KeyValueTags(resp.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) + + if err = d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { + return diag.FromErr(fmt.Errorf("error setting `%s` for Macie CustomDataIdentifier (%s): %w", "tags", d.Id(), err)) + } + + if err = d.Set("tags_all", tags.Map()); err != nil { + return diag.FromErr(fmt.Errorf("error setting `%s` for Macie CustomDataIdentifier (%s): %w", "tags_all", d.Id(), err)) + } + + if aws.BoolValue(resp.Deleted) { + log.Printf("[WARN] Macie CustomDataIdentifier (%s) is soft deleted, removing from state", d.Id()) + d.SetId("") + } + + d.Set("created_at", aws.TimeValue(resp.CreatedAt).Format(time.RFC3339)) + d.Set("arn", resp.Arn) + + return nil +} + +func resourceMacie2CustomDataIdentifierDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + conn := meta.(*AWSClient).macie2conn + + input := &macie2.DeleteCustomDataIdentifierInput{ + Id: aws.String(d.Id()), + } + + _, err := conn.DeleteCustomDataIdentifierWithContext(ctx, input) + if err != nil { + if tfawserr.ErrCodeEquals(err, macie2.ErrCodeResourceNotFoundException) || + tfawserr.ErrMessageContains(err, macie2.ErrCodeAccessDeniedException, "Macie is not enabled") { + return nil + } + return diag.FromErr(fmt.Errorf("error deleting Macie CustomDataIdentifier (%s): %w", d.Id(), err)) + } + return nil +} diff --git a/aws/resource_aws_macie2_custom_data_identifier_test.go b/aws/resource_aws_macie2_custom_data_identifier_test.go new file mode 100644 index 00000000000..b898d92af0e --- /dev/null +++ b/aws/resource_aws_macie2_custom_data_identifier_test.go @@ -0,0 +1,373 @@ +package aws + +import ( + "fmt" + "regexp" + "testing" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/macie2" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/naming" +) + +func testAccAwsMacie2CustomDataIdentifier_basic(t *testing.T) { + var macie2Output macie2.GetCustomDataIdentifierOutput + resourceName := "aws_macie2_custom_data_identifier.test" + regex := "[0-9]{3}-[0-9]{2}-[0-9]{4}" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAwsMacie2CustomDataIdentifierDestroy, + ErrorCheck: testAccErrorCheck(t, macie2.EndpointsID), + Steps: []resource.TestStep{ + { + Config: testAccAwsMacieCustomDataIdentifierconfigNameGenerated(regex), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsMacie2CustomDataIdentifierExists(resourceName, &macie2Output), + naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), + testAccCheckResourceAttrRfc3339(resourceName, "created_at"), + resource.TestCheckResourceAttr(resourceName, "regex", regex), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "macie2", regexp.MustCompile(`custom-data-identifier/.+`)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAwsMacie2CustomDataIdentifier_Name_Generated(t *testing.T) { + var macie2Output macie2.GetCustomDataIdentifierOutput + resourceName := "aws_macie2_custom_data_identifier.test" + regex := "[0-9]{3}-[0-9]{2}-[0-9]{4}" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAwsMacie2CustomDataIdentifierDestroy, + ErrorCheck: testAccErrorCheck(t, macie2.EndpointsID), + Steps: []resource.TestStep{ + { + Config: testAccAwsMacieCustomDataIdentifierconfigNameGenerated(regex), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsMacie2CustomDataIdentifierExists(resourceName, &macie2Output), + naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAwsMacie2CustomDataIdentifier_disappears(t *testing.T) { + var macie2Output macie2.GetCustomDataIdentifierOutput + resourceName := "aws_macie2_custom_data_identifier.test" + regex := "[0-9]{3}-[0-9]{2}-[0-9]{4}" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAwsMacie2CustomDataIdentifierDestroy, + ErrorCheck: testAccErrorCheck(t, macie2.EndpointsID), + Steps: []resource.TestStep{ + { + Config: testAccAwsMacieCustomDataIdentifierconfigNameGenerated(regex), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsMacie2CustomDataIdentifierExists(resourceName, &macie2Output), + naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), + testAccCheckResourceDisappears(testAccProvider, resourceAwsMacie2Account(), resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccAwsMacie2CustomDataIdentifier_NamePrefix(t *testing.T) { + var macie2Output macie2.GetCustomDataIdentifierOutput + resourceName := "aws_macie2_custom_data_identifier.test" + regex := "[0-9]{3}-[0-9]{2}-[0-9]{4}" + namePrefix := "tf-acc-test-prefix-" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAwsMacie2CustomDataIdentifierDestroy, + ErrorCheck: testAccErrorCheck(t, macie2.EndpointsID), + Steps: []resource.TestStep{ + { + Config: testAccAwsMacieCustomDataIdentifierconfigNamePrefix(namePrefix, regex), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsMacie2CustomDataIdentifierExists(resourceName, &macie2Output), + naming.TestCheckResourceAttrNameFromPrefix(resourceName, "name", namePrefix), + resource.TestCheckResourceAttr(resourceName, "name_prefix", namePrefix), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "macie2", regexp.MustCompile(`custom-data-identifier/.+`)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAwsMacie2CustomDataIdentifier_WithClassificationJob(t *testing.T) { + var macie2Output macie2.GetCustomDataIdentifierOutput + resourceName := "aws_macie2_custom_data_identifier.test" + regex := "[0-9]{3}-[0-9]{2}-[0-9]{4}" + bucketName := acctest.RandomWithPrefix("tf-acc-test") + description := "this is a description" + descriptionUpdated := "this is a updated description" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAwsMacie2CustomDataIdentifierDestroy, + ErrorCheck: testAccErrorCheck(t, macie2.EndpointsID), + Steps: []resource.TestStep{ + { + Config: testAccAwsMacieCustomDataIdentifierconfigComplete(bucketName, regex, description), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsMacie2CustomDataIdentifierExists(resourceName, &macie2Output), + naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), + testAccCheckResourceAttrRfc3339(resourceName, "created_at"), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "macie2", regexp.MustCompile(`custom-data-identifier/.+`)), + ), + }, + { + Config: testAccAwsMacieCustomDataIdentifierconfigComplete(bucketName, regex, descriptionUpdated), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsMacie2CustomDataIdentifierExists(resourceName, &macie2Output), + naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), + testAccCheckResourceAttrRfc3339(resourceName, "created_at"), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "macie2", regexp.MustCompile(`custom-data-identifier/.+`)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAwsMacie2CustomDataIdentifier_WithTags(t *testing.T) { + var macie2Output macie2.GetCustomDataIdentifierOutput + resourceName := "aws_macie2_custom_data_identifier.test" + regex := "[0-9]{3}-[0-9]{2}-[0-9]{4}" + bucketName := acctest.RandomWithPrefix("tf-acc-test") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + ProviderFactories: testAccProviderFactories, + CheckDestroy: testAccCheckAwsMacie2CustomDataIdentifierDestroy, + ErrorCheck: testAccErrorCheck(t, macie2.EndpointsID), + Steps: []resource.TestStep{ + { + Config: testAccAwsMacieCustomDataIdentifierconfigCompleteWithTags(bucketName, regex), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsMacie2CustomDataIdentifierExists(resourceName, &macie2Output), + naming.TestCheckResourceAttrNameGenerated(resourceName, "name"), + resource.TestCheckResourceAttr(resourceName, "name_prefix", "terraform-"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), + resource.TestCheckResourceAttr(resourceName, "tags.Key", "value"), + resource.TestCheckResourceAttr(resourceName, "tags.Key2", "value2"), + resource.TestCheckResourceAttr(resourceName, "tags.Key3", "value3"), + resource.TestCheckResourceAttr(resourceName, "tags_all.%", "3"), + resource.TestCheckResourceAttr(resourceName, "tags_all.Key", "value"), + resource.TestCheckResourceAttr(resourceName, "tags_all.Key2", "value2"), + resource.TestCheckResourceAttr(resourceName, "tags_all.Key3", "value3"), + testAccCheckResourceAttrRfc3339(resourceName, "created_at"), + testAccMatchResourceAttrRegionalARN(resourceName, "arn", "macie2", regexp.MustCompile(`custom-data-identifier/.+`)), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccCheckAwsMacie2CustomDataIdentifierExists(resourceName string, macie2Session *macie2.GetCustomDataIdentifierOutput) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return fmt.Errorf("not found: %s", resourceName) + } + + conn := testAccProvider.Meta().(*AWSClient).macie2conn + input := &macie2.GetCustomDataIdentifierInput{Id: aws.String(rs.Primary.ID)} + + resp, err := conn.GetCustomDataIdentifier(input) + + if err != nil { + return err + } + + if resp == nil { + return fmt.Errorf("macie CustomDataIdentifier %q does not exist", rs.Primary.ID) + } + + *macie2Session = *resp + + return nil + } +} + +func testAccCheckAwsMacie2CustomDataIdentifierDestroy(s *terraform.State) error { + conn := testAccProvider.Meta().(*AWSClient).macie2conn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_macie2_custom_data_identifier" { + continue + } + + input := &macie2.GetCustomDataIdentifierInput{Id: aws.String(rs.Primary.ID)} + resp, err := conn.GetCustomDataIdentifier(input) + + if tfawserr.ErrCodeEquals(err, macie2.ErrCodeResourceNotFoundException) || + tfawserr.ErrMessageContains(err, macie2.ErrCodeAccessDeniedException, "Macie is not enabled") { + continue + } + + if err != nil { + return err + } + + if resp != nil { + return fmt.Errorf("macie CustomDataIdentifier %q still exists", rs.Primary.ID) + } + } + + return nil + +} + +func testAccAwsMacieCustomDataIdentifierconfigNameGenerated(regex string) string { + return fmt.Sprintf(` +resource "aws_macie2_account" "test" {} + +resource "aws_macie2_custom_data_identifier" "test" { + regex = %[1]q + + depends_on = [aws_macie2_account.test] +} +`, regex) +} + +func testAccAwsMacieCustomDataIdentifierconfigNamePrefix(name, regex string) string { + return fmt.Sprintf(` +resource "aws_macie2_account" "test" {} + +resource "aws_macie2_custom_data_identifier" "test" { + name_prefix = %[1]q + regex = %[2]q + + depends_on = [aws_macie2_account.test] +} +`, name, regex) +} + +func testAccAwsMacieCustomDataIdentifierconfigComplete(bucketName, regex, description string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +resource "aws_macie2_account" "test" {} + +resource "aws_s3_bucket" "test" { + bucket = %[1]q +} + +resource "aws_macie2_custom_data_identifier" "test" { + regex = %[2]q + description = %[3]q + maximum_match_distance = 10 + keywords = ["test"] + ignore_words = ["not testing"] + + depends_on = [aws_macie2_account.test] +} + +resource "aws_macie2_classification_job" "test" { + custom_data_identifier_ids = [aws_macie2_custom_data_identifier.test.id] + job_type = "SCHEDULED" + s3_job_definition { + bucket_definitions { + account_id = data.aws_caller_identity.current.account_id + buckets = [aws_s3_bucket.test.bucket] + } + } + schedule_frequency { + daily_schedule = true + } + sampling_percentage = 100 + description = "test" + initial_run = true +} +`, bucketName, regex, description) +} + +func testAccAwsMacieCustomDataIdentifierconfigCompleteWithTags(bucketName, regex string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} + +resource "aws_macie2_account" "test" {} + +resource "aws_s3_bucket" "test" { + bucket = %[1]q +} + +resource "aws_macie2_custom_data_identifier" "test" { + regex = %[2]q + description = "this a description" + maximum_match_distance = 10 + keywords = ["test"] + ignore_words = ["not testing"] + tags = { + Key = "value" + Key2 = "value2" + Key3 = "value3" + } + + depends_on = [aws_macie2_account.test] +} + +resource "aws_macie2_classification_job" "test" { + custom_data_identifier_ids = [aws_macie2_custom_data_identifier.test.id] + job_type = "SCHEDULED" + s3_job_definition { + bucket_definitions { + account_id = data.aws_caller_identity.current.account_id + buckets = [aws_s3_bucket.test.bucket] + } + } + schedule_frequency { + daily_schedule = true + } + sampling_percentage = 100 + description = "test" + initial_run = true +} +`, bucketName, regex) +} diff --git a/aws/resource_aws_macie2_test.go b/aws/resource_aws_macie2_test.go index b3695e98350..e2da5ae708a 100644 --- a/aws/resource_aws_macie2_test.go +++ b/aws/resource_aws_macie2_test.go @@ -22,6 +22,14 @@ func TestAccAWSMacie2_serial(t *testing.T) { "complete": testAccAwsMacie2ClassificationJob_complete, "tags": testAccAwsMacie2ClassificationJob_WithTags, }, + "CustomDataIdentifier": { + "basic": testAccAwsMacie2CustomDataIdentifier_basic, + "name_generated": testAccAwsMacie2CustomDataIdentifier_Name_Generated, + "name_prefix": testAccAwsMacie2CustomDataIdentifier_disappears, + "disappears": testAccAwsMacie2CustomDataIdentifier_NamePrefix, + "classification_job": testAccAwsMacie2CustomDataIdentifier_WithClassificationJob, + "tags": testAccAwsMacie2CustomDataIdentifier_WithTags, + }, } for group, m := range testCases { diff --git a/website/docs/r/macie2_custom_data_identifier.html.markdown b/website/docs/r/macie2_custom_data_identifier.html.markdown new file mode 100644 index 00000000000..1c185ac1c18 --- /dev/null +++ b/website/docs/r/macie2_custom_data_identifier.html.markdown @@ -0,0 +1,58 @@ +--- +subcategory: "Macie" +layout: "aws" +page_title: "AWS: aws_macie2_custom_data_identifier" +description: |- + Provides a resource to manage an AWS Macie Custom Data Identifier. +--- + +# Resource: aws_macie2_custom_data_identifier + +Provides a resource to manage an [AWS Macie Custom Data Identifier](https://docs.aws.amazon.com/macie/latest/APIReference/custom-data-identifiers-id.html). + +## Example Usage + +```terraform +resource "aws_macie2_account" "example" {} + +resource "aws_macie2_custom_data_identifier" "example" { + name = "NAME OF CUSTOM DATA IDENTIFIER" + regex = "[0-9]{3}-[0-9]{2}-[0-9]{4}" + description = "DESCRIPTION" + maximum_match_distance = 10 + keywords = ["keyword"] + ignore_words = ["ignore"] + + depends_on = [aws_macie2_account.test] +} +``` + +## Argument Reference + +The following arguments are supported: + +* `regex` - (Optional) The regular expression (regex) that defines the pattern to match. The expression can contain as many as 512 characters. +* `keywords` - (Optional) An array that lists specific character sequences (keywords), one of which must be within proximity (`maximum_match_distance`) of the regular expression to match. The array can contain as many as 50 keywords. Each keyword can contain 3 - 90 characters. Keywords aren't case sensitive. +* `ignore_words` - (Optional) An array that lists specific character sequences (ignore words) to exclude from the results. If the text matched by the regular expression is the same as any string in this array, Amazon Macie ignores it. The array can contain as many as 10 ignore words. Each ignore word can contain 4 - 90 characters. Ignore words are case sensitive. +* `name` - (Optional) A custom name for the custom data identifier. The name can contain as many as 128 characters. If omitted, Terraform will assign a random, unique name. Conflicts with `name_prefix`. +* `name_prefix` - (Optional) Creates a unique name beginning with the specified prefix. Conflicts with `name`. +* `description` - (Optional) A custom description of the custom data identifier. The description can contain as many as 512 characters. +* `maximum_match_distance` - (Optional) The maximum number of characters that can exist between text that matches the regex pattern and the character sequences specified by the keywords array. Macie includes or excludes a result based on the proximity of a keyword to text that matches the regex pattern. The distance can be 1 - 300 characters. The default value is 50. +* `tags` - (Optional) A map of key-value pairs that specifies the tags to associate with the custom data identifier. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The unique identifier (ID) of the macie custom data identifier. +* `deleted` - Specifies whether the custom data identifier was deleted. If you delete a custom data identifier, Amazon Macie doesn't delete it permanently. Instead, it soft deletes the identifier. +* `created_at` - The date and time, in UTC and extended RFC 3339 format, when the Amazon Macie account was created. +* `arn` - The Amazon Resource Name (ARN) of the custom data identifier. + +## Import + +`aws_macie2_custom_data_identifier` can be imported using the id, e.g. + +``` +$ terraform import aws_macie2_custom_data_identifier.example abcd1 +```