diff --git a/aws/resource_aws_ecs_task_definition.go b/aws/resource_aws_ecs_task_definition.go index 0eecaee729e7..637bc55b4848 100644 --- a/aws/resource_aws_ecs_task_definition.go +++ b/aws/resource_aws_ecs_task_definition.go @@ -198,6 +198,45 @@ func resourceAwsEcsTaskDefinition() *schema.Resource { Optional: true, Default: "/", }, + "transit_encryption": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + ecs.EFSTransitEncryptionEnabled, + ecs.EFSTransitEncryptionDisabled, + }, false), + }, + "transit_encryption_port": { + Type: schema.TypeInt, + ForceNew: true, + Optional: true, + ValidateFunc: validation.IsPortNumber, + }, + "authorization_config": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_point_id": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + }, + "iam": { + Type: schema.TypeString, + ForceNew: true, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + ecs.EFSAuthorizationConfigIAMEnabled, + ecs.EFSAuthorizationConfigIAMDisabled, + }, false), + }, + }, + }, + }, }, }, }, @@ -598,6 +637,23 @@ func resourceAwsEcsTaskDefinitionVolumeHash(v interface{}) int { if v, ok := m["root_directory"]; ok && v.(string) != "" { buf.WriteString(fmt.Sprintf("%s-", v.(string))) } + + if v, ok := m["transit_encryption"]; ok && v.(string) != "" { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + if v, ok := m["transit_encryption_port"]; ok && v.(int) > 0 { + buf.WriteString(fmt.Sprintf("%d-", v.(int))) + } + if v, ok := m["authorization_config"]; ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + m := v.([]interface{})[0].(map[string]interface{}) + if v, ok := m["access_point_id"]; ok && v.(string) != "" { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + if v, ok := m["iam"]; ok && v.(string) != "" { + buf.WriteString(fmt.Sprintf("%s-", v.(string))) + } + } + } return hashcode.String(buf.String()) diff --git a/aws/resource_aws_ecs_task_definition_test.go b/aws/resource_aws_ecs_task_definition_test.go index 38a9c18829cd..7c41848b8051 100644 --- a/aws/resource_aws_ecs_task_definition_test.go +++ b/aws/resource_aws_ecs_task_definition_test.go @@ -244,6 +244,61 @@ func TestAccAWSEcsTaskDefinition_withEFSVolume(t *testing.T) { }) } +func TestAccAWSEcsTaskDefinition_withTransitEncryptionEFSVolume(t *testing.T) { + var def ecs.TaskDefinition + + tdName := acctest.RandomWithPrefix("tf-acc-td-with-efs-volume") + resourceName := "aws_ecs_task_definition.test" + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEcsTaskDefinitionWithTransitEncryptionEFSVolume(tdName, "ENABLED", 2999), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEcsTaskDefinitionExists(resourceName, &def), + resource.TestCheckResourceAttr(resourceName, "volume.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAWSEcsTaskDefinitionImportStateIdFunc(resourceName), + ImportStateVerify: true, + }, + }, + }) +} + +func TestAccAWSEcsTaskDefinition_withEFSAccessPoint(t *testing.T) { + var def ecs.TaskDefinition + + tdName := acctest.RandomWithPrefix("tf-acc-td-with-efs-volume") + resourceName := "aws_ecs_task_definition.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckAWSEcsTaskDefinitionDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAWSEcsTaskDefinitionWithEFSAccessPoint(tdName, "DISABLED"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAWSEcsTaskDefinitionExists(resourceName, &def), + resource.TestCheckResourceAttr(resourceName, "volume.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateIdFunc: testAccAWSEcsTaskDefinitionImportStateIdFunc(resourceName), + ImportStateVerify: true, + }, + }, + }) +} + func TestAccAWSEcsTaskDefinition_withTaskScopedDockerVolume(t *testing.T) { var def ecs.TaskDefinition @@ -1506,6 +1561,89 @@ TASK_DEFINITION `, tdName, rDir) } +func testAccAWSEcsTaskDefinitionWithTransitEncryptionEFSVolume(tdName, tEnc string, tEncPort int) string { + return fmt.Sprintf(` +resource "aws_efs_file_system" "test" { + creation_token = %[1]q +} + +resource "aws_ecs_task_definition" "test" { + family = %[1]q + + container_definitions = < 0 { + l.EfsVolumeConfiguration.TransitEncryptionPort = aws.Int64(int64(v)) + } + authConfig, ok := config["authorization_config"].([]interface{}) + if ok && len(authConfig) > 0 { + authconfig := authConfig[0].(map[string]interface{}) + l.EfsVolumeConfiguration.RootDirectory = nil + l.EfsVolumeConfiguration.AuthorizationConfig = &ecs.EFSAuthorizationConfig{} + + if v, ok := authconfig["access_point_id"].(string); ok && v != "" { + l.EfsVolumeConfiguration.AuthorizationConfig.AccessPointId = aws.String(v) + } + + if v, ok := authconfig["iam"].(string); ok && v != "" { + l.EfsVolumeConfiguration.AuthorizationConfig.Iam = aws.String(v) + } + } } volumes = append(volumes, l) @@ -748,6 +769,33 @@ func flattenEFSVolumeConfiguration(config *ecs.EFSVolumeConfiguration) []interfa if v := config.RootDirectory; v != nil { m["root_directory"] = aws.StringValue(v) } + if v := config.TransitEncryption; v != nil { + m["transit_encryption"] = aws.StringValue(v) + } + + if v := config.TransitEncryptionPort; v != nil { + m["transit_encryption_port"] = int(aws.Int64Value(v)) + } + + if v := config.AuthorizationConfig; v != nil { + m["authorization_config"] = flattenEFSVolumeAuthorizationConfig(v) + } + } + + items = append(items, m) + return items +} + +func flattenEFSVolumeAuthorizationConfig(config *ecs.EFSAuthorizationConfig) []interface{} { + var items []interface{} + m := make(map[string]interface{}) + if config != nil { + if v := config.AccessPointId; v != nil { + m["access_point_id"] = aws.StringValue(v) + } + if v := config.Iam; v != nil { + m["iam"] = aws.StringValue(v) + } } items = append(items, m) diff --git a/website/docs/r/ecs_task_definition.html.markdown b/website/docs/r/ecs_task_definition.html.markdown index 30f6b42377af..7b29327d748a 100644 --- a/website/docs/r/ecs_task_definition.html.markdown +++ b/website/docs/r/ecs_task_definition.html.markdown @@ -159,10 +159,15 @@ resource "aws_ecs_task_definition" "service" { #### EFS Volume Configuration Arguments -For more information, see [Specifying an EFS volume in your Task Definition Developer Guide](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/using_efs.html) +For more information, see [Specifying an EFS volume in your Task Definition Developer Guide](https://docs.aws.amazon.com/AmazonECS/latest/developerguide/efs-volumes.html#specify-efs-config) * `file_system_id` - (Required) The ID of the EFS File System. -* `root_directory` - (Optional) The path to mount on the host +* `root_directory` - (Optional) The directory within the Amazon EFS file system to mount as the root directory inside the host. If this parameter is omitted, the root of the Amazon EFS volume will be used. Specifying / will have the same effect as omitting this parameter. This argument is ignored when using `authorization_config`. +* `transit_encryption` - (Optional) Whether or not to enable encryption for Amazon EFS data in transit between the Amazon ECS host and the Amazon EFS server. Transit encryption must be enabled if Amazon EFS IAM authorization is used. Valid values: `ENABLED`, `DISABLED`. If this parameter is omitted, the default value of `DISABLED` is used. +* `transit_encryption_port` - (Optional) The port to use for transit encryption. If you do not specify a transit encryption port, it will use the port selection strategy that the Amazon EFS mount helper uses. +* `authorization_config` - (Optional) The authorization configuration details for the Amazon EFS file system. + * `access_point_id` - The access point ID to use. If an access point is specified, the root directory value will be relative to the directory set for the access point. If specified, transit encryption must be enabled in the EFSVolumeConfiguration. + * `iam` - Whether or not to use the Amazon ECS task IAM role defined in a task definition when mounting the Amazon EFS file system. If enabled, transit encryption must be enabled in the EFSVolumeConfiguration. Valid values: `ENABLED`, `DISABLED`. If this parameter is omitted, the default value of `DISABLED` is used. ##### Example Usage @@ -175,13 +180,20 @@ resource "aws_ecs_task_definition" "service" { name = "service-storage" efs_volume_configuration { - file_system_id = aws_efs_file_system.fs.id - root_directory = "/opt/data" + file_system_id = aws_efs_file_system.fs.id + root_directory = "/opt/data" + transit_encryption = "ENABLED" + transit_encryption_port = 2999 + authorization_config { + access_point_id = aws_efs_access_point.test.id + iam = "ENABLED" + } } } } ``` + #### Placement Constraints Arguments * `type` - (Required) The type of constraint. Use `memberOf` to restrict selection to a group of valid candidates.