From 566e59cea3985e962c76af88ba1b34c68bd9735c Mon Sep 17 00:00:00 2001 From: Daniel Rieske Date: Sat, 21 Oct 2023 18:38:16 +0200 Subject: [PATCH 1/8] feat: added ipv6_allowed_for_dual_stack field --- internal/acctest/acctest.go | 122 +++++++++++++++++++ internal/service/lambda/flex.go | 1 + internal/service/lambda/function.go | 30 +++-- internal/service/lambda/function_test.go | 76 ++++++++++++ website/docs/r/lambda_function.html.markdown | 3 +- 5 files changed, 221 insertions(+), 11 deletions(-) diff --git a/internal/acctest/acctest.go b/internal/acctest/acctest.go index 9f151c73a12..0795a2c5c68 100644 --- a/internal/acctest/acctest.go +++ b/internal/acctest/acctest.go @@ -2229,6 +2229,128 @@ resource "aws_security_group" "sg_for_lambda" { `, policyName, roleName, sgName)) } +func ConfigLambdaDualStackBase(policyName, roleName, sgName string, subnetCount int) string { + return ConfigCompose(ConfigAvailableAZsNoOptIn(), fmt.Sprintf(` +data "aws_partition" "current" {} + +resource "aws_iam_role_policy" "iam_policy_for_lambda" { + name = "%s" + role = aws_iam_role.iam_for_lambda.id + + policy = < 0 && v.([]interface{})[0] != nil { tfMap := v.([]interface{})[0].(map[string]interface{}) input.VpcConfig = &types.VpcConfig{ - SecurityGroupIds: flex.ExpandStringValueSet(tfMap["security_group_ids"].(*schema.Set)), - SubnetIds: flex.ExpandStringValueSet(tfMap["subnet_ids"].(*schema.Set)), + Ipv6AllowedForDualStack: aws.Bool(tfMap["ipv6_allowed_for_dual_stack"].(bool)), + SecurityGroupIds: flex.ExpandStringValueSet(tfMap["security_group_ids"].(*schema.Set)), + SubnetIds: flex.ExpandStringValueSet(tfMap["subnet_ids"].(*schema.Set)), } } @@ -849,17 +856,19 @@ func resourceFunctionUpdate(ctx context.Context, d *schema.ResourceData, meta in } } - if d.HasChanges("vpc_config.0.security_group_ids", "vpc_config.0.subnet_ids") { + if d.HasChanges("vpc_config.0.security_group_ids", "vpc_config.0.subnet_ids", "vpc_config.0.ipv6_allowed_for_dual_stack") { if v, ok := d.GetOk("vpc_config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { tfMap := v.([]interface{})[0].(map[string]interface{}) input.VpcConfig = &types.VpcConfig{ - SecurityGroupIds: flex.ExpandStringValueSet(tfMap["security_group_ids"].(*schema.Set)), - SubnetIds: flex.ExpandStringValueSet(tfMap["subnet_ids"].(*schema.Set)), + Ipv6AllowedForDualStack: aws.Bool(tfMap["ipv6_allowed_for_dual_stack"].(bool)), + SecurityGroupIds: flex.ExpandStringValueSet(tfMap["security_group_ids"].(*schema.Set)), + SubnetIds: flex.ExpandStringValueSet(tfMap["subnet_ids"].(*schema.Set)), } } else { input.VpcConfig = &types.VpcConfig{ - SecurityGroupIds: []string{}, - SubnetIds: []string{}, + Ipv6AllowedForDualStack: aws.Bool(false), + SecurityGroupIds: []string{}, + SubnetIds: []string{}, } } } @@ -1250,6 +1259,7 @@ func needsFunctionConfigUpdate(d verify.ResourceDiffer) bool { d.HasChange("dead_letter_config") || d.HasChange("snap_start") || d.HasChange("tracing_config") || + d.HasChange("vpc_config.0.ipv6_allowed_for_dual_stack") || d.HasChange("vpc_config.0.security_group_ids") || d.HasChange("vpc_config.0.subnet_ids") || d.HasChange("runtime") || diff --git a/internal/service/lambda/function_test.go b/internal/service/lambda/function_test.go index 6142bcabf19..cc226d28394 100644 --- a/internal/service/lambda/function_test.go +++ b/internal/service/lambda/function_test.go @@ -2161,6 +2161,43 @@ func TestAccLambdaFunction_Zip_validation(t *testing.T) { }) } +func TestAccLambdaFunction_ipv6AllowedForDualStack(t *testing.T) { + ctx := acctest.Context(t) + var conf lambda.GetFunctionOutput + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_lambda_function.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.LambdaEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckFunctionDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccFunctionConfig_ipv6AllowedForDualStackDisabled(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckFunctionExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "1"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"filename", "publish"}, + }, + { + Config: testAccFunctionConfig_ipv6AllowedForDualStackEnabled(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckFunctionExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, "vpc_config.#", "1"), + resource.TestCheckResourceAttr(resourceName, "vpc_config.0.ipv6_allowed_for_dual_stack", "true"), + ), + }, + }, + }) +} + func TestAccLambdaFunction_skipDestroy(t *testing.T) { ctx := acctest.Context(t) var conf lambda.GetFunctionOutput @@ -3869,6 +3906,45 @@ resource "aws_lambda_function" "test" { `, rName)) } +func testAccFunctionConfig_ipv6AllowedForDualStackDisabled(rName string) string { + return acctest.ConfigCompose( + acctest.ConfigLambdaDualStackBase(rName, rName, rName, 1), + fmt.Sprintf(` +resource "aws_lambda_function" "test" { + filename = "test-fixtures/lambdatest.zip" + function_name = %[1]q + role = aws_iam_role.iam_for_lambda.arn + handler = "exports.example" + runtime = "nodejs16.x" + + vpc_config { + subnet_ids = [aws_subnet.subnet_for_lambda[0].id] + security_group_ids = [aws_security_group.sg_for_lambda.id] + } +} +`, rName)) +} + +func testAccFunctionConfig_ipv6AllowedForDualStackEnabled(rName string) string { + return acctest.ConfigCompose( + acctest.ConfigLambdaDualStackBase(rName, rName, rName, 1), + fmt.Sprintf(` +resource "aws_lambda_function" "test" { + filename = "test-fixtures/lambdatest.zip" + function_name = %[1]q + role = aws_iam_role.iam_for_lambda.arn + handler = "exports.example" + runtime = "nodejs16.x" + + vpc_config { + ipv6_allowed_for_dual_stack = true + subnet_ids = [aws_subnet.subnet_for_lambda[0].id] + security_group_ids = [aws_security_group.sg_for_lambda.id] + } +} +`, rName)) +} + func testAccFunctionConfig_skipDestroy(rName string) string { return acctest.ConfigCompose(acctest.ConfigLambdaBase(rName, rName, rName), fmt.Sprintf(` resource "aws_lambda_function" "test" { diff --git a/website/docs/r/lambda_function.html.markdown b/website/docs/r/lambda_function.html.markdown index 0df5d4a33cc..c4cbcca76ad 100644 --- a/website/docs/r/lambda_function.html.markdown +++ b/website/docs/r/lambda_function.html.markdown @@ -331,8 +331,9 @@ Snap start settings for low-latency startups. This feature is currently only sup For network connectivity to AWS resources in a VPC, specify a list of security groups and subnets in the VPC. When you connect a function to a VPC, it can only access resources and the internet through that VPC. See [VPC Settings][7]. -~> **NOTE:** If both `subnet_ids` and `security_group_ids` are empty then `vpc_config` is considered to be empty or unset. +~> **NOTE:** If `subnet_ids`, `security_group_ids` and `ipv6_allowed_for_dual_stack` are empty then `vpc_config` is considered to be empty or unset. +* `ipv6_allowed_for_dual_stack` - (Optional) Allows outbound IPv6 traffic on VPC functions that are connected to dual-stack subnets. Default is `false`. * `security_group_ids` - (Required) List of security group IDs associated with the Lambda function. * `subnet_ids` - (Required) List of subnet IDs associated with the Lambda function. From f507f842fb6a4ed3c0f2ac8f989b1f45c43344eb Mon Sep 17 00:00:00 2001 From: Daniel Rieske Date: Sat, 21 Oct 2023 19:08:19 +0200 Subject: [PATCH 2/8] chore: added changelog --- .changelog/34045.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/34045.txt diff --git a/.changelog/34045.txt b/.changelog/34045.txt new file mode 100644 index 00000000000..b7c1ea91298 --- /dev/null +++ b/.changelog/34045.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_lambda_function: Added `ipv6_allowed_for_dual_stack` field to support outbound ipv6 traffic on dual-stack subnets +``` From 74f6fdbd7237c4417b265d6d2b5030f3d9aa98cd Mon Sep 17 00:00:00 2001 From: Daniel Rieske Date: Sat, 21 Oct 2023 19:10:48 +0200 Subject: [PATCH 3/8] chore: fixed fmt --- internal/service/lambda/function_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/service/lambda/function_test.go b/internal/service/lambda/function_test.go index cc226d28394..b1d514dbdf0 100644 --- a/internal/service/lambda/function_test.go +++ b/internal/service/lambda/function_test.go @@ -3937,7 +3937,7 @@ resource "aws_lambda_function" "test" { runtime = "nodejs16.x" vpc_config { - ipv6_allowed_for_dual_stack = true + ipv6_allowed_for_dual_stack = true subnet_ids = [aws_subnet.subnet_for_lambda[0].id] security_group_ids = [aws_security_group.sg_for_lambda.id] } From bcb2fa222e8b82f4d87248ff94615fc60cfdf105 Mon Sep 17 00:00:00 2001 From: Daniel Rieske Date: Sat, 21 Oct 2023 19:23:19 +0200 Subject: [PATCH 4/8] chore: updated changelog --- .changelog/34045.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/34045.txt b/.changelog/34045.txt index b7c1ea91298..5c09c261e46 100644 --- a/.changelog/34045.txt +++ b/.changelog/34045.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_lambda_function: Added `ipv6_allowed_for_dual_stack` field to support outbound ipv6 traffic on dual-stack subnets +resource/aws_lambda_function: Added `ipv6_allowed_for_dual_stack` argument ``` From eb0bce3335a2f63a49ad9bd7b0d37ccc25eabe2d Mon Sep 17 00:00:00 2001 From: Daniel Rieske Date: Sat, 21 Oct 2023 19:47:20 +0200 Subject: [PATCH 5/8] chore: fixed fmt --- internal/service/lambda/function_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/lambda/function_test.go b/internal/service/lambda/function_test.go index b1d514dbdf0..ea892cf8bc9 100644 --- a/internal/service/lambda/function_test.go +++ b/internal/service/lambda/function_test.go @@ -3918,8 +3918,8 @@ resource "aws_lambda_function" "test" { runtime = "nodejs16.x" vpc_config { - subnet_ids = [aws_subnet.subnet_for_lambda[0].id] - security_group_ids = [aws_security_group.sg_for_lambda.id] + subnet_ids = [aws_subnet.subnet_for_lambda[0].id] + security_group_ids = [aws_security_group.sg_for_lambda.id] } } `, rName)) From ffd6af1f48dc9fe872ce9498e8cf45b970adb0b8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 23 Oct 2023 07:53:02 -0400 Subject: [PATCH 6/8] Update 34045.txt --- .changelog/34045.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/34045.txt b/.changelog/34045.txt index 5c09c261e46..2a48dd03b3a 100644 --- a/.changelog/34045.txt +++ b/.changelog/34045.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_lambda_function: Added `ipv6_allowed_for_dual_stack` argument +resource/aws_lambda_function: Add `vpc_config.ipv6_allowed_for_dual_stack` argument ``` From 2f7c00c2bb80739863b84eaa7ae6f1b3de6c166d Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 23 Oct 2023 10:05:06 -0400 Subject: [PATCH 7/8] r/aws_lambda_function: Update source code hashes after adding copywrite headers (#32351). --- internal/service/lambda/function_test.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/internal/service/lambda/function_test.go b/internal/service/lambda/function_test.go index ea892cf8bc9..a1af3fdb8d4 100644 --- a/internal/service/lambda/function_test.go +++ b/internal/service/lambda/function_test.go @@ -1824,7 +1824,7 @@ func TestAccLambdaFunction_localUpdate(t *testing.T) { Config: testAccFunctionConfig_local(path, rName), Check: resource.ComposeTestCheckFunc( testAccCheckFunctionExists(ctx, resourceName, &conf), - testAccCheckSourceCodeHash(&conf, "8DPiX+G1l2LQ8hjBkwRchQFf1TSCEvPrYGRKlM9UoyY="), + testAccCheckSourceCodeHash(&conf, "MbW0T1Pcy1QPtrFC9dT7hUfircj1NXss2uXgakqzAbk="), ), }, { @@ -1843,7 +1843,7 @@ func TestAccLambdaFunction_localUpdate(t *testing.T) { Config: testAccFunctionConfig_local(path, rName), Check: resource.ComposeTestCheckFunc( testAccCheckFunctionExists(ctx, resourceName, &conf), - testAccCheckSourceCodeHash(&conf, "0tdaP9H9hsk9c2CycSwOG/sa/x5JyAmSYunA/ce99Pg="), + testAccCheckSourceCodeHash(&conf, "7qn3LZOWCpWK5nm49qjw+VrbPQHfdu2ZrDjBsSUveKM="), func(s *terraform.State) error { return testAccCheckAttributeIsDateAfter(s, resourceName, "last_modified", timeBeforeUpdate) }, @@ -1890,7 +1890,7 @@ func TestAccLambdaFunction_LocalUpdate_nameOnly(t *testing.T) { Config: testAccFunctionConfig_localNameOnly(path, rName), Check: resource.ComposeTestCheckFunc( testAccCheckFunctionExists(ctx, resourceName, &conf), - testAccCheckSourceCodeHash(&conf, "8DPiX+G1l2LQ8hjBkwRchQFf1TSCEvPrYGRKlM9UoyY="), + testAccCheckSourceCodeHash(&conf, "MbW0T1Pcy1QPtrFC9dT7hUfircj1NXss2uXgakqzAbk="), ), }, { @@ -1908,7 +1908,7 @@ func TestAccLambdaFunction_LocalUpdate_nameOnly(t *testing.T) { Config: testAccFunctionConfig_localNameOnly(updatedPath, rName), Check: resource.ComposeTestCheckFunc( testAccCheckFunctionExists(ctx, resourceName, &conf), - testAccCheckSourceCodeHash(&conf, "0tdaP9H9hsk9c2CycSwOG/sa/x5JyAmSYunA/ce99Pg="), + testAccCheckSourceCodeHash(&conf, "7qn3LZOWCpWK5nm49qjw+VrbPQHfdu2ZrDjBsSUveKM="), ), }, }, @@ -1945,7 +1945,7 @@ func TestAccLambdaFunction_S3Update_basic(t *testing.T) { Config: testAccFunctionConfig_s3(key, path, rName), Check: resource.ComposeTestCheckFunc( testAccCheckFunctionExists(ctx, resourceName, &conf), - testAccCheckSourceCodeHash(&conf, "8DPiX+G1l2LQ8hjBkwRchQFf1TSCEvPrYGRKlM9UoyY="), + testAccCheckSourceCodeHash(&conf, "MbW0T1Pcy1QPtrFC9dT7hUfircj1NXss2uXgakqzAbk="), ), }, { @@ -1964,7 +1964,7 @@ func TestAccLambdaFunction_S3Update_basic(t *testing.T) { Config: testAccFunctionConfig_s3(key, path, rName), Check: resource.ComposeTestCheckFunc( testAccCheckFunctionExists(ctx, resourceName, &conf), - testAccCheckSourceCodeHash(&conf, "0tdaP9H9hsk9c2CycSwOG/sa/x5JyAmSYunA/ce99Pg="), + testAccCheckSourceCodeHash(&conf, "7qn3LZOWCpWK5nm49qjw+VrbPQHfdu2ZrDjBsSUveKM="), ), }, }, @@ -2001,7 +2001,7 @@ func TestAccLambdaFunction_S3Update_unversioned(t *testing.T) { Config: testAccFunctionConfig_s3UnversionedTPL(rName, key, path), Check: resource.ComposeTestCheckFunc( testAccCheckFunctionExists(ctx, resourceName, &conf), - testAccCheckSourceCodeHash(&conf, "8DPiX+G1l2LQ8hjBkwRchQFf1TSCEvPrYGRKlM9UoyY="), + testAccCheckSourceCodeHash(&conf, "MbW0T1Pcy1QPtrFC9dT7hUfircj1NXss2uXgakqzAbk="), ), }, { @@ -2020,7 +2020,7 @@ func TestAccLambdaFunction_S3Update_unversioned(t *testing.T) { Config: testAccFunctionConfig_s3UnversionedTPL(rName, key2, path), Check: resource.ComposeTestCheckFunc( testAccCheckFunctionExists(ctx, resourceName, &conf), - testAccCheckSourceCodeHash(&conf, "0tdaP9H9hsk9c2CycSwOG/sa/x5JyAmSYunA/ce99Pg="), + testAccCheckSourceCodeHash(&conf, "7qn3LZOWCpWK5nm49qjw+VrbPQHfdu2ZrDjBsSUveKM="), ), }, }, From 3f26c92f2159b5e4b6ee60d41b2f0c7fe3a525be Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 23 Oct 2023 11:00:52 -0400 Subject: [PATCH 8/8] Consolidate 'ConfigLambdaDualStackBase' into 'ConfigLambdaBase' and correct permissions for IAM role. --- internal/acctest/acctest.go | 151 +++-------------------- internal/service/lambda/function_test.go | 8 +- 2 files changed, 24 insertions(+), 135 deletions(-) diff --git a/internal/acctest/acctest.go b/internal/acctest/acctest.go index 0795a2c5c68..35fda5149a7 100644 --- a/internal/acctest/acctest.go +++ b/internal/acctest/acctest.go @@ -2107,7 +2107,7 @@ func ConfigLambdaBase(policyName, roleName, sgName string) string { data "aws_partition" "current" {} resource "aws_iam_role_policy" "iam_policy_for_lambda" { - name = "%s" + name = %[1]q role = aws_iam_role.iam_for_lambda.id policy = <