diff --git a/.changelog/41589.txt b/.changelog/41589.txt new file mode 100644 index 000000000000..4a884476e4be --- /dev/null +++ b/.changelog/41589.txt @@ -0,0 +1,3 @@ +```release-note:new-resource +aws_quicksight_role_membership +``` diff --git a/docs/acc-test-environment-variables.md b/docs/acc-test-environment-variables.md index 1cc26f287262..e73982ef4915 100644 --- a/docs/acc-test-environment-variables.md +++ b/docs/acc-test-environment-variables.md @@ -97,6 +97,7 @@ Environment variables (beyond standard AWS Go SDK ones) used by acceptance testi | `TF_AWS_LICENSE_MANAGER_GRANT_HOME_REGION` | Region where a License Manager license is imported. | | `TF_AWS_LICENSE_MANAGER_GRANT_LICENSE_ARN` | ARN for a License Manager license imported into the current account. | | `TF_AWS_LICENSE_MANAGER_GRANT_PRINCIPAL` | ARN of a principal to share the License Manager license with. Either a root user, Organization, or Organizational Unit. | +| `TF_AWS_QUICKSIGHT_IDC_GROUP` | Name of the IAM Identity Center Group to be assigned role membership. | | `TF_TEST_CLOUDFRONT_RETAIN` | Flag to disable but dangle CloudFront Distributions during testing to reduce feedback time (must be manually destroyed afterwards) | | `TF_TEST_ELASTICACHE_RESERVED_CACHE_NODE` | Flag to enable resource tests for ElastiCache reserved nodes. Set to `1` to run tests | | `TRUST_ANCHOR_CERTIFICATE` | Trust anchor certificate for KMS custom key store acceptance tests. | diff --git a/internal/service/quicksight/exports_test.go b/internal/service/quicksight/exports_test.go index 72860266657f..1dd241af68f9 100644 --- a/internal/service/quicksight/exports_test.go +++ b/internal/service/quicksight/exports_test.go @@ -18,6 +18,7 @@ var ( ResourceIngestion = newIngestionResource ResourceNamespace = newNamespaceResource ResourceRefreshSchedule = newRefreshScheduleResource + ResourceRoleMembership = newResourceRoleMembership ResourceTemplate = resourceTemplate ResourceTemplateAlias = newTemplateAliasResource ResourceTheme = resourceTheme @@ -41,6 +42,7 @@ var ( FindIngestionByThreePartKey = findIngestionByThreePartKey FindNamespaceByTwoPartKey = findNamespaceByTwoPartKey FindRefreshScheduleByThreePartKey = findRefreshScheduleByThreePartKey + FindRoleMembershipByMultiPartKey = findRoleMembershipByMultiPartKey FindTemplateAliasByThreePartKey = findTemplateAliasByThreePartKey FindTemplateByTwoPartKey = findTemplateByTwoPartKey FindThemeByTwoPartKey = findThemeByTwoPartKey diff --git a/internal/service/quicksight/quicksight_test.go b/internal/service/quicksight/quicksight_test.go index be8778431daa..554b4e10c278 100644 --- a/internal/service/quicksight/quicksight_test.go +++ b/internal/service/quicksight/quicksight_test.go @@ -29,6 +29,11 @@ func TestAccQuickSight_serial(t *testing.T) { acctest.CtBasic: testAccAccountSubscription_basic, acctest.CtDisappears: testAccAccountSubscription_disappears, }, + "RoleMembership": { + acctest.CtBasic: testAccRoleMembership_basic, + acctest.CtDisappears: testAccRoleMembership_disappears, + "role": testAccRoleMembership_role, + }, } acctest.RunSerialTests2Levels(t, testCases, 0) diff --git a/internal/service/quicksight/role_membership.go b/internal/service/quicksight/role_membership.go new file mode 100644 index 000000000000..902823c40fca --- /dev/null +++ b/internal/service/quicksight/role_membership.go @@ -0,0 +1,233 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package quicksight + +import ( + "context" + "fmt" + + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/quicksight" + awstypes "github.com/aws/aws-sdk-go-v2/service/quicksight/types" + "github.com/hashicorp/terraform-plugin-framework/path" + "github.com/hashicorp/terraform-plugin-framework/resource" + "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/errs" + intflex "github.com/hashicorp/terraform-provider-aws/internal/flex" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkResource("aws_quicksight_role_membership", name="Role Membership") +func newResourceRoleMembership(_ context.Context) (resource.ResourceWithConfigure, error) { + return &resourceRoleMembership{}, nil +} + +const ( + ResNameRoleMembership = "Role Membership" +) + +type resourceRoleMembership struct { + framework.ResourceWithConfigure + framework.WithNoUpdate +} + +func (r *resourceRoleMembership) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + names.AttrAWSAccountID: schema.StringAttribute{ + Optional: true, + Computed: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.UseStateForUnknown(), + stringplanmodifier.RequiresReplace(), + }, + }, + "member_name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrNamespace: schema.StringAttribute{ + Optional: true, + Computed: true, + Default: stringdefault.StaticString("default"), + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrRole: schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.Role](), + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + } +} + +func (r *resourceRoleMembership) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) { + conn := r.Meta().QuickSightClient(ctx) + + var plan resourceRoleMembershipModel + resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...) + if resp.Diagnostics.HasError() { + return + } + + if plan.AWSAccountID.IsUnknown() || plan.AWSAccountID.IsNull() { + plan.AWSAccountID = types.StringValue(r.Meta().AccountID(ctx)) + } + + input := quicksight.CreateRoleMembershipInput{ + AwsAccountId: plan.AWSAccountID.ValueStringPointer(), + MemberName: plan.MemberName.ValueStringPointer(), + Namespace: plan.Namespace.ValueStringPointer(), + Role: plan.Role.ValueEnum(), + } + + _, err := conn.CreateRoleMembership(ctx, &input) + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.QuickSight, create.ErrActionCreating, ResNameRoleMembership, plan.MemberName.String(), err), + err.Error(), + ) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, plan)...) +} + +func (r *resourceRoleMembership) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) { + conn := r.Meta().QuickSightClient(ctx) + + var state resourceRoleMembershipModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + err := findRoleMembershipByMultiPartKey(ctx, conn, state.AWSAccountID.ValueString(), state.Namespace.ValueString(), state.Role.ValueEnum(), state.MemberName.ValueString()) + if tfresource.NotFound(err) { + resp.State.RemoveResource(ctx) + return + } + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.QuickSight, create.ErrActionSetting, ResNameRoleMembership, state.MemberName.String(), err), + err.Error(), + ) + return + } + + resp.Diagnostics.Append(resp.State.Set(ctx, &state)...) +} + +func (r *resourceRoleMembership) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) { + conn := r.Meta().QuickSightClient(ctx) + + var state resourceRoleMembershipModel + resp.Diagnostics.Append(req.State.Get(ctx, &state)...) + if resp.Diagnostics.HasError() { + return + } + + input := quicksight.DeleteRoleMembershipInput{ + AwsAccountId: state.AWSAccountID.ValueStringPointer(), + MemberName: state.MemberName.ValueStringPointer(), + Namespace: state.Namespace.ValueStringPointer(), + Role: state.Role.ValueEnum(), + } + + _, err := conn.DeleteRoleMembership(ctx, &input) + if err != nil { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return + } + + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.QuickSight, create.ErrActionDeleting, ResNameRoleMembership, state.MemberName.String(), err), + err.Error(), + ) + return + } +} + +const roleMembershipIDParts = 4 + +func (r *resourceRoleMembership) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) { + parts, err := intflex.ExpandResourceId(req.ID, roleMembershipIDParts, false) + if err != nil { + resp.Diagnostics.AddError( + "Unexpected Import Identifier", + fmt.Sprintf("Expected import identifier with format: aws_account_id,namespace,role,member_name. Got: %q", req.ID), + ) + return + } + + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(names.AttrAWSAccountID), parts[0])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(names.AttrNamespace), parts[1])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(names.AttrRole), parts[2])...) + resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("member_name"), parts[3])...) +} + +// findRoleMembershipByMultiPartKey verifies the existence of a role membership +// +// No value is returned, but the error will be non-nil if no matching member name +// is found in the list of group members for the provided role. +func findRoleMembershipByMultiPartKey(ctx context.Context, conn *quicksight.Client, accountID string, namespace string, role awstypes.Role, member string) error { + input := quicksight.ListRoleMembershipsInput{ + AwsAccountId: aws.String(accountID), + Namespace: aws.String(namespace), + Role: role, + } + + out, err := findRoleMemberships(ctx, conn, &input) + if err != nil { + return err + } + + for _, m := range out { + if m == member { + return nil + } + } + + return &retry.NotFoundError{ + LastRequest: input, + } +} + +func findRoleMemberships(ctx context.Context, conn *quicksight.Client, input *quicksight.ListRoleMembershipsInput) ([]string, error) { + paginator := quicksight.NewListRoleMembershipsPaginator(conn, input) + + var memberNames []string + for paginator.HasMorePages() { + page, err := paginator.NextPage(ctx) + if err != nil { + return nil, err + } + + memberNames = append(memberNames, page.MembersList...) + } + + return memberNames, nil +} + +type resourceRoleMembershipModel struct { + AWSAccountID types.String `tfsdk:"aws_account_id"` + MemberName types.String `tfsdk:"member_name"` + Namespace types.String `tfsdk:"namespace"` + Role fwtypes.StringEnum[awstypes.Role] `tfsdk:"role"` +} diff --git a/internal/service/quicksight/role_membership_test.go b/internal/service/quicksight/role_membership_test.go new file mode 100644 index 000000000000..00637411f7ff --- /dev/null +++ b/internal/service/quicksight/role_membership_test.go @@ -0,0 +1,213 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package quicksight_test + +import ( + "context" + "errors" + "fmt" + "testing" + + "github.com/aws/aws-sdk-go-v2/service/quicksight/types" + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-plugin-testing/plancheck" + "github.com/hashicorp/terraform-plugin-testing/terraform" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" + tfquicksight "github.com/hashicorp/terraform-provider-aws/internal/service/quicksight" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func testAccRoleMembership_basic(t *testing.T) { + ctx := acctest.Context(t) + role := string(types.RoleReader) + resourceName := "aws_quicksight_role_membership.test" + + memberName := acctest.SkipIfEnvVarNotSet(t, "TF_AWS_QUICKSIGHT_IDC_GROUP") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.QuickSightEndpointID) + // Role Membership APIs are only available when QuickSight is configured with IAM Identity Center + acctest.PreCheckSSOAdminInstances(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.QuickSightServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckRoleMembershipDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccRoleMembershipConfig_basic(role, memberName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRoleMembershipExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "member_name", memberName), + resource.TestCheckResourceAttr(resourceName, names.AttrRole, role), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccRoleMembershipImportStateIdFunc(resourceName), + ImportStateVerify: true, + ImportStateVerifyIdentifierAttribute: "member_name", + }, + }, + }) +} + +func testAccRoleMembership_disappears(t *testing.T) { + ctx := acctest.Context(t) + role := string(types.RoleReader) + resourceName := "aws_quicksight_role_membership.test" + + memberName := acctest.SkipIfEnvVarNotSet(t, "TF_AWS_QUICKSIGHT_IDC_GROUP") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.QuickSightEndpointID) + // Role Membership APIs are only available when QuickSight is configured with IAM Identity Center + acctest.PreCheckSSOAdminInstances(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.QuickSightServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckRoleMembershipDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccRoleMembershipConfig_basic(role, memberName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRoleMembershipExists(ctx, resourceName), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfquicksight.ResourceRoleMembership, resourceName), + ), + ExpectNonEmptyPlan: true, + }, + }, + }) +} + +func testAccRoleMembership_role(t *testing.T) { + ctx := acctest.Context(t) + role := string(types.RoleReader) + roleUpdated := string(types.RoleAuthor) + resourceName := "aws_quicksight_role_membership.test" + + memberName := acctest.SkipIfEnvVarNotSet(t, "TF_AWS_QUICKSIGHT_IDC_GROUP") + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.QuickSightEndpointID) + // Role Membership APIs are only available when QuickSight is configured with IAM Identity Center + acctest.PreCheckSSOAdminInstances(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.QuickSightServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckRoleMembershipDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccRoleMembershipConfig_basic(role, memberName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRoleMembershipExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "member_name", memberName), + resource.TestCheckResourceAttr(resourceName, names.AttrRole, role), + ), + }, + { + Config: testAccRoleMembershipConfig_basic(roleUpdated, memberName), + Check: resource.ComposeAggregateTestCheckFunc( + testAccCheckRoleMembershipExists(ctx, resourceName), + resource.TestCheckResourceAttr(resourceName, "member_name", memberName), + resource.TestCheckResourceAttr(resourceName, names.AttrRole, roleUpdated), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionDestroyBeforeCreate), + }, + }, + }, + }, + }) +} + +func testAccCheckRoleMembershipDestroy(ctx context.Context) resource.TestCheckFunc { + return func(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).QuickSightClient(ctx) + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_quicksight_role_membership" { + continue + } + + accountID := rs.Primary.Attributes[names.AttrAWSAccountID] + namespace := rs.Primary.Attributes[names.AttrNamespace] + role := rs.Primary.Attributes[names.AttrRole] + memberName := rs.Primary.Attributes["member_name"] + + err := tfquicksight.FindRoleMembershipByMultiPartKey(ctx, conn, accountID, namespace, types.Role(role), memberName) + if tfresource.NotFound(err) { + return nil + } + if err != nil { + return create.Error(names.QuickSight, create.ErrActionCheckingDestroyed, tfquicksight.ResNameRoleMembership, rs.Primary.ID, err) + } + + return create.Error(names.QuickSight, create.ErrActionCheckingDestroyed, tfquicksight.ResNameRoleMembership, rs.Primary.ID, errors.New("not destroyed")) + } + + return nil + } +} + +func testAccCheckRoleMembershipExists(ctx context.Context, name string) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.RootModule().Resources[name] + if !ok { + return create.Error(names.QuickSight, create.ErrActionCheckingExistence, tfquicksight.ResNameRoleMembership, name, errors.New("not found")) + } + + accountID := rs.Primary.Attributes[names.AttrAWSAccountID] + namespace := rs.Primary.Attributes[names.AttrNamespace] + role := rs.Primary.Attributes[names.AttrRole] + memberName := rs.Primary.Attributes["member_name"] + if accountID == "" || namespace == "" || role == "" || memberName == "" { + return create.Error(names.QuickSight, create.ErrActionCheckingExistence, tfquicksight.ResNameRoleMembership, name, errors.New("not set")) + } + + conn := acctest.Provider.Meta().(*conns.AWSClient).QuickSightClient(ctx) + + err := tfquicksight.FindRoleMembershipByMultiPartKey(ctx, conn, accountID, namespace, types.Role(role), memberName) + if err != nil { + return create.Error(names.QuickSight, create.ErrActionCheckingExistence, tfquicksight.ResNameRoleMembership, rs.Primary.ID, err) + } + + return nil + } +} + +func testAccRoleMembershipImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("Not found: %s", resourceName) + } + + return fmt.Sprintf("%s,%s,%s,%s", + rs.Primary.Attributes[names.AttrAWSAccountID], + rs.Primary.Attributes[names.AttrNamespace], + rs.Primary.Attributes[names.AttrRole], + rs.Primary.Attributes["member_name"], + ), nil + } +} + +func testAccRoleMembershipConfig_basic(role, memberName string) string { + return fmt.Sprintf(` +resource "aws_quicksight_role_membership" "test" { + role = %[1]q + member_name = %[2]q +} +`, role, memberName) +} diff --git a/internal/service/quicksight/service_package_gen.go b/internal/service/quicksight/service_package_gen.go index 56e20573db46..a0084fcb5fd7 100644 --- a/internal/service/quicksight/service_package_gen.go +++ b/internal/service/quicksight/service_package_gen.go @@ -48,6 +48,11 @@ func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.Servic TypeName: "aws_quicksight_refresh_schedule", Name: "Refresh Schedule", }, + { + Factory: newResourceRoleMembership, + TypeName: "aws_quicksight_role_membership", + Name: "Role Membership", + }, { Factory: newTemplateAliasResource, TypeName: "aws_quicksight_template_alias", diff --git a/website/docs/r/quicksight_account_subscription.html.markdown b/website/docs/r/quicksight_account_subscription.html.markdown index 2ed3e96cbe52..0de4c54734a4 100644 --- a/website/docs/r/quicksight_account_subscription.html.markdown +++ b/website/docs/r/quicksight_account_subscription.html.markdown @@ -10,6 +10,8 @@ description: |- Terraform resource for managing an AWS QuickSight Account Subscription. +~> Due to the absence of the `admin_group`, `author_group`, and `reader_group` fields in the [`DescribeAccountSettings`](https://docs.aws.amazon.com/quicksight/latest/APIReference/API_DescribeAccountSettings.html) API response, changes made to these groups post-subscription will not be detected by this resource. + ## Example Usage ```terraform @@ -42,7 +44,7 @@ The following arguments are optional: * `first_name` - (Optional) First name of the author of the Amazon QuickSight account to use for future communications. This field is required if `ENTERPPRISE_AND_Q` is the selected edition of the new Amazon QuickSight account. * `iam_identity_center_instance_arn` - (Optional) The Amazon Resource Name (ARN) for the IAM Identity Center instance. * `last_name` - (Optional) Last name of the author of the Amazon QuickSight account to use for future communications. This field is required if `ENTERPPRISE_AND_Q` is the selected edition of the new Amazon QuickSight account. -* `reader_group` - (Optional) Reader group associated with your Active Direcrtory. +* `reader_group` - (Optional) Reader group associated with your Active Directory. * `realm` - (Optional) Realm of the Active Directory that is associated with your Amazon QuickSight account. ## Attribute Reference diff --git a/website/docs/r/quicksight_role_membership.html.markdown b/website/docs/r/quicksight_role_membership.html.markdown new file mode 100644 index 000000000000..fc4eabd06836 --- /dev/null +++ b/website/docs/r/quicksight_role_membership.html.markdown @@ -0,0 +1,56 @@ +--- +subcategory: "QuickSight" +layout: "aws" +page_title: "AWS: aws_quicksight_role_membership" +description: |- + Terraform resource for managing an AWS QuickSight Role Membership. +--- +# Resource: aws_quicksight_role_membership + +Terraform resource for managing an AWS QuickSight Role Membership. + +~> The role membership APIs are disabled for identities managed by QuickSight. This resource can only be used when the QuickSight account subscription uses the Active Directory or IAM Identity Center authentication method. + +## Example Usage + +### Basic Usage + +```terraform +resource "aws_quicksight_role_membership" "example" { + member_name = "example-group" + role = "READER" +} +``` + +## Argument Reference + +The following arguments are required: + +* `member_name` - (Required) Name of the group to be added to the role. +* `role` - (Required) Role to add the group to. Valid values are `ADMIN`, `AUTHOR`, `READER`, `ADMIN_PRO`, `AUTHOR_PRO`, and `READER_PRO`. + +The following arguments are optional: + +* `aws_account_id` - (Optional) AWS account ID. Defaults to the account of the caller identity if not configured. +* `namespace` - (Required) Name of the namespace. Defaults to `default`. + +## Attribute Reference + +This resource exports no additional attributes. + +## Import + +In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import QuickSight Role Membership using a comma-delimited string combining the `aws_account_id`, `namespace`, `role`, and `member_name`. For example: + +```terraform +import { + to = aws_quicksight_role_membership.example + id = "012345678901,default,READER,example-group" +} +``` + +Using `terraform import`, import QuickSight Role Membership using a comma-delimited string combining the `aws_account_id`, `namespace`, `role`, and `member_name`. For example: + +```console +% terraform import aws_quicksight_role_membership.example 012345678901,default,READER,example-group +```