Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

resource/aws_transfer_user: add home_directory_type and home_directory_mappings arguments #13591

Merged
merged 2 commits into from
Sep 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions aws/resource_aws_transfer_user.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,32 @@ func resourceAwsTransferUser() *schema.Resource {
ValidateFunc: validation.StringLenBetween(0, 1024),
},

"home_directory_mappings": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"entry": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(0, 1024),
},
"target": {
Type: schema.TypeString,
Required: true,
ValidateFunc: validation.StringLenBetween(0, 1024),
},
},
},
},

"home_directory_type": {
Type: schema.TypeString,
Optional: true,
Default: transfer.HomeDirectoryTypePath,
ValidateFunc: validation.StringInSlice([]string{transfer.HomeDirectoryTypePath, transfer.HomeDirectoryTypeLogical}, false),
},

"policy": {
Type: schema.TypeString,
Optional: true,
Expand Down Expand Up @@ -84,6 +110,14 @@ func resourceAwsTransferUserCreate(d *schema.ResourceData, meta interface{}) err
createOpts.HomeDirectory = aws.String(attr.(string))
}

if attr, ok := d.GetOk("home_directory_type"); ok {
createOpts.HomeDirectoryType = aws.String(attr.(string))
}

if attr, ok := d.GetOk("home_directory_mappings"); ok {
createOpts.HomeDirectoryMappings = expandAwsTransferHomeDirectoryMappings(attr.([]interface{}))
}

if attr, ok := d.GetOk("policy"); ok {
createOpts.Policy = aws.String(attr.(string))
}
Expand Down Expand Up @@ -134,9 +168,14 @@ func resourceAwsTransferUserRead(d *schema.ResourceData, meta interface{}) error
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)

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("tags", keyvaluetags.TransferKeyValueTags(resp.User.Tags).IgnoreAws().IgnoreConfig(ignoreTagsConfig).Map()); err != nil {
return fmt.Errorf("Error setting tags: %s", err)
}
Expand All @@ -161,6 +200,16 @@ func resourceAwsTransferUserUpdate(d *schema.ResourceData, meta interface{}) err
updateFlag = true
}

if d.HasChange("home_directory_mappings") {
updateOpts.HomeDirectoryMappings = expandAwsTransferHomeDirectoryMappings(d.Get("home_directory_mappings").([]interface{}))
updateFlag = true
}

if d.HasChange("home_directory_type") {
updateOpts.HomeDirectoryType = aws.String(d.Get("home_directory_type").(string))
updateFlag = true
}

if d.HasChange("policy") {
updateOpts.Policy = aws.String(d.Get("policy").(string))
updateFlag = true
Expand Down Expand Up @@ -261,3 +310,31 @@ func waitForTransferUserDeletion(conn *transfer.Transfer, serverID, userName str
}
return nil
}

func expandAwsTransferHomeDirectoryMappings(in []interface{}) []*transfer.HomeDirectoryMapEntry {
mappings := make([]*transfer.HomeDirectoryMapEntry, 0)

for _, tConfig := range in {
config := tConfig.(map[string]interface{})

m := &transfer.HomeDirectoryMapEntry{
Entry: aws.String(config["entry"].(string)),
Target: aws.String(config["target"].(string)),
}

mappings = append(mappings, m)
}

return mappings
}

func flattenAwsTransferHomeDirectoryMappings(mappings []*transfer.HomeDirectoryMapEntry) []interface{} {
l := make([]interface{}, len(mappings))
for i, m := range mappings {
l[i] = map[string]interface{}{
"entry": aws.StringValue(m.Entry),
"target": aws.StringValue(m.Target),
}
}
return l
}
196 changes: 162 additions & 34 deletions aws/resource_aws_transfer_user_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,40 @@ 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"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t); testAccPreCheckAWSTransfer(t) },
IDRefreshName: resourceName,
Providers: testAccProviders,
CheckDestroy: testAccCheckAWSTransferUserDestroy,
Steps: []resource.TestStep{
{
Config: testAccAWSTransferUserConfig_homeDirectoryMappings(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSTransferUserExists(resourceName, &conf),
resource.TestCheckResourceAttr(resourceName, "home_directory_mappings.#", "1"),
),
},
{
Config: testAccAWSTransferUserConfig_homeDirectoryMappingsUpdate(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckAWSTransferUserExists(resourceName, &conf),
resource.TestCheckResourceAttr(resourceName, "home_directory_mappings.#", "2"),
),
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

func testAccCheckAWSTransferUserExists(n string, res *transfer.DescribedUser) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
Expand Down Expand Up @@ -233,15 +267,18 @@ func testAccCheckAWSTransferUserDestroy(s *terraform.State) error {
return nil
}

func testAccAWSTransferUserConfig_basic(rName string) string {
return fmt.Sprintf(`
const testAccAWSTransferUserConfig_base = `
resource "aws_transfer_server" "foo" {
identity_provider_type = "SERVICE_MANAGED"

tags = {
NAME = "tf-acc-test-transfer-server"
}
}
`

func testAccAWSTransferUserConfig_basic(rName string) string {
return testAccAWSTransferUserConfig_base + fmt.Sprintf(`

resource "aws_iam_role" "foo" {
name = "tf-test-transfer-user-iam-role-%s"
Expand Down Expand Up @@ -292,14 +329,7 @@ resource "aws_transfer_user" "foo" {
}

func testAccAWSTransferUserName_validation(rName string) string {
return fmt.Sprintf(`
resource "aws_transfer_server" "foo" {
identity_provider_type = "SERVICE_MANAGED"

tags = {
NAME = "tf-acc-test-transfer-server"
}
}
return testAccAWSTransferUserConfig_base + fmt.Sprintf(`

resource "aws_transfer_user" "foo" {
server_id = "${aws_transfer_server.foo.id}"
Expand Down Expand Up @@ -329,14 +359,7 @@ EOF
}

func testAccAWSTransferUserConfig_options(rName string) string {
return fmt.Sprintf(`
resource "aws_transfer_server" "foo" {
identity_provider_type = "SERVICE_MANAGED"

tags = {
NAME = "tf-acc-test-transfer-server"
}
}
return testAccAWSTransferUserConfig_base + fmt.Sprintf(`

resource "aws_iam_role" "foo" {
name = "tf-test-transfer-user-iam-role-%s"
Expand Down Expand Up @@ -438,14 +461,7 @@ resource "aws_transfer_user" "foo" {
}

func testAccAWSTransferUserConfig_modify(rName string) string {
return fmt.Sprintf(`
resource "aws_transfer_server" "foo" {
identity_provider_type = "SERVICE_MANAGED"

tags = {
NAME = "tf-acc-test-transfer-server"
}
}
return testAccAWSTransferUserConfig_base + fmt.Sprintf(`

resource "aws_iam_role" "foo" {
name = "tf-test-transfer-user-iam-role-%s"
Expand Down Expand Up @@ -544,14 +560,7 @@ resource "aws_transfer_user" "foo" {
}

func testAccAWSTransferUserConfig_forceNew(rName string) string {
return fmt.Sprintf(`
resource "aws_transfer_server" "foo" {
identity_provider_type = "SERVICE_MANAGED"

tags = {
NAME = "tf-acc-test-transfer-server"
}
}
return testAccAWSTransferUserConfig_base + fmt.Sprintf(`

resource "aws_iam_role" "foo" {
name = "tf-test-transfer-user-iam-role-%s"
Expand Down Expand Up @@ -650,3 +659,122 @@ resource "aws_transfer_user" "foo" {
}
`, rName, rName)
}

func testAccAWSTransferUserConfig_homeDirectoryMappings(rName string) string {
return testAccAWSTransferUserConfig_base + fmt.Sprintf(`

resource "aws_iam_role" "foo" {
name = "tf-test-transfer-user-iam-role-%s"

assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "transfer.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}

resource "aws_iam_role_policy" "foo" {
name = "tf-test-transfer-user-iam-policy-%s"
role = "${aws_iam_role.foo.id}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: We are now using Terraform 0.12+ syntax in test configurations, will adjust on merge. 👍


policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowFullAccesstoS3",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": "*"
}
]
}
POLICY
}

resource "aws_transfer_user" "foo" {
server_id = "${aws_transfer_server.foo.id}"
user_name = "tftestuser"
role = "${aws_iam_role.foo.arn}"
home_directory_type = "LOGICAL"

home_directory_mappings {
entry = "/your-personal-report.pdf"
target = "/bucket3/customized-reports/tftestuser.pdf"
}
}
`, rName, rName)
}

func testAccAWSTransferUserConfig_homeDirectoryMappingsUpdate(rName string) string {
return testAccAWSTransferUserConfig_base + fmt.Sprintf(`

resource "aws_iam_role" "foo" {
name = "tf-test-transfer-user-iam-role-%s"

assume_role_policy = <<EOF
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "transfer.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
EOF
}

resource "aws_iam_role_policy" "foo" {
name = "tf-test-transfer-user-iam-policy-%s"
role = "${aws_iam_role.foo.id}"

policy = <<POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AllowFullAccesstoS3",
"Effect": "Allow",
"Action": [
"s3:*"
],
"Resource": "*"
}
]
}
POLICY
}

resource "aws_transfer_user" "foo" {
server_id = "${aws_transfer_server.foo.id}"
user_name = "tftestuser"
role = "${aws_iam_role.foo.arn}"
home_directory_type = "LOGICAL"

home_directory_mappings {
entry = "/your-personal-report.pdf"
target = "/bucket3/customized-reports/tftestuser.pdf"
}

home_directory_mappings {
entry = "/your-personal-report2.pdf"
target = "/bucket3/customized-reports2/tftestuser.pdf"
}
}
`, rName, rName)
}
7 changes: 7 additions & 0 deletions website/docs/r/transfer_user.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,17 @@ 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.
* `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_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.
* `tags` - (Optional) A map of tags to assign to the resource.

Home Directory Mappings (`home_directory_mappings`) support the following:

* `entry` - (Requirement) Represents an entry and a target.
* `target` - (Requirement) Represents the map target.

## Attributes Reference
In addition to all arguments above, the following attributes are exported:

Expand Down