Skip to content

Commit

Permalink
resource/aws_ecs_task_definition: Support EFS Access Points and Trans…
Browse files Browse the repository at this point in the history
…it Encryption (#13136)

Output from acceptance testing:

```
--- PASS: TestAccAWSEcsTaskDefinition_arrays (20.05s)
--- PASS: TestAccAWSEcsTaskDefinition_basic (33.04s)
--- PASS: TestAccAWSEcsTaskDefinition_changeVolumesForcesNewResource (32.93s)
--- PASS: TestAccAWSEcsTaskDefinition_constraint (20.00s)
--- PASS: TestAccAWSEcsTaskDefinition_ExecutionRole (20.53s)
--- PASS: TestAccAWSEcsTaskDefinition_Fargate (27.83s)
--- PASS: TestAccAWSEcsTaskDefinition_Inactive (35.23s)
--- PASS: TestAccAWSEcsTaskDefinition_inferenceAccelerator (20.16s)
--- PASS: TestAccAWSEcsTaskDefinition_ProxyConfiguration (32.37s)
--- PASS: TestAccAWSEcsTaskDefinition_Tags (53.63s)
--- PASS: TestAccAWSEcsTaskDefinition_withDockerVolume (19.53s)
--- PASS: TestAccAWSEcsTaskDefinition_withDockerVolumeMinimalConfig (19.77s)
--- PASS: TestAccAWSEcsTaskDefinition_withEcsService (55.57s)
--- PASS: TestAccAWSEcsTaskDefinition_withEFSAccessPoint (36.35s)
--- PASS: TestAccAWSEcsTaskDefinition_withEFSVolume (32.50s)
--- PASS: TestAccAWSEcsTaskDefinition_withEFSVolumeMinimal (32.62s)
--- PASS: TestAccAWSEcsTaskDefinition_withIPCMode (20.97s)
--- PASS: TestAccAWSEcsTaskDefinition_withNetworkMode (20.95s)
--- PASS: TestAccAWSEcsTaskDefinition_withPidMode (20.92s)
--- PASS: TestAccAWSEcsTaskDefinition_withScratchVolume (19.86s)
--- PASS: TestAccAWSEcsTaskDefinition_withTaskRoleArn (19.80s)
--- PASS: TestAccAWSEcsTaskDefinition_withTaskScopedDockerVolume (20.78s)
--- PASS: TestAccAWSEcsTaskDefinition_withTransitEncryptionEFSVolume (32.56s)
```
  • Loading branch information
jukie authored Jun 24, 2020
1 parent 2a70310 commit a6d8095
Show file tree
Hide file tree
Showing 4 changed files with 258 additions and 4 deletions.
56 changes: 56 additions & 0 deletions aws/resource_aws_ecs_task_definition.go
Original file line number Diff line number Diff line change
Expand Up @@ -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),
},
},
},
},
},
},
},
Expand Down Expand Up @@ -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())
Expand Down
138 changes: 138 additions & 0 deletions aws/resource_aws_ecs_task_definition_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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 = <<TASK_DEFINITION
[
{
"name": "sleep",
"image": "busybox",
"cpu": 10,
"command": ["sleep","360"],
"memory": 10,
"essential": true
}
]
TASK_DEFINITION
volume {
name = %[1]q
efs_volume_configuration {
file_system_id = "${aws_efs_file_system.test.id}"
root_directory = "/home/test"
transit_encryption = %[2]q
transit_encryption_port = %[3]d
}
}
}
`, tdName, tEnc, tEncPort)
}

func testAccAWSEcsTaskDefinitionWithEFSAccessPoint(tdName, useIam string) string {
return fmt.Sprintf(`
resource "aws_efs_file_system" "test" {
creation_token = %[1]q
}
resource "aws_efs_access_point" "test" {
file_system_id = "${aws_efs_file_system.test.id}"
posix_user {
gid = 1001
uid = 1001
}
}
resource "aws_ecs_task_definition" "test" {
family = %[1]q
container_definitions = <<TASK_DEFINITION
[
{
"name": "sleep",
"image": "busybox",
"cpu": 10,
"command": ["sleep","360"],
"memory": 10,
"essential": true
}
]
TASK_DEFINITION
volume {
name = %[1]q
efs_volume_configuration {
file_system_id = "${aws_efs_file_system.test.id}"
transit_encryption = "ENABLED"
transit_encryption_port = 2999
authorization_config {
access_point_id = "${aws_efs_access_point.test.id}"
iam = %[2]q
}
}
}
}
`, tdName, useIam)
}
func testAccAWSEcsTaskDefinitionWithTaskRoleArn(roleName, policyName, tdName string) string {
return fmt.Sprintf(`
resource "aws_iam_role" "test" {
Expand Down
48 changes: 48 additions & 0 deletions aws/structure.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,27 @@ func expandEcsVolumes(configured []interface{}) []*ecs.Volume {
if v, ok := config["root_directory"].(string); ok && v != "" {
l.EfsVolumeConfiguration.RootDirectory = aws.String(v)
}
if v, ok := config["transit_encryption"].(string); ok && v != "" {
l.EfsVolumeConfiguration.TransitEncryption = aws.String(v)
}

if v, ok := config["transit_encryption_port"].(int); ok && v > 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)
Expand Down Expand Up @@ -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)
Expand Down
20 changes: 16 additions & 4 deletions website/docs/r/ecs_task_definition.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -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.
Expand Down

0 comments on commit a6d8095

Please sign in to comment.