diff --git a/internal/provider/provider.go b/internal/provider/provider.go index c8e00839e987..2756d28671ed 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -1831,6 +1831,7 @@ func Provider() *schema.Provider { "aws_ssm_resource_data_sync": ssm.ResourceResourceDataSync(), "aws_ssoadmin_account_assignment": ssoadmin.ResourceAccountAssignment(), + "aws_ssoadmin_account_assignments": ssoadmin.ResourceAccountAssignments(), "aws_ssoadmin_managed_policy_attachment": ssoadmin.ResourceManagedPolicyAttachment(), "aws_ssoadmin_permission_set": ssoadmin.ResourcePermissionSet(), "aws_ssoadmin_permission_set_inline_policy": ssoadmin.ResourcePermissionSetInlinePolicy(), diff --git a/internal/service/ssoadmin/account_assignments.go b/internal/service/ssoadmin/account_assignments.go new file mode 100644 index 000000000000..38ea1bcebb15 --- /dev/null +++ b/internal/service/ssoadmin/account_assignments.go @@ -0,0 +1,318 @@ +package ssoadmin + +import ( + "fmt" + "regexp" + "strings" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/service/ssoadmin" + "github.com/hashicorp/aws-sdk-go-base/tfawserr" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/flex" + "github.com/hashicorp/terraform-provider-aws/internal/verify" +) + +func ResourceAccountAssignments() *schema.Resource { + return &schema.Resource{ + Create: resourceAccountAssignmentsCreate, + Read: resourceAccountAssignmentsRead, + Delete: resourceAccountAssignmentsDelete, + Update: resourceAccountAssignmentsUpdate, + + Importer: &schema.ResourceImporter{ + State: schema.ImportStatePassthrough, + }, + + Schema: map[string]*schema.Schema{ + "instance_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: verify.ValidARN, + }, + + "permission_set_arn": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: verify.ValidARN, + }, + + "principal_ids": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.All( + validation.StringLenBetween(1, 47), + validation.StringMatch(regexp.MustCompile(`^([0-9a-f]{10}-|)[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}$`), "must match ([0-9a-f]{10}-|)[A-Fa-f0-9]{8}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{4}-[A-Fa-f0-9]{12}"), + ), + }, + }, + + "principal_type": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ssoadmin.PrincipalType_Values(), false), + }, + + "target_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: verify.ValidAccountID, + }, + + "target_type": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(ssoadmin.TargetType_Values(), false), + }, + }, + } +} + +func resourceAccountAssignmentsCreate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).SSOAdminConn + + principalIDs := []*string{} + if v, ok := d.GetOk("principal_ids"); ok { + principalIDs = flex.ExpandStringSet(v.(*schema.Set)) + } + + instanceArn := d.Get("instance_arn").(string) + permissionSetArn := d.Get("permission_set_arn").(string) + principalType := d.Get("principal_type").(string) + targetID := d.Get("target_id").(string) + targetType := d.Get("target_type").(string) + + // We need to check if any of the assignments exists before creating them + // since the AWS SSO API doesn't prevent us from creating duplicates + assignedIDs, err := FindAccountAssignmentPrincipals(conn, principalType, targetID, permissionSetArn, instanceArn) + if err != nil { + return fmt.Errorf("error listing SSO Account Assignments for AccountId (%s) PermissionSet (%s): %w", targetID, permissionSetArn, err) + } + + if len(assignedIDs) > 0 { + return fmt.Errorf("error creating SSO Account Assignments for %s: already exists", principalType) + } + + err = createAccountAssignments(conn, instanceArn, permissionSetArn, targetType, targetID, principalType, principalIDs) + + if err != nil { + return fmt.Errorf("error creating SSO Account Assignments for %s: %w", principalType, err) + } + + d.SetId(fmt.Sprintf("%s,%s,%s,%s,%s", principalType, targetID, targetType, permissionSetArn, instanceArn)) + + return resourceAccountAssignmentsRead(d, meta) +} + +func resourceAccountAssignmentsRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).SSOAdminConn + + idParts, err := ParseAccountAssignmentsID(d.Id()) + if err != nil { + return fmt.Errorf("error parsing SSO Account Assignment ID: %w", err) + } + + principalType := idParts[0] + targetID := idParts[1] + targetType := idParts[2] + permissionSetArn := idParts[3] + instanceArn := idParts[4] + + assignedIDs, err := FindAccountAssignmentPrincipals(conn, principalType, targetID, permissionSetArn, instanceArn) + + if err != nil { + return fmt.Errorf("error listing SSO Account Assignments for AccountId (%s) PermissionSet (%s): %w", targetID, permissionSetArn, err) + } + + d.Set("instance_arn", instanceArn) + d.Set("permission_set_arn", permissionSetArn) + d.Set("principal_ids", assignedIDs) + d.Set("principal_type", principalType) + d.Set("target_id", targetID) + d.Set("target_type", targetType) + + return nil +} + +func resourceAccountAssignmentsDelete(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).SSOAdminConn + + idParts, err := ParseAccountAssignmentsID(d.Id()) + if err != nil { + return fmt.Errorf("error parsing SSO Account Assignment ID: %w", err) + } + + principalType := idParts[0] + targetID := idParts[1] + targetType := idParts[2] + permissionSetArn := idParts[3] + instanceArn := idParts[4] + + principalIDs := []*string{} + if v, ok := d.GetOk("principal_ids"); ok { + principalIDs = flex.ExpandStringSet(v.(*schema.Set)) + } + + err = deleteAccountAssignments(conn, instanceArn, permissionSetArn, targetType, targetID, principalType, principalIDs) + + if err != nil { + return fmt.Errorf("error deleting SSO Account Assignments for %s: %w", principalType, err) + } + + return nil +} + +func resourceAccountAssignmentsUpdate(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).SSOAdminConn + + idParts, err := ParseAccountAssignmentsID(d.Id()) + if err != nil { + return fmt.Errorf("error parsing SSO Account Assignment ID: %w", err) + } + + principalType := idParts[0] + targetID := idParts[1] + targetType := idParts[2] + permissionSetArn := idParts[3] + instanceArn := idParts[4] + + principalIDs := []*string{} + if v, ok := d.GetOk("principal_ids"); ok { + principalIDs = flex.ExpandStringSet(v.(*schema.Set)) + } + + assignedIDs, err := FindAccountAssignmentPrincipals(conn, principalType, targetID, permissionSetArn, instanceArn) + + if err != nil { + return fmt.Errorf("error listing SSO Account Assignments for AccountId (%s) PermissionSet (%s): %w", targetID, permissionSetArn, err) + } + + var createPrincipalIDs []*string + for _, principalID := range principalIDs { + found := false + for _, assignedID := range assignedIDs { + if aws.StringValue(principalID) == aws.StringValue(assignedID) { + found = true + break + } + } + if !found { + createPrincipalIDs = append(createPrincipalIDs, principalID) + } + } + + err = createAccountAssignments(conn, instanceArn, permissionSetArn, targetType, targetID, principalType, createPrincipalIDs) + + if err != nil { + return fmt.Errorf("error creating SSO Account Assignments for %s: %w", principalType, err) + } + + var deletePrincipalIDs []*string + for _, assignedID := range assignedIDs { + found := false + for _, principalID := range principalIDs { + if aws.StringValue(principalID) == aws.StringValue(assignedID) { + found = true + break + } + } + if !found { + deletePrincipalIDs = append(deletePrincipalIDs, assignedID) + } + } + + err = deleteAccountAssignments(conn, instanceArn, permissionSetArn, targetType, targetID, principalType, deletePrincipalIDs) + + if err != nil { + return fmt.Errorf("error deleting SSO Account Assignments for %s: %w", principalType, err) + } + + return resourceAccountAssignmentsRead(d, meta) +} + +func createAccountAssignments(conn *ssoadmin.SSOAdmin, instanceArn string, permissionSetArn string, targetType string, targetID string, principalType string, principalIDs []*string) error { + + for _, principalID := range principalIDs { + input := &ssoadmin.CreateAccountAssignmentInput{ + InstanceArn: aws.String(instanceArn), + PermissionSetArn: aws.String(permissionSetArn), + PrincipalId: aws.String(*principalID), + PrincipalType: aws.String(principalType), + TargetId: aws.String(targetID), + TargetType: aws.String(targetType), + } + + output, err := conn.CreateAccountAssignment(input) + if err != nil { + return fmt.Errorf("error creating SSO Account Assignment for %s (%s): %w", principalType, *principalID, err) + } + + if output == nil || output.AccountAssignmentCreationStatus == nil { + return fmt.Errorf("error creating SSO Account Assignment for %s (%s): empty output", principalType, *principalID) + + } + + status := output.AccountAssignmentCreationStatus + + _, err = waitAccountAssignmentCreated(conn, instanceArn, aws.StringValue(status.RequestId)) + if err != nil { + return fmt.Errorf("error waiting for SSO Account Assignment for %s (%s) to be created: %w", principalType, *principalID, err) + } + + } + return nil +} + +func deleteAccountAssignments(conn *ssoadmin.SSOAdmin, instanceArn string, permissionSetArn string, targetType string, targetID string, principalType string, principalIDs []*string) error { + + for _, principalID := range principalIDs { + + input := &ssoadmin.DeleteAccountAssignmentInput{ + PrincipalId: aws.String(*principalID), + InstanceArn: aws.String(instanceArn), + PermissionSetArn: aws.String(permissionSetArn), + TargetType: aws.String(targetType), + TargetId: aws.String(targetID), + PrincipalType: aws.String(principalType), + } + + output, err := conn.DeleteAccountAssignment(input) + if err != nil { + if tfawserr.ErrCodeEquals(err, ssoadmin.ErrCodeResourceNotFoundException) { + return nil + } + return fmt.Errorf("error deleting SSO Account Assignment for Principal (%s): %w", *principalID, err) + } + + if output == nil || output.AccountAssignmentDeletionStatus == nil { + return fmt.Errorf("error deleting SSO Account Assignment for Principal (%s): empty output", *principalID) + } + + status := output.AccountAssignmentDeletionStatus + + _, err = waitAccountAssignmentDeleted(conn, instanceArn, aws.StringValue(status.RequestId)) + if err != nil { + return fmt.Errorf("error waiting for SSO Account Assignment for Principal (%s) to be deleted: %w", *principalID, err) + } + } + + return nil +} + +func ParseAccountAssignmentsID(id string) ([]string, error) { + idParts := strings.Split(id, ",") + if len(idParts) != 5 || idParts[0] == "" || idParts[1] == "" || idParts[2] == "" || + idParts[3] == "" || idParts[4] == "" { + return nil, fmt.Errorf("unexpected format for ID (%q), expected PRINCIPAL_TYPE,TARGET_ID,TARGET_TYPE,PERMISSION_SET_ARN,INSTANCE_ARN", id) + } + return idParts, nil +} diff --git a/internal/service/ssoadmin/account_assignments_test.go b/internal/service/ssoadmin/account_assignments_test.go new file mode 100644 index 000000000000..76dbb2e7e6fa --- /dev/null +++ b/internal/service/ssoadmin/account_assignments_test.go @@ -0,0 +1,163 @@ +package ssoadmin_test + +import ( + "fmt" + "os" + "testing" + + "github.com/aws/aws-sdk-go/service/ssoadmin" + sdkacctest "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/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tfssoadmin "github.com/hashicorp/terraform-provider-aws/internal/service/ssoadmin" +) + +func TestAccSSOAdminAccountAssignments_Basic_group(t *testing.T) { + resourceName := "aws_ssoadmin_account_assignments.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + groupName := os.Getenv("AWS_IDENTITY_STORE_GROUP_NAME") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + testAccPreCheckInstances(t) + }, + ErrorCheck: acctest.ErrorCheck(t, ssoadmin.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAccountAssignmentsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAccountAssignmentsBasicGroupConfig(groupName, rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "target_type", "AWS_ACCOUNT"), + resource.TestCheckResourceAttr(resourceName, "principal_type", "GROUP"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccSSOAdminAccountAssignments_Basic_user(t *testing.T) { + resourceName := "aws_ssoadmin_account_assignments.test" + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + userName := os.Getenv("AWS_IDENTITY_STORE_USER_NAME") + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(t) + testAccPreCheckInstances(t) + }, + ErrorCheck: acctest.ErrorCheck(t, ssoadmin.EndpointsID), + Providers: acctest.Providers, + CheckDestroy: testAccCheckAccountAssignmentsDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAccountAssignmentsBasicUserConfig(userName, rName), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttr(resourceName, "target_type", "AWS_ACCOUNT"), + resource.TestCheckResourceAttr(resourceName, "principal_type", "USER"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAccountAssignmentsBaseConfig(rName string) string { + return fmt.Sprintf(` +data "aws_ssoadmin_instances" "test" {} + +data "aws_caller_identity" "current" {} + +resource "aws_ssoadmin_permission_set" "test" { + name = %q + instance_arn = tolist(data.aws_ssoadmin_instances.test.arns)[0] +} +`, rName) +} + +func testAccAccountAssignmentsBasicGroupConfig(groupName, rName string) string { + return acctest.ConfigCompose( + testAccAccountAssignmentsBaseConfig(rName), + fmt.Sprintf(` +data "aws_identitystore_group" "test" { + identity_store_id = tolist(data.aws_ssoadmin_instances.test.identity_store_ids)[0] + filter { + attribute_path = "DisplayName" + attribute_value = %q + } +} + +resource "aws_ssoadmin_account_assignments" "test" { + instance_arn = aws_ssoadmin_permission_set.test.instance_arn + permission_set_arn = aws_ssoadmin_permission_set.test.arn + target_type = "AWS_ACCOUNT" + target_id = data.aws_caller_identity.current.account_id + principal_type = "GROUP" + principal_ids = [data.aws_identitystore_group.test.group_id] +} +`, groupName)) +} + +func testAccAccountAssignmentsBasicUserConfig(userName, rName string) string { + return acctest.ConfigCompose( + testAccAccountAssignmentsBaseConfig(rName), + fmt.Sprintf(` +data "aws_identitystore_user" "test" { + identity_store_id = tolist(data.aws_ssoadmin_instances.test.identity_store_ids)[0] + filter { + attribute_path = "UserName" + attribute_value = %q + } +} + +resource "aws_ssoadmin_account_assignments" "test" { + instance_arn = aws_ssoadmin_permission_set.test.instance_arn + permission_set_arn = aws_ssoadmin_permission_set.test.arn + target_type = "AWS_ACCOUNT" + target_id = data.aws_caller_identity.current.account_id + principal_type = "USER" + principal_ids = [data.aws_identitystore_user.test.user_id] +} +`, userName)) +} + +func testAccCheckAccountAssignmentsDestroy(s *terraform.State) error { + conn := acctest.Provider.Meta().(*conns.AWSClient).SSOAdminConn + + for _, rs := range s.RootModule().Resources { + if rs.Type != "aws_ssoadmin_account_assignments" { + continue + } + + idParts, err := tfssoadmin.ParseAccountAssignmentsID(rs.Primary.ID) + + if err != nil { + return fmt.Errorf("error parsing SSO Account Assignments ID (%s): %w", rs.Primary.ID, err) + } + + principalType := idParts[0] + targetID := idParts[1] + permissionSetArn := idParts[3] + instanceArn := idParts[4] + + assignedIDs, _ := tfssoadmin.FindAccountAssignmentPrincipals(conn, principalType, targetID, permissionSetArn, instanceArn) + + if len(assignedIDs) > 0 { + return fmt.Errorf("SSO Account Assignments still exist") + } + } + + return nil +} diff --git a/internal/service/ssoadmin/find.go b/internal/service/ssoadmin/find.go index 3cb125f4207e..4f488320f6a5 100644 --- a/internal/service/ssoadmin/find.go +++ b/internal/service/ssoadmin/find.go @@ -69,3 +69,36 @@ func FindManagedPolicy(conn *ssoadmin.SSOAdmin, managedPolicyArn, permissionSetA return attachedPolicy, err } + +// FindAccountAssignmentPrincipals returns the principal ids assigned to a permission set within a specified SSO instance. +func FindAccountAssignmentPrincipals(conn *ssoadmin.SSOAdmin, principalType, accountId, permissionSetArn, instanceArn string) ([]*string, error) { + input := &ssoadmin.ListAccountAssignmentsInput{ + AccountId: aws.String(accountId), + InstanceArn: aws.String(instanceArn), + PermissionSetArn: aws.String(permissionSetArn), + } + + var principalIds []*string + + err := conn.ListAccountAssignmentsPages(input, func(page *ssoadmin.ListAccountAssignmentsOutput, lastPage bool) bool { + if page == nil { + return !lastPage + } + + for _, a := range page.AccountAssignments { + if a == nil { + continue + } + + if aws.StringValue(a.PrincipalType) != principalType { + continue + } + + principalIds = append(principalIds, a.PrincipalId) + } + + return !lastPage + }) + + return principalIds, err +} diff --git a/internal/service/ssoadmin/wait.go b/internal/service/ssoadmin/wait.go index 1ed462130683..67d3d667bc43 100644 --- a/internal/service/ssoadmin/wait.go +++ b/internal/service/ssoadmin/wait.go @@ -16,7 +16,7 @@ const ( awsSSOAdminPermissionSetProvisionTimeout = 10 * time.Minute ) -func waitAccountAssignmentCreated(conn *ssoadmin.SSOAdmin, instanceArn, requestID string) (*ssoadmin.AccountAssignmentOperationStatus, error) { +func waitAccountAssignmentCreated(conn *ssoadmin.SSOAdmin, instanceArn, requestID string) (*ssoadmin.AccountAssignmentOperationStatus, error) { //nolint:unparam stateConf := &resource.StateChangeConf{ Pending: []string{ssoadmin.StatusValuesInProgress}, Target: []string{ssoadmin.StatusValuesSucceeded}, @@ -34,7 +34,7 @@ func waitAccountAssignmentCreated(conn *ssoadmin.SSOAdmin, instanceArn, requestI return nil, err } -func waitAccountAssignmentDeleted(conn *ssoadmin.SSOAdmin, instanceArn, requestID string) (*ssoadmin.AccountAssignmentOperationStatus, error) { +func waitAccountAssignmentDeleted(conn *ssoadmin.SSOAdmin, instanceArn, requestID string) (*ssoadmin.AccountAssignmentOperationStatus, error) { //nolint:unparam stateConf := &resource.StateChangeConf{ Pending: []string{ssoadmin.StatusValuesInProgress}, Target: []string{ssoadmin.StatusValuesSucceeded}, diff --git a/website/docs/r/ssoadmin_account_assignment.html.markdown b/website/docs/r/ssoadmin_account_assignment.html.markdown index 0bdc0f0a003f..aa5fab04d59a 100644 --- a/website/docs/r/ssoadmin_account_assignment.html.markdown +++ b/website/docs/r/ssoadmin_account_assignment.html.markdown @@ -6,6 +6,8 @@ description: |- Manages a Single Sign-On (SSO) Account Assignment --- +~> **Note:** `aws_ssoadmin_account_assignment` **cannot** be used in conjunction with `aws_ssoadmin_account_assignments` or they will fight over what principal ids should be associated with what permission sets. + # Resource: aws_ssoadmin_account_assignment Provides a Single Sign-On (SSO) Account Assignment resource diff --git a/website/docs/r/ssoadmin_account_assignments.html.markdown b/website/docs/r/ssoadmin_account_assignments.html.markdown new file mode 100644 index 000000000000..7e231f0357c3 --- /dev/null +++ b/website/docs/r/ssoadmin_account_assignments.html.markdown @@ -0,0 +1,85 @@ +--- +subcategory: "SSO Admin" +layout: "aws" +page_title: "AWS: aws_ssoadmin_account_assignments" +description: |- + Manages Multiple Single Sign-On (SSO) Account Assignments Authoritatively +--- + +# Resource: aws_ssoadmin_account_assignments + +Manages multiple Single Sign-On (SSO) Account Assignments Authoritatively. + +This resource is authoritative over a given combination of `instance_arn`, `permission_set_arn` and `principal type`. + +~> **Note:** `aws_ssoadmin_account_assignments` **cannot** be used in conjunction with `aws_ssoadmin_account_assignment` or they will fight over what principal ids should be associated with what permission sets. + + +## Example Usage + +```terraform +data "aws_ssoadmin_instances" "example" {} + +data "aws_ssoadmin_permission_set" "example" { + instance_arn = tolist(data.aws_ssoadmin_instances.example.arns)[0] + name = "AWSReadOnlyAccess" +} + +data "aws_identitystore_group" "example1" { + identity_store_id = tolist(data.aws_ssoadmin_instances.example.identity_store_ids)[0] + + filter { + attribute_path = "DisplayName" + attribute_value = "ExampleGroup1" + } +} + +data "aws_identitystore_group" "example2" { + identity_store_id = tolist(data.aws_ssoadmin_instances.example.identity_store_ids)[0] + + filter { + attribute_path = "DisplayName" + attribute_value = "ExampleGroup2" + } +} + +resource "aws_ssoadmin_account_assignments" "example" { + instance_arn = data.aws_ssoadmin_permission_set.example.instance_arn + permission_set_arn = data.aws_ssoadmin_permission_set.example.arn + + principal_ids = [ + data.aws_identitystore_group.example1.group_id, + data.aws_identitystore_group.example2.group_id + ] + + principal_type = "GROUP" + + target_id = "012347678910" + target_type = "AWS_ACCOUNT" +} +``` + +## Argument Reference + +The following arguments are supported: + +* `instance_arn` - (Required, Forces new resource) The Amazon Resource Name (ARN) of the SSO Instance. +* `permission_set_arn` - (Required, Forces new resource) The Amazon Resource Name (ARN) of the Permission Set that the admin wants to grant the principal access to. +* `principal_ids` - (Required) A list of identifiers for objects in SSO, such as a user or group. PrincipalIds are GUIDs (For example, `f81d4fae-7dec-11d0-a765-00a0c91e6bf6`). +* `principal_type` - (Required, Forces new resource) The entity type for which the assignment will be created. Valid values: `USER`, `GROUP`. +* `target_id` - (Required, Forces new resource) An AWS account identifier, typically a 10-12 digit string. +* `target_type` - (Optional, Forces new resource) The entity type for which the assignment will be created. Valid values: `AWS_ACCOUNT`. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - The identifier of the Account Assignment i.e., `principal_type`, `target_id`, `target_type`, `permission_set_arn`, `instance_arn` separated by commas (`,`). + +## Import + +SSO Account Assignments can be imported using the `principal_type`, `target_id`, `target_type`, `permission_set_arn`, `instance_arn` separated by commas (`,`) e.g., + +``` +$ terraform import aws_ssoadmin_account_assignments.example GROUP,1234567890,AWS_ACCOUNT,arn:aws:sso:::permissionSet/ssoins-0123456789abcdef/ps-0123456789abcdef,arn:aws:sso:::instance/ssoins-0123456789abcdef +```