diff --git a/.changelog/32027.txt b/.changelog/32027.txt new file mode 100644 index 000000000000..d8b6b7317d73 --- /dev/null +++ b/.changelog/32027.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_memorydb_user: Support IAM authentication mode +``` \ No newline at end of file diff --git a/internal/service/memorydb/user.go b/internal/service/memorydb/user.go index 7a4a2f957e9b..fd902b61bd5c 100644 --- a/internal/service/memorydb/user.go +++ b/internal/service/memorydb/user.go @@ -54,7 +54,7 @@ func ResourceUser() *schema.Resource { Schema: map[string]*schema.Schema{ "passwords": { Type: schema.TypeSet, - Required: true, + Optional: true, MinItems: 1, MaxItems: 2, Elem: &schema.Schema{ @@ -100,12 +100,12 @@ func resourceUserCreate(ctx context.Context, d *schema.ResourceData, meta interf userName := d.Get("user_name").(string) input := &memorydb.CreateUserInput{ AccessString: aws.String(d.Get("access_string").(string)), - AuthenticationMode: &memorydb.AuthenticationMode{ - Passwords: flex.ExpandStringSet(d.Get("authentication_mode.0.passwords").(*schema.Set)), - Type: aws.String(d.Get("authentication_mode.0.type").(string)), - }, - Tags: getTagsIn(ctx), - UserName: aws.String(userName), + Tags: getTagsIn(ctx), + UserName: aws.String(userName), + } + + if v, ok := d.GetOk("authentication_mode"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.AuthenticationMode = expandAuthenticationMode(v.([]interface{})[0].(map[string]interface{})) } _, err := conn.CreateUserWithContext(ctx, input) @@ -171,11 +171,8 @@ func resourceUserUpdate(ctx context.Context, d *schema.ResourceData, meta interf input.AccessString = aws.String(d.Get("access_string").(string)) } - if d.HasChange("authentication_mode") { - input.AuthenticationMode = &memorydb.AuthenticationMode{ - Passwords: flex.ExpandStringSet(d.Get("authentication_mode.0.passwords").(*schema.Set)), - Type: aws.String(d.Get("authentication_mode.0.type").(string)), - } + if v, ok := d.GetOk("authentication_mode"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.AuthenticationMode = expandAuthenticationMode(v.([]interface{})[0].(map[string]interface{})) } _, err := conn.UpdateUserWithContext(ctx, input) @@ -216,3 +213,21 @@ func resourceUserDelete(ctx context.Context, d *schema.ResourceData, meta interf return diags } + +func expandAuthenticationMode(tfMap map[string]interface{}) *memorydb.AuthenticationMode { + if tfMap == nil { + return nil + } + + apiObject := &memorydb.AuthenticationMode{} + + if v, ok := tfMap["passwords"].(*schema.Set); ok && v.Len() > 0 { + apiObject.Passwords = flex.ExpandStringSet(v) + } + + if v, ok := tfMap["type"].(string); ok && v != "" { + apiObject.Type = aws.String(v) + } + + return apiObject +} diff --git a/internal/service/memorydb/user_data_source_test.go b/internal/service/memorydb/user_data_source_test.go index 4685ae9c55c1..b11a9d4de6bf 100644 --- a/internal/service/memorydb/user_data_source_test.go +++ b/internal/service/memorydb/user_data_source_test.go @@ -41,6 +41,32 @@ func TestAccMemoryDBUserDataSource_basic(t *testing.T) { }) } +func TestAccMemoryDBUserDataSource_authenticationModeIAM(t *testing.T) { + ctx := acctest.Context(t) + rName := "tf-test-" + sdkacctest.RandString(8) + resourceName := "aws_memorydb_user.test" + dataSourceName := "data.aws_memorydb_user.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccUserDataSourceConfig_authenticationModeIAM(rName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSourceName, "access_string", resourceName, "access_string"), + resource.TestCheckResourceAttrPair(dataSourceName, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSourceName, "authentication_mode.0.type", resourceName, "authentication_mode.0.type"), + resource.TestCheckResourceAttrPair(dataSourceName, "authentication_mode.0.password_count", resourceName, "authentication_mode.0.password_count"), + resource.TestCheckResourceAttrPair(dataSourceName, "minimum_engine_version", resourceName, "minimum_engine_version"), + resource.TestCheckResourceAttrPair(dataSourceName, "user_name", resourceName, "user_name"), + ), + }, + }, + }) +} + func testAccUserDataSourceConfig_basic(rName string) string { return fmt.Sprintf(` resource "aws_memorydb_user" "test" { @@ -62,3 +88,20 @@ data "aws_memorydb_user" "test" { } `, rName) } + +func testAccUserDataSourceConfig_authenticationModeIAM(rName string) string { + return fmt.Sprintf(` +resource "aws_memorydb_user" "test" { + access_string = "on ~* &* +@all" + user_name = %[1]q + + authentication_mode { + type = "iam" + } +} + +data "aws_memorydb_user" "test" { + user_name = aws_memorydb_user.test.user_name +} +`, rName) +} diff --git a/internal/service/memorydb/user_test.go b/internal/service/memorydb/user_test.go index 8a779f60dbb1..7dac2652cf3b 100644 --- a/internal/service/memorydb/user_test.go +++ b/internal/service/memorydb/user_test.go @@ -55,6 +55,41 @@ func TestAccMemoryDBUser_basic(t *testing.T) { }) } +func TestAccMemoryDBUser_authenticationModeIAM(t *testing.T) { + ctx := acctest.Context(t) + rName := "tf-test-" + sdkacctest.RandString(8) + resourceName := "aws_memorydb_user.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, names.MemoryDBServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckUserDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccUserConfig_authenticationModeIAM(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckUserExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "access_string", "on ~* &* +@all"), + acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "memorydb", "user/"+rName), + resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.type", "iam"), + resource.TestCheckResourceAttr(resourceName, "authentication_mode.0.password_count", "0"), + resource.TestCheckResourceAttrSet(resourceName, "minimum_engine_version"), + resource.TestCheckResourceAttr(resourceName, "user_name", rName), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{ + "authentication_mode.0.passwords", + }, + }, + }, + }) +} + func TestAccMemoryDBUser_disappears(t *testing.T) { ctx := acctest.Context(t) rName := "tf-test-" + sdkacctest.RandString(8) @@ -276,6 +311,19 @@ resource "aws_memorydb_user" "test" { `, rName) } +func testAccUserConfig_authenticationModeIAM(rName string) string { + return fmt.Sprintf(` +resource "aws_memorydb_user" "test" { + access_string = "on ~* &* +@all" + user_name = %[1]q + + authentication_mode { + type = "iam" + } +} +`, rName) +} + func testAccUserConfig_accessString(rName, accessString string) string { return fmt.Sprintf(` resource "aws_memorydb_user" "test" { diff --git a/website/docs/d/memorydb_user.html.markdown b/website/docs/d/memorydb_user.html.markdown index 616e7ca0a213..0656d5023b88 100644 --- a/website/docs/d/memorydb_user.html.markdown +++ b/website/docs/d/memorydb_user.html.markdown @@ -32,7 +32,7 @@ This data source exports the following attributes in addition to the arguments a * `access_string` - Access permissions string used for this user. * `arn` - ARN of the user. * `authentication_mode` - Denotes the user's authentication properties. - * `password_count` - The number of passwords belonging to the user. - * `type` - Whether the user requires a password to authenticate. -* `minimum_engine_version` - The minimum engine version supported for the user. -* `tags` - Map of tags assigned to the subnet group. + * `password_count` - Number of passwords belonging to the user if `type` is set to `password`. + * `type` - Type of authentication configured. +* `minimum_engine_version` - Minimum engine version supported for the user. +* `tags` - Map of tags assigned to the user. diff --git a/website/docs/r/memorydb_user.html.markdown b/website/docs/r/memorydb_user.html.markdown index c7daea2459e9..d3af6428b260 100644 --- a/website/docs/r/memorydb_user.html.markdown +++ b/website/docs/r/memorydb_user.html.markdown @@ -37,7 +37,7 @@ resource "aws_memorydb_user" "example" { The following arguments are required: -* `access_string` - (Required) The access permissions string used for this user. +* `access_string` - (Required) Access permissions string used for this user. * `authentication_mode` - (Required) Denotes the user's authentication properties. Detailed below. * `user_name` - (Required, Forces new resource) Name of the MemoryDB user. Up to 40 characters. @@ -47,18 +47,18 @@ The following arguments are optional: ### authentication_mode Configuration Block -* `passwords` - (Required) The set of passwords used for authentication. You can create up to two passwords for each user. -* `type` - (Required) Indicates whether the user requires a password to authenticate. Must be set to `password`. +* `passwords` - (Optional) Set of passwords used for authentication if `type` is set to `password`. You can create up to two passwords for each user. +* `type` - (Required) Specifies the authentication type. Valid values are: `password` or `iam`. ## Attribute Reference This resource exports the following attributes in addition to the arguments above: * `id` - Same as `user_name`. -* `arn` - The ARN of the user. -* `minimum_engine_version` - The minimum engine version supported for the user. +* `arn` - ARN of the user. +* `minimum_engine_version` - Minimum engine version supported for the user. * `authentication_mode` configuration block - * `password_count` - The number of passwords belonging to the user. + * `password_count` - Number of passwords belonging to the user if `type` is set to `password`. * `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block). ## Import