Skip to content

Commit

Permalink
Merge pull request #89 from ministryofjustice/feature/vpc-config
Browse files Browse the repository at this point in the history
feat: vpc config functionality
  • Loading branch information
haitchison authored Jan 4, 2024
2 parents 338e9f4 + 2e6692d commit 1ca84d0
Show file tree
Hide file tree
Showing 8 changed files with 210 additions and 11 deletions.
12 changes: 12 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -65,10 +65,15 @@ resource "aws_lambda_function" "this" { #tfsec:ignore:aws-lambda-enable-tracing
description = var.description
reserved_concurrent_executions = var.reserved_concurrent_executions
image_uri = var.image_uri
filename = var.filename
handler = var.handler
runtime = var.runtime
source_code_hash = var.source_code_hash
package_type = var.package_type
role = var.create_role ? aws_iam_role.this[0].arn : var.lambda_role
timeout = var.timeout
memory_size = var.memory_size

dynamic "tracing_config" {
for_each = var.tracing_mode != null ? [1] : []
content {
Expand All @@ -81,6 +86,13 @@ resource "aws_lambda_function" "this" { #tfsec:ignore:aws-lambda-enable-tracing
variables = var.environment_variables
}
}
dynamic "vpc_config" {
for_each = var.vpc_subnet_ids != null && var.vpc_security_group_ids != null ? [true] : []
content {
security_group_ids = var.vpc_security_group_ids
subnet_ids = var.vpc_subnet_ids
}
}
}

resource "aws_lambda_permission" "allowed_triggers" {
Expand Down
10 changes: 10 additions & 0 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,13 @@ output "lambda_function_name" {
description = "The Name of the Lambda Function"
value = try(aws_lambda_function.this.function_name, "")
}

output "vpc_security_group_ids" {
description = "The VPC security groups the lambda function has been deployed into"
value = try(aws_lambda_function.this.vpc_config[0].security_group_ids, "")
}

output "vpc_subnet_ids" {
description = "The vpc subnet(s) the Lambda function has been deployed into"
value = try(aws_lambda_function.this.vpc_config[0].subnet_ids, "")
}
19 changes: 17 additions & 2 deletions test/lambda_test.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
package main

import (
"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/assert"
"regexp"
"testing"

"github.com/gruntwork-io/terratest/modules/terraform"
"github.com/stretchr/testify/assert"
)

func TestLambdaCreation(t *testing.T) {
Expand All @@ -19,8 +20,22 @@ func TestLambdaCreation(t *testing.T) {
terraform.InitAndApply(t, terraformOptions)

functionName := terraform.Output(t, terraformOptions, "function_name")
functionVpcName := terraform.Output(t, terraformOptions, "function_vpc_name")
resultCode := terraform.Output(t, terraformOptions, "result_code")
resultVpcCode := terraform.Output(t, terraformOptions, "vpc_result_code")
subnetId := terraform.Output(t, terraformOptions, "subnet_ids")
securityGroupId := terraform.Output(t, terraformOptions, "security_group_ids")

re := regexp.MustCompile(`[{}\[\]\s]`)
subnetId = re.ReplaceAllString(subnetId, "")
securityGroupId = re.ReplaceAllString(securityGroupId, "")

assert.Regexp(t, regexp.MustCompile(`^instance-scheduler-lambda-function*`), functionName)
assert.Regexp(t, regexp.MustCompile(`^200*`), resultCode)

assert.Regexp(t, regexp.MustCompile(`^subnet-\w+$`), subnetId)
assert.Regexp(t, regexp.MustCompile(`^sg-\w+$`), securityGroupId)

assert.Regexp(t, regexp.MustCompile(`^lambda-function-in-vpc-test*`), functionVpcName)
assert.Regexp(t, regexp.MustCompile(`^"Hello from AWS Lambda using Python*`), resultVpcCode)
}
115 changes: 108 additions & 7 deletions test/unit-test/main.tf
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@

# lambda module test with image package type
module "module_test" {
source = "../../"
application_name = local.application_name
tags = local.tags
description = "test lambda"
role_name = "InstanceSchedulerLambdaFunctionPolicy"
role_name = format("InstanceSchedulerLambdaFunctionPolicy-%s", random_id.role.dec)
policy_json_attached = true
policy_json = data.aws_iam_policy_document.instance-scheduler-lambda-function-policy.json
function_name = "instance-scheduler-lambda-function"
function_name = format("instance-scheduler-lambda-function-%s", random_id.lambda.dec)
create_role = true
reserved_concurrent_executions = 1
environment_variables = {
Expand Down Expand Up @@ -152,8 +152,109 @@ data "aws_iam_policy_document" "instance-scheduler-lambda-function-policy" {
resource "aws_lambda_invocation" "test_invocation" {
function_name = module.module_test.lambda_function_name

input = jsonencode(
{
action = "Test"
input = jsonencode({
action = "Test"
})
}

# lambda module test with zip package type and vpc config
module "lambda_function_in_vpc" {
source = "../../"
application_name = local.application_name
tags = local.tags
description = "lambda function provisioned within a vpc test"
lambda_role = aws_iam_role.lambda-vpc-role.arn
function_name = format("lambda-function-in-vpc-test-%s", random_id.lambda_name.dec)
create_role = false
package_type = "Zip"
filename = data.archive_file.lambda-zip.output_path
source_code_hash = data.archive_file.lambda-zip.output_base64sha256
handler = "test.lambda_handler"
runtime = "python3.8"

vpc_subnet_ids = [data.aws_subnet.private-2a.id]
vpc_security_group_ids = [aws_security_group.lambda_security_group_test.id]
}

data "aws_iam_policy_document" "lambda_assume_role_policy" {
statement {
effect = "Allow"
actions = ["sts:AssumeRole"]

principals {
type = "Service"
identifiers = ["lambda.amazonaws.com"]
}
}
}

resource "aws_iam_role" "lambda-vpc-role" {
name = format("LambdaFunctionVPCAccess-%s", random_id.role_name.dec)
tags = local.tags

assume_role_policy = data.aws_iam_policy_document.lambda_assume_role_policy.json
}

resource "aws_iam_role_policy_attachment" "lambda-vpc-attachment" {
role = aws_iam_role.lambda-vpc-role.name
policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
}

data "aws_vpc" "platforms-test" {
id = "vpc-05900bb7e2e82391f"
}

data "aws_subnet" "private-2a" {
id = "subnet-0e2a4d5f4b346c981"
}

resource "aws_security_group" "lambda_security_group_test" {
name = format("lambda-vpc-module-test-%s", random_id.sg_name.dec)
description = "lambda attached to vpc test security group"
vpc_id = data.aws_vpc.platforms-test.id

egress {
description = "Allow all outbound traffic"
from_port = 0
to_port = 0
protocol = "-1"
}

tags = local.tags
}

data "archive_file" "lambda-zip" {
type = "zip"
source_file = "test-zip/test.py"
output_path = "test.zip"
}

resource "aws_lambda_invocation" "test_vpc_invocation" {
function_name = module.lambda_function_in_vpc.lambda_function_name

input = jsonencode({
action = "Test"
})
}
}

# random IDs to allow for go unit test to run to completion via github action

resource "random_id" "lambda_name" {
byte_length = 1
}

resource "random_id" "role" {
byte_length = 1
}

resource "random_id" "lambda" {
byte_length = 1
}

resource "random_id" "sg_name" {
byte_length = 1
}

resource "random_id" "role_name" {
byte_length = 1
}
18 changes: 17 additions & 1 deletion test/unit-test/outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,20 @@ output "function_name" {

output "result_code" {
value = jsondecode(aws_lambda_invocation.test_invocation.result)["statusCode"]
}
}

output "security_group_ids" {
value = module.lambda_function_in_vpc.vpc_security_group_ids
}

output "subnet_ids" {
value = module.lambda_function_in_vpc.vpc_subnet_ids
}

output "function_vpc_name" {
value = module.lambda_function_in_vpc.lambda_function_name
}

output "vpc_result_code" {
value = aws_lambda_invocation.test_vpc_invocation.result
}
5 changes: 5 additions & 0 deletions test/unit-test/test-zip/test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import sys


def lambda_handler(event, context):
return 'Hello from AWS Lambda using Python' + sys.version + '!'
4 changes: 4 additions & 0 deletions test/unit-test/versions.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ terraform {
version = "~> 5.0"
source = "hashicorp/aws"
}
random = {
source = "hashicorp/random"
version = "~> 3.5"
}
}
required_version = ">= 1.0.1"
}
38 changes: 37 additions & 1 deletion variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ variable "environment_variables" {
}

variable "package_type" {
description = "The Lambda deployment package type. Valid options: Image"
description = "The Lambda deployment package type. Valid options: Image or Zip"
type = string
default = "Image"
}
Expand All @@ -87,6 +87,30 @@ variable "image_uri" {
default = null
}

variable "filename" {
description = "The absolute path to an existing zip-file to use"
type = string
default = null
}

variable "source_code_hash" {
description = "Hash value of the archive file. Calculated externally. Use to trigger updates when source file is changed."
type = string
default = null
}

variable "handler" {
description = "Lambda Function entrypoint in your code"
type = string
default = null
}

variable "runtime" {
description = "Lambda function runtime"
type = string
default = null
}

variable "timeout" {
description = "The amount of time your Lambda Function has to run in seconds."
type = number
Expand Down Expand Up @@ -138,3 +162,15 @@ variable "sns_topic_on_success" {
type = string
default = ""
}

variable "vpc_subnet_ids" {
description = "List of subnet ids when Lambda Function should run in the VPC. Usually private or intra subnets."
type = list(string)
default = null
}

variable "vpc_security_group_ids" {
description = "List of security group ids when Lambda Function should run in the VPC."
type = list(string)
default = null
}

0 comments on commit 1ca84d0

Please sign in to comment.