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

breaking: VPC configuration refactor #72

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Local .terraform directories
**/.terraform/*
.terraform.lock.hcl

# .tfstate files
*.tfstate
Expand Down
8 changes: 2 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ No modules.
| [aws_lambda_function_event_invoke_config.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function_event_invoke_config) | resource |
| [aws_s3_object.s3_dummy](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object) | resource |
| [aws_security_group.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/security_group) | resource |
| [aws_vpc_security_group_egress_rule.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/vpc_security_group_egress_rule) | resource |
| [archive_file.dummy](https://registry.terraform.io/providers/hashicorp/archive/latest/docs/data-sources/file) | data source |
| [aws_iam_policy_document.default](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/iam_policy_document) | data source |
| [aws_subnet.selected](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/subnet) | data source |
Expand Down Expand Up @@ -75,14 +74,11 @@ No modules.
| <a name="input_s3_bucket"></a> [s3\_bucket](#input\_s3\_bucket) | The S3 bucket location containing the function's deployment package | `string` | `null` | no |
| <a name="input_s3_key"></a> [s3\_key](#input\_s3\_key) | The S3 key of an object containing the function's deployment package | `string` | `null` | no |
| <a name="input_s3_object_version"></a> [s3\_object\_version](#input\_s3\_object\_version) | The object version containing the function's deployment package | `string` | `null` | no |
| <a name="input_security_group_egress_rules"></a> [security\_group\_egress\_rules](#input\_security\_group\_egress\_rules) | Security Group egress rules | <pre>list(object({<br> cidr_ipv4 = optional(string)<br> cidr_ipv6 = optional(string)<br> description = string<br> from_port = optional(number, 0)<br> ip_protocol = optional(string, "-1")<br> prefix_list_id = optional(string)<br> referenced_security_group_id = optional(string)<br> to_port = optional(number, 0)<br> }))</pre> | `[]` | no |
| <a name="input_security_group_ids"></a> [security\_group\_ids](#input\_security\_group\_ids) | The security group(s) for running the Lambda within the VPC. If not specified a minimal default SG will be created | `list(string)` | `[]` | no |
| <a name="input_security_group_name_prefix"></a> [security\_group\_name\_prefix](#input\_security\_group\_name\_prefix) | An optional prefix to create a unique name of the security group. If not provided `var.name` will be used | `string` | `null` | no |
| <a name="input_source_code_hash"></a> [source\_code\_hash](#input\_source\_code\_hash) | Optional source code hash | `string` | `null` | no |
| <a name="input_subnet_ids"></a> [subnet\_ids](#input\_subnet\_ids) | The subnet ids where this lambda needs to run | `list(string)` | `null` | no |
| <a name="input_tags"></a> [tags](#input\_tags) | A mapping of tags to assign to the bucket | `map(string)` | `{}` | no |
| <a name="input_timeout"></a> [timeout](#input\_timeout) | The timeout of the lambda | `number` | `5` | no |
| <a name="input_tracing_config_mode"></a> [tracing\_config\_mode](#input\_tracing\_config\_mode) | The lambda's AWS X-Ray tracing configuration | `string` | `null` | no |
| <a name="input_vpc_config"></a> [vpc\_config](#input\_vpc\_config) | The VPC configuration for Lambda function | <pre>object({<br> ipv6_allowed_for_dual_stack = optional(bool, false)<br> security_group_ids = optional(list(string), [])<br> security_group_name_prefix = optional(string, null)<br> subnet_ids = list(string)<br> })</pre> | `null` | no |

## Outputs

Expand All @@ -93,7 +89,7 @@ No modules.
| <a name="output_name"></a> [name](#output\_name) | Function name of the Lambda |
| <a name="output_qualified_arn"></a> [qualified\_arn](#output\_qualified\_arn) | Qualified ARN of the Lambda |
| <a name="output_role_arn"></a> [role\_arn](#output\_role\_arn) | ARN of the lambda execution role |
| <a name="output_security_group_id"></a> [security\_group\_id](#output\_security\_group\_id) | If the Lambda is deployed into a VPC this will output the genetered security group id (if no security groups are specified) |
| <a name="output_security_group_ids"></a> [security\_group\_ids](#output\_security\_group\_ids) | Security groups associated with the Lambda |
| <a name="output_version"></a> [version](#output\_version) | Latest published version of the Lambda function |
<!-- END_TF_DOCS -->

Expand Down
34 changes: 10 additions & 24 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ locals {
dead_letter_config = var.dead_letter_target_arn != null ? { create : true } : {}
environment = var.environment != null ? { create : true } : {}
ephemeral_storage = var.ephemeral_storage_size != null ? { create : true } : {}
execution_type = var.subnet_ids == null ? "Basic" : "VPCAccess"
execution_type = var.vpc_config == null ? "Basic" : "VPCAccess"
filename = var.filename != null ? var.filename : data.archive_file.dummy.output_path
source_code_hash = var.source_code_hash != null ? var.source_code_hash : var.filename != null ? filebase64sha256(var.filename) : null
tracing_config = var.tracing_config_mode != null ? { create : true } : {}
vpc_config = var.subnet_ids != null ? { create : true } : {}
create_security_group = var.vpc_config != null ? length(var.vpc_config.security_group_ids) == 0 : false
}

data "aws_iam_policy_document" "default" {
Expand Down Expand Up @@ -65,17 +65,17 @@ resource "aws_iam_role_policy_attachment" "enable_xray_daemon_write" {
}

data "aws_subnet" "selected" {
count = var.subnet_ids != null ? 1 : 0
count = var.vpc_config != null ? 1 : 0

id = var.subnet_ids[0]
id = var.vpc_config.subnet_ids[0]
}

resource "aws_security_group" "default" {
#checkov:skip=CKV2_AWS_5: False positive finding, the security group is attached.
count = var.subnet_ids != null && length(var.security_group_ids) == 0 ? 1 : 0
count = local.create_security_group ? 1 : 0

name = var.security_group_name_prefix == null ? var.name : null
name_prefix = var.security_group_name_prefix != null ? var.security_group_name_prefix : null
name = try(var.vpc_config.security_group_name_prefix, null) == null ? var.name : null
name_prefix = try(var.vpc_config.security_group_name_prefix, null) != null ? var.vpc_config.security_group_name_prefix : null
description = "Security group for lambda ${var.name}"
vpc_id = data.aws_subnet.selected[0].vpc_id
tags = var.tags
Expand All @@ -85,20 +85,6 @@ resource "aws_security_group" "default" {
}
}

resource "aws_vpc_security_group_egress_rule" "default" {
for_each = var.subnet_ids != null && length(var.security_group_ids) == 0 && length(var.security_group_egress_rules) != 0 ? { for v in var.security_group_egress_rules : v.description => v } : {}

cidr_ipv4 = each.value.cidr_ipv4
cidr_ipv6 = each.value.cidr_ipv6
description = each.value.description
from_port = each.value.from_port
ip_protocol = each.value.ip_protocol
prefix_list_id = each.value.prefix_list_id
referenced_security_group_id = each.value.referenced_security_group_id
security_group_id = aws_security_group.default[0].id
to_port = each.value.to_port
}

data "archive_file" "dummy" {
type = "zip"
output_path = "${path.module}/dummy_payload.zip"
Expand Down Expand Up @@ -200,11 +186,11 @@ resource "aws_lambda_function" "default" {
}

dynamic "vpc_config" {
for_each = local.vpc_config
for_each = var.vpc_config != null ? { create : true } : {}

content {
subnet_ids = var.subnet_ids
security_group_ids = length(var.security_group_ids) > 0 ? var.security_group_ids : [aws_security_group.default[0].id]
subnet_ids = var.vpc_config.subnet_ids
security_group_ids = length(var.vpc_config.security_group_ids) > 0 ? var.vpc_config.security_group_ids : [aws_security_group.default[0].id]
}
}

Expand Down
6 changes: 3 additions & 3 deletions outputs.tf
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,9 @@ output "role_arn" {
description = "ARN of the lambda execution role"
}

output "security_group_id" {
value = try(aws_security_group.default[0].id, "")
description = "If the Lambda is deployed into a VPC this will output the genetered security group id (if no security groups are specified)"
output "security_group_ids" {
value = length(try(var.vpc_config.security_group_ids, [])) > 0 ? var.vpc_config.security_group_ids : try(aws_security_group.default[0].id, [])
description = "Security groups associated with the Lambda"
}

output "version" {
Expand Down
49 changes: 11 additions & 38 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -176,50 +176,12 @@ variable "s3_object_version" {
description = "The object version containing the function's deployment package"
}

variable "security_group_ids" {
type = list(string)
default = []
description = "The security group(s) for running the Lambda within the VPC. If not specified a minimal default SG will be created"
}

variable "security_group_egress_rules" {
type = list(object({
cidr_ipv4 = optional(string)
cidr_ipv6 = optional(string)
description = string
from_port = optional(number, 0)
ip_protocol = optional(string, "-1")
prefix_list_id = optional(string)
referenced_security_group_id = optional(string)
to_port = optional(number, 0)
}))
default = []
description = "Security Group egress rules"

validation {
condition = alltrue([for o in var.security_group_egress_rules : (o.cidr_ipv4 != null || o.cidr_ipv6 != null || o.prefix_list_id != null || o.referenced_security_group_id != null)])
error_message = "Although \"cidr_ipv4\", \"cidr_ipv6\", \"prefix_list_id\", and \"referenced_security_group_id\" are all marked as optional, you must provide one of them in order to configure the destination of the traffic."
}
}

variable "security_group_name_prefix" {
type = string
default = null
description = "An optional prefix to create a unique name of the security group. If not provided `var.name` will be used"
}

variable "source_code_hash" {
type = string
default = null
description = "Optional source code hash"
}

variable "subnet_ids" {
type = list(string)
default = null
description = "The subnet ids where this lambda needs to run"
}

variable "tags" {
type = map(string)
default = {}
Expand All @@ -237,3 +199,14 @@ variable "tracing_config_mode" {
default = null
description = "The lambda's AWS X-Ray tracing configuration"
}

variable "vpc_config" {
type = object({
ipv6_allowed_for_dual_stack = optional(bool, false)
security_group_ids = optional(list(string), [])
security_group_name_prefix = optional(string, null)
subnet_ids = list(string)
})
default = null
description = "The VPC configuration for Lambda function"
}