From 8f0e871353e802af0c411f88b7e9ccfc7532ce25 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 14:32:35 +0300 Subject: [PATCH 1/3] transfer server user - efs + refactor --- .../service/transfer/finder/finder.go | 29 ++ .../service/transfer/waiter/status.go | 16 + .../service/transfer/waiter/waiter.go | 18 + aws/resource_aws_transfer_user.go | 153 +++++--- aws/resource_aws_transfer_user_test.go | 350 ++++++++++++------ 5 files changed, 393 insertions(+), 173 deletions(-) diff --git a/aws/internal/service/transfer/finder/finder.go b/aws/internal/service/transfer/finder/finder.go index 5680e032ca2..50493ce74cf 100644 --- a/aws/internal/service/transfer/finder/finder.go +++ b/aws/internal/service/transfer/finder/finder.go @@ -34,3 +34,32 @@ func ServerByID(conn *transfer.Transfer, id string) (*transfer.DescribedServer, return output.Server, nil } + +func UserByID(conn *transfer.Transfer, serverId, userName string) (*transfer.DescribeUserOutput, error) { + input := &transfer.DescribeUserInput{ + ServerId: aws.String(serverId), + UserName: aws.String(userName), + } + + output, err := conn.DescribeUser(input) + + if tfawserr.ErrCodeEquals(err, transfer.ErrCodeResourceNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.User == nil { + return nil, &resource.NotFoundError{ + Message: "Empty result", + LastRequest: input, + } + } + + return output, nil +} diff --git a/aws/internal/service/transfer/waiter/status.go b/aws/internal/service/transfer/waiter/status.go index b142972008d..7f860ac0b8b 100644 --- a/aws/internal/service/transfer/waiter/status.go +++ b/aws/internal/service/transfer/waiter/status.go @@ -23,3 +23,19 @@ func ServerState(conn *transfer.Transfer, id string) resource.StateRefreshFunc { return output, aws.StringValue(output.State), nil } } + +func UserState(conn *transfer.Transfer, serverId, userName string) resource.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := finder.UserByID(conn, serverId, userName) + + if tfresource.NotFound(err) { + return nil, "", nil + } + + if err != nil { + return nil, "", err + } + + return output, "Available", nil + } +} diff --git a/aws/internal/service/transfer/waiter/waiter.go b/aws/internal/service/transfer/waiter/waiter.go index a6d5000e2cf..6ffaed93c52 100644 --- a/aws/internal/service/transfer/waiter/waiter.go +++ b/aws/internal/service/transfer/waiter/waiter.go @@ -9,6 +9,7 @@ import ( const ( ServerDeletedTimeout = 10 * time.Minute + UserDeletedTimeout = 10 * time.Minute ) func ServerCreated(conn *transfer.Transfer, id string, timeout time.Duration) (*transfer.DescribedServer, error) { @@ -78,3 +79,20 @@ func ServerStopped(conn *transfer.Transfer, id string, timeout time.Duration) (* return nil, err } + +func UserDeleted(conn *transfer.Transfer, serverId, userName string) (*transfer.DescribedUser, error) { + stateConf := &resource.StateChangeConf{ + Pending: []string{"Available"}, + Target: []string{}, + Refresh: UserState(conn, serverId, userName), + Timeout: UserDeletedTimeout, + } + + outputRaw, err := stateConf.WaitForState() + + if output, ok := outputRaw.(*transfer.DescribedUser); ok { + return output, err + } + + return nil, err +} diff --git a/aws/resource_aws_transfer_user.go b/aws/resource_aws_transfer_user.go index f65fddf8027..61f8fdc5fd3 100644 --- a/aws/resource_aws_transfer_user.go +++ b/aws/resource_aws_transfer_user.go @@ -3,15 +3,16 @@ package aws import ( "fmt" "log" - "time" "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/transfer" - "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" tftransfer "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/service/transfer/waiter" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func resourceAwsTransferUser() *schema.Resource { @@ -69,6 +70,28 @@ func resourceAwsTransferUser() *schema.Resource { ValidateFunc: validateIAMPolicyJson, DiffSuppressFunc: suppressEquivalentAwsPolicyDiffs, }, + "posix_profile": { + Type: schema.TypeList, + MaxItems: 1, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "gid": { + Type: schema.TypeInt, + Required: true, + }, + "uid": { + Type: schema.TypeInt, + Required: true, + }, + "secondary_gids": { + Type: schema.TypeSet, + Elem: &schema.Schema{Type: schema.TypeInt}, + Optional: true, + }, + }, + }, + }, "role": { Type: schema.TypeString, @@ -124,6 +147,10 @@ func resourceAwsTransferUserCreate(d *schema.ResourceData, meta interface{}) err createOpts.HomeDirectoryMappings = expandAwsTransferHomeDirectoryMappings(attr.([]interface{})) } + if attr, ok := d.GetOk("posix_profile"); ok { + createOpts.PosixProfile = expandTransferUserPosixUser(attr.([]interface{})) + } + if attr, ok := d.GetOk("policy"); ok { createOpts.Policy = aws.String(attr.(string)) } @@ -154,36 +181,34 @@ func resourceAwsTransferUserRead(d *schema.ResourceData, meta interface{}) error return fmt.Errorf("error parsing Transfer User ID: %s", err) } - descOpts := &transfer.DescribeUserInput{ - UserName: aws.String(userName), - ServerId: aws.String(serverID), + resp, err := finder.UserByID(conn, serverID, userName) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] Transfer User (%s) not found, removing from state", d.Id()) + d.SetId("") + return nil } - log.Printf("[DEBUG] Describe Transfer User Option: %#v", descOpts) - - resp, err := conn.DescribeUser(descOpts) if err != nil { - if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { - log.Printf("[WARN] Transfer User (%s) for Server (%s) not found, removing from state", userName, serverID) - d.SetId("") - return nil - } - return fmt.Errorf("error reading Transfer User (%s): %s", d.Id(), err) + return fmt.Errorf("error reading Transfer User (%s): %w", d.Id(), err) } + user := resp.User d.Set("server_id", resp.ServerId) - d.Set("user_name", resp.User.UserName) - d.Set("arn", resp.User.Arn) - d.Set("home_directory", resp.User.HomeDirectory) - d.Set("home_directory_type", resp.User.HomeDirectoryType) - d.Set("policy", resp.User.Policy) - d.Set("role", resp.User.Role) + d.Set("user_name", user.UserName) + d.Set("arn", user.Arn) + d.Set("home_directory", user.HomeDirectory) + d.Set("home_directory_type", user.HomeDirectoryType) + d.Set("policy", user.Policy) + d.Set("role", user.Role) - if err := d.Set("home_directory_mappings", flattenAwsTransferHomeDirectoryMappings(resp.User.HomeDirectoryMappings)); err != nil { - return fmt.Errorf("Error setting home_directory_mappings: %s", err) + if err := d.Set("home_directory_mappings", flattenAwsTransferHomeDirectoryMappings(user.HomeDirectoryMappings)); err != nil { + return fmt.Errorf("Error setting home_directory_mappings: %w", err) } - tags := keyvaluetags.TransferKeyValueTags(resp.User.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) + if err := d.Set("posix_profile", flattenTransferUserPosixUser(user.PosixProfile)); err != nil { + return fmt.Errorf("Error setting posix_profile: %w", err) + } + tags := keyvaluetags.TransferKeyValueTags(user.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { @@ -219,6 +244,11 @@ func resourceAwsTransferUserUpdate(d *schema.ResourceData, meta interface{}) err updateFlag = true } + if d.HasChange("posix_profile") { + updateOpts.PosixProfile = expandTransferUserPosixUser(d.Get("posix_profile").([]interface{})) + updateFlag = true + } + if d.HasChange("home_directory_type") { updateOpts.HomeDirectoryType = aws.String(d.Get("home_directory_type").(string)) updateFlag = true @@ -242,14 +272,14 @@ func resourceAwsTransferUserUpdate(d *schema.ResourceData, meta interface{}) err d.SetId("") return nil } - return fmt.Errorf("error updating Transfer User (%s): %s", d.Id(), err) + return fmt.Errorf("error updating Transfer User (%s): %w", d.Id(), err) } } if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") if err := keyvaluetags.TransferUpdateTags(conn, d.Get("arn").(string), o, n); err != nil { - return fmt.Errorf("error updating tags: %s", err) + return fmt.Errorf("error updating tags: %w", err) } } @@ -260,7 +290,7 @@ func resourceAwsTransferUserDelete(d *schema.ResourceData, meta interface{}) err conn := meta.(*AWSClient).transferconn serverID, userName, err := tftransfer.UserParseResourceID(d.Id()) if err != nil { - return fmt.Errorf("error parsing Transfer User ID: %s", err) + return fmt.Errorf("error parsing Transfer User ID: %w", err) } delOpts := &transfer.DeleteUserInput{ @@ -275,45 +305,15 @@ func resourceAwsTransferUserDelete(d *schema.ResourceData, meta interface{}) err if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { return nil } - return fmt.Errorf("error deleting Transfer User (%s) for Server(%s): %s", userName, serverID, err) + return fmt.Errorf("error deleting Transfer User (%s) for Server(%s): %w", userName, serverID, err) } - if err := waitForTransferUserDeletion(conn, serverID, userName); err != nil { - return fmt.Errorf("error waiting for Transfer User (%s) for Server (%s): %s", userName, serverID, err) - } - - return nil -} + _, err = waiter.UserDeleted(conn, serverID, userName) -func waitForTransferUserDeletion(conn *transfer.Transfer, serverID, userName string) error { - params := &transfer.DescribeUserInput{ - ServerId: aws.String(serverID), - UserName: aws.String(userName), - } - - err := resource.Retry(10*time.Minute, func() *resource.RetryError { - _, err := conn.DescribeUser(params) - - if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { - return nil - } - - if err != nil { - return resource.NonRetryableError(err) - } - - return resource.RetryableError(fmt.Errorf("Transfer User (%s) for Server (%s) still exists", userName, serverID)) - }) - - if isResourceTimeoutError(err) { - _, err = conn.DescribeUser(params) - } - if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { - return nil - } if err != nil { - return fmt.Errorf("Error decoding transfer user ID: %s", err) + return fmt.Errorf("error waiting for Transfer User (%s) delete: %w", d.Id(), err) } + return nil } @@ -344,3 +344,36 @@ func flattenAwsTransferHomeDirectoryMappings(mappings []*transfer.HomeDirectoryM } return l } + +func expandTransferUserPosixUser(pUser []interface{}) *transfer.PosixProfile { + if len(pUser) < 1 || pUser[0] == nil { + return nil + } + + m := pUser[0].(map[string]interface{}) + + posixUser := &transfer.PosixProfile{ + Gid: aws.Int64(int64(m["gid"].(int))), + Uid: aws.Int64(int64(m["uid"].(int))), + } + + if v, ok := m["secondary_gids"].(*schema.Set); ok && len(v.List()) > 0 { + posixUser.SecondaryGids = expandInt64Set(v) + } + + return posixUser +} + +func flattenTransferUserPosixUser(posixUser *transfer.PosixProfile) []interface{} { + if posixUser == nil { + return []interface{}{} + } + + m := map[string]interface{}{ + "gid": aws.Int64Value(posixUser.Gid), + "uid": aws.Int64Value(posixUser.Uid), + "secondary_gids": aws.Int64ValueSlice(posixUser.SecondaryGids), + } + + return []interface{}{m} +} diff --git a/aws/resource_aws_transfer_user_test.go b/aws/resource_aws_transfer_user_test.go index ff5567706f4..c92e735b503 100644 --- a/aws/resource_aws_transfer_user_test.go +++ b/aws/resource_aws_transfer_user_test.go @@ -5,16 +5,17 @@ import ( "regexp" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/transfer" "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/service/transfer/finder" + "github.com/terraform-providers/terraform-provider-aws/aws/internal/tfresource" ) func TestAccAWSTransferUser_basic(t *testing.T) { var conf transfer.DescribedUser - resourceName := "aws_transfer_user.foo" + resourceName := "aws_transfer_user.test" rName := acctest.RandString(10) resource.ParallelTest(t, resource.TestCase{ @@ -28,10 +29,9 @@ func TestAccAWSTransferUser_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferUserExists(resourceName, &conf), testAccMatchResourceAttrRegionalARN(resourceName, "arn", "transfer", regexp.MustCompile(`user/.+`)), - resource.TestCheckResourceAttrPair( - resourceName, "server_id", "aws_transfer_server.foo", "id"), - resource.TestCheckResourceAttrPair( - resourceName, "role", "aws_iam_role.foo", "arn"), + resource.TestCheckResourceAttrPair(resourceName, "server_id", "aws_transfer_server.test", "id"), + resource.TestCheckResourceAttrPair(resourceName, "role", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "posix_profile.#", "0"), ), }, { @@ -43,9 +43,48 @@ func TestAccAWSTransferUser_basic(t *testing.T) { }) } +func TestAccAWSTransferUser_posix(t *testing.T) { + var conf transfer.DescribedUser + resourceName := "aws_transfer_user.test" + rName := acctest.RandString(10) + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, + ErrorCheck: testAccErrorCheck(t, transfer.EndpointsID), + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSTransferUserDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSTransferUserConfigPosix(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferUserExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "posix_profile.#", "1"), + resource.TestCheckResourceAttr(resourceName, "posix_profile.0.gid", "1000"), + resource.TestCheckResourceAttr(resourceName, "posix_profile.0.uid", "1000"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAWSTransferUserConfigPosixUpdated(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSTransferUserExists(resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "posix_profile.#", "1"), + resource.TestCheckResourceAttr(resourceName, "posix_profile.0.gid", "1001"), + resource.TestCheckResourceAttr(resourceName, "posix_profile.0.uid", "1001"), + resource.TestCheckResourceAttr(resourceName, "posix_profile.0.secondary_gids.#", "2"), + ), + }, + }, + }) +} + func TestAccAWSTransferUser_modifyWithOptions(t *testing.T) { var conf transfer.DescribedUser - resourceName := "aws_transfer_user.foo" + resourceName := "aws_transfer_user.test" rName := acctest.RandString(10) rName2 := acctest.RandString(10) @@ -59,44 +98,31 @@ func TestAccAWSTransferUser_modifyWithOptions(t *testing.T) { Config: testAccAWSTransferUserConfig_options(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferUserExists(resourceName, &conf), - resource.TestCheckResourceAttr( - resourceName, "home_directory", "/home/tftestuser"), - resource.TestCheckResourceAttr( - resourceName, "tags.%", "3"), - resource.TestCheckResourceAttr( - resourceName, "tags.NAME", "tftestuser"), - resource.TestCheckResourceAttr( - resourceName, "tags.ENV", "test"), - resource.TestCheckResourceAttr( - resourceName, "tags.ADMIN", "test"), + resource.TestCheckResourceAttr(resourceName, "home_directory", "/home/tftestuser"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "3"), + resource.TestCheckResourceAttr(resourceName, "tags.NAME", "tftestuser"), + resource.TestCheckResourceAttr(resourceName, "tags.ENV", "test"), + resource.TestCheckResourceAttr(resourceName, "tags.ADMIN", "test"), ), }, { Config: testAccAWSTransferUserConfig_modify(rName2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferUserExists(resourceName, &conf), - resource.TestCheckResourceAttrPair( - resourceName, "role", "aws_iam_role.foo", "arn"), - resource.TestCheckResourceAttr( - resourceName, "home_directory", "/test"), - resource.TestCheckResourceAttr( - resourceName, "tags.%", "2"), - resource.TestCheckResourceAttr( - resourceName, "tags.NAME", "tf-test-user"), - resource.TestCheckResourceAttr( - resourceName, "tags.TEST", "test2"), + resource.TestCheckResourceAttrPair(resourceName, "role", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "home_directory", "/test"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.NAME", "tf-test-user"), + resource.TestCheckResourceAttr(resourceName, "tags.TEST", "test2"), ), }, { Config: testAccAWSTransferUserConfig_forceNew(rName2), Check: resource.ComposeTestCheckFunc( testAccCheckAWSTransferUserExists(resourceName, &conf), - resource.TestCheckResourceAttr( - resourceName, "user_name", "tftestuser2"), - resource.TestCheckResourceAttrPair( - resourceName, "role", "aws_iam_role.foo", "arn"), - resource.TestCheckResourceAttr( - resourceName, "home_directory", "/home/tftestuser2"), + resource.TestCheckResourceAttr(resourceName, "user_name", "tftestuser2"), + resource.TestCheckResourceAttrPair(resourceName, "role", "aws_iam_role.test", "arn"), + resource.TestCheckResourceAttr(resourceName, "home_directory", "/home/tftestuser2"), ), }, }, @@ -107,6 +133,7 @@ func TestAccAWSTransferUser_disappears(t *testing.T) { var serverConf transfer.DescribedServer var userConf transfer.DescribedUser rName := acctest.RandString(10) + resourceName := "aws_transfer_user.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, @@ -117,9 +144,9 @@ func TestAccAWSTransferUser_disappears(t *testing.T) { { Config: testAccAWSTransferUserConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckAWSTransferServerExists("aws_transfer_server.foo", &serverConf), - testAccCheckAWSTransferUserExists("aws_transfer_user.foo", &userConf), - testAccCheckAWSTransferUserDisappears(&serverConf, &userConf), + testAccCheckAWSTransferServerExists("aws_transfer_server.test", &serverConf), + testAccCheckAWSTransferUserExists("aws_transfer_user.test", &userConf), + testAccCheckResourceDisappears(testAccProvider, resourceAwsTransferUser(), resourceName), ), ExpectNonEmptyPlan: true, }, @@ -167,7 +194,7 @@ func TestAccAWSTransferUser_UserName_Validation(t *testing.T) { func TestAccAWSTransferUser_homeDirectoryMappings(t *testing.T) { var conf transfer.DescribedUser rName := acctest.RandString(10) - resourceName := "aws_transfer_user.foo" + resourceName := "aws_transfer_user.test" resource.ParallelTest(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) }, @@ -213,11 +240,7 @@ func testAccCheckAWSTransferUserExists(n string, res *transfer.DescribedUser) re userName := rs.Primary.Attributes["user_name"] serverID := rs.Primary.Attributes["server_id"] - describe, err := conn.DescribeUser(&transfer.DescribeUserInput{ - ServerId: aws.String(serverID), - UserName: aws.String(userName), - }) - + describe, err := finder.UserByID(conn, serverID, userName) if err != nil { return err } @@ -228,24 +251,6 @@ func testAccCheckAWSTransferUserExists(n string, res *transfer.DescribedUser) re } } -func testAccCheckAWSTransferUserDisappears(serverConf *transfer.DescribedServer, userConf *transfer.DescribedUser) resource.TestCheckFunc { - return func(s *terraform.State) error { - conn := testAccProvider.Meta().(*AWSClient).transferconn - - params := &transfer.DeleteUserInput{ - ServerId: serverConf.ServerId, - UserName: userConf.UserName, - } - - _, err := conn.DeleteUser(params) - if err != nil { - return err - } - - return waitForTransferUserDeletion(conn, *serverConf.ServerId, *userConf.UserName) - } -} - func testAccCheckAWSTransferUserDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).transferconn @@ -257,12 +262,8 @@ func testAccCheckAWSTransferUserDestroy(s *terraform.State) error { userName := rs.Primary.Attributes["user_name"] serverID := rs.Primary.Attributes["server_id"] - _, err := conn.DescribeUser(&transfer.DescribeUserInput{ - UserName: aws.String(userName), - ServerId: aws.String(serverID), - }) - - if isAWSErr(err, transfer.ErrCodeResourceNotFoundException, "") { + _, err := finder.UserByID(conn, serverID, userName) + if tfresource.NotFound(err) { continue } @@ -275,7 +276,7 @@ func testAccCheckAWSTransferUserDestroy(s *terraform.State) error { } const testAccAWSTransferUserConfig_base = ` -resource "aws_transfer_server" "foo" { +resource "aws_transfer_server" "test" { identity_provider_type = "SERVICE_MANAGED" tags = { @@ -288,7 +289,7 @@ data "aws_partition" "current" {} func testAccAWSTransferUserConfig_basic(rName string) string { return composeConfig(testAccAWSTransferUserConfig_base, fmt.Sprintf(` -resource "aws_iam_role" "foo" { +resource "aws_iam_role" "test" { name = "tf-test-transfer-user-iam-role-%[1]s" assume_role_policy = < Date: Mon, 7 Jun 2021 14:43:24 +0300 Subject: [PATCH 2/3] docs --- website/docs/r/transfer_user.html.markdown | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/website/docs/r/transfer_user.html.markdown b/website/docs/r/transfer_user.html.markdown index e54ed51a875..f011274e4ab 100644 --- a/website/docs/r/transfer_user.html.markdown +++ b/website/docs/r/transfer_user.html.markdown @@ -78,19 +78,27 @@ resource "aws_transfer_user" "foo" { The following arguments are supported: -* `server_id` - (Requirement) The Server ID of the Transfer Server (e.g. `s-12345678`) -* `user_name` - (Requirement) The name used for log in to your SFTP server. +* `server_id` - (Required) The Server ID of the Transfer Server (e.g. `s-12345678`) +* `user_name` - (Required) The name used for log in to your SFTP server. * `home_directory` - (Optional) The landing directory (folder) for a user when they log in to the server using their SFTP client. It should begin with a `/`. The first item in the path is the name of the home bucket (accessible as `${Transfer:HomeBucket}` in the policy) and the rest is the home directory (accessible as `${Transfer:HomeDirectory}` in the policy). For example, `/example-bucket-1234/username` would set the home bucket to `example-bucket-1234` and the home directory to `username`. -* `home_directory_mappings` - (Optional) Logical directory mappings that specify what S3 paths and keys should be visible to your user and how you want to make them visible. documented below. +* `home_directory_mappings` - (Optional) Logical directory mappings that specify what S3 paths and keys should be visible to your user and how you want to make them visible. See [Home Directory Mappings](#home-directory-mappings) below. * `home_directory_type` - (Optional) The type of landing directory (folder) you mapped for your users' home directory. Valid values are `PATH` and `LOGICAL`. * `policy` - (Optional) An IAM JSON policy document that scopes down user access to portions of their Amazon S3 bucket. IAM variables you can use inside this policy include `${Transfer:UserName}`, `${Transfer:HomeDirectory}`, and `${Transfer:HomeBucket}`. Since the IAM variable syntax matches Terraform's interpolation syntax, they must be escaped inside Terraform configuration strings (`$${Transfer:UserName}`). These are evaluated on-the-fly when navigating the bucket. -* `role` - (Requirement) Amazon Resource Name (ARN) of an IAM role that allows the service to controls your user’s access to your Amazon S3 bucket. +* `posix_profile` - (Optional) Specifies the full POSIX identity, including user ID (Uid), group ID (Gid), and any secondary groups IDs (SecondaryGids), that controls your users' access to your Amazon EFS file systems. See [Posix Profile](#posix-profile) below. +* `role` - (Required) Amazon Resource Name (ARN) of an IAM role that allows the service to controls your user’s access to your Amazon S3 bucket. * `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. -Home Directory Mappings (`home_directory_mappings`) support the following: -* `entry` - (Requirement) Represents an entry and a target. -* `target` - (Requirement) Represents the map target. +### Home Directory Mappings + +* `entry` - (Required) Represents an entry and a target. +* `target` - (Required) Represents the map target. + +### Posix Profile + +* `gid` - (Required) The POSIX group ID used for all EFS operations by this user. +* `uid` - (Required) The POSIX user ID used for all EFS operations by this user. +* `secondary_gids` - (Optional) The secondary POSIX group IDs used for all EFS operations by this user. ## Attributes Reference In addition to all arguments above, the following attributes are exported: From 174d62e82c6ea5ed2104289ddb4839fd2ae8e996 Mon Sep 17 00:00:00 2001 From: drfaust92 Date: Mon, 7 Jun 2021 14:54:33 +0300 Subject: [PATCH 3/3] changelog --- .changelog/19693.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/19693.txt diff --git a/.changelog/19693.txt b/.changelog/19693.txt new file mode 100644 index 00000000000..4a1fe974b82 --- /dev/null +++ b/.changelog/19693.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_transfer_user: Add `posix_profile` argument. +``` \ No newline at end of file