Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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
6 changes: 6 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -711,6 +711,7 @@ No modules.
| [aws_lambda_permission.unqualified_alias_triggers](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_permission) | resource |
| [aws_lambda_provisioned_concurrency_config.current_version](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_provisioned_concurrency_config) | resource |
| [aws_s3_object.lambda_package](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object) | resource |
| [aws_signer_signing_job.lambda_code_signing](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/signer_signing_job) | resource |
| [local_file.archive_plan](https://registry.terraform.io/providers/hashicorp/local/latest/docs/resources/file) | resource |
| [null_resource.archive](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
| [null_resource.sam_metadata_aws_lambda_function](https://registry.terraform.io/providers/hashicorp/null/latest/docs/resources/resource) | resource |
Expand Down Expand Up @@ -783,6 +784,7 @@ No modules.
| <a name="input_docker_image"></a> [docker\_image](#input\_docker\_image) | Docker image to use for the build | `string` | `""` | no |
| <a name="input_docker_pip_cache"></a> [docker\_pip\_cache](#input\_docker\_pip\_cache) | Whether to mount a shared pip cache folder into docker environment or not | `any` | `null` | no |
| <a name="input_docker_with_ssh_agent"></a> [docker\_with\_ssh\_agent](#input\_docker\_with\_ssh\_agent) | Whether to pass SSH\_AUTH\_SOCK into docker environment or not | `bool` | `false` | no |
| <a name="input_enable_code_signing"></a> [enable\_code\_signing](#input\_enable\_code\_signing) | Must be used with a lambda storing code on s3. Set this to true for triggering a signing job creating a signed copy of the lambda zip. https://docs.aws.amazon.com/lambda/latest/dg/configuration-codesigning.html | `bool` | `false` | no |
| <a name="input_environment_variables"></a> [environment\_variables](#input\_environment\_variables) | A map that defines environment variables for the Lambda Function. | `map(string)` | `{}` | no |
| <a name="input_ephemeral_storage_size"></a> [ephemeral\_storage\_size](#input\_ephemeral\_storage\_size) | Amount of ephemeral storage (/tmp) in MB your Lambda Function can use at runtime. Valid value between 512 MB to 10,240 MB (10 GB). | `number` | `512` | no |
| <a name="input_event_source_mapping"></a> [event\_source\_mapping](#input\_event\_source\_mapping) | Map of event source mapping | `any` | `{}` | no |
Expand All @@ -792,6 +794,7 @@ No modules.
| <a name="input_function_tags"></a> [function\_tags](#input\_function\_tags) | A map of tags to assign only to the lambda function | `map(string)` | `{}` | no |
| <a name="input_handler"></a> [handler](#input\_handler) | Lambda Function entrypoint in your code | `string` | `""` | no |
| <a name="input_hash_extra"></a> [hash\_extra](#input\_hash\_extra) | The string to add into hashing function. Useful when building same source path for different functions. | `string` | `""` | no |
| <a name="input_ignore_signing_job_failure"></a> [ignore\_signing\_job\_failure](#input\_ignore\_signing\_job\_failure) | Set this argument to true to ignore signing job failures and retrieve failed status and reason | `bool` | `false` | no |
| <a name="input_ignore_source_code_hash"></a> [ignore\_source\_code\_hash](#input\_ignore\_source\_code\_hash) | Whether to ignore changes to the function's source code hash. Set to true if you manage infrastructure and code deployments separately. | `bool` | `false` | no |
| <a name="input_image_config_command"></a> [image\_config\_command](#input\_image\_config\_command) | The CMD for the docker image | `list(string)` | `[]` | no |
| <a name="input_image_config_entry_point"></a> [image\_config\_entry\_point](#input\_image\_config\_entry\_point) | The ENTRYPOINT for the docker image | `list(string)` | `[]` | no |
Expand All @@ -803,6 +806,7 @@ No modules.
| <a name="input_kms_key_arn"></a> [kms\_key\_arn](#input\_kms\_key\_arn) | The ARN of KMS key to use by your Lambda Function | `string` | `null` | no |
| <a name="input_lambda_at_edge"></a> [lambda\_at\_edge](#input\_lambda\_at\_edge) | Set this to true if using Lambda@Edge, to enable publishing, limit the timeout, and allow edgelambda.amazonaws.com to invoke the function | `bool` | `false` | no |
| <a name="input_lambda_at_edge_logs_all_regions"></a> [lambda\_at\_edge\_logs\_all\_regions](#input\_lambda\_at\_edge\_logs\_all\_regions) | Whether to specify a wildcard in IAM policy used by Lambda@Edge to allow logging in all regions | `bool` | `true` | no |
| <a name="input_lambda_code_signing_profile_name"></a> [lambda\_code\_signing\_profile\_name](#input\_lambda\_code\_signing\_profile\_name) | Lambda code signing profile name https://console.aws.amazon.com/lambda/home#/code-signing-configurations | `string` | `null` | no |
| <a name="input_lambda_role"></a> [lambda\_role](#input\_lambda\_role) | IAM role ARN attached to the Lambda Function. This governs both who / what can invoke your Lambda Function, as well as what resources our Lambda Function has access to. See Lambda Permission Model for more details. | `string` | `""` | no |
| <a name="input_layer_name"></a> [layer\_name](#input\_layer\_name) | Name of Lambda Layer to create | `string` | `""` | no |
| <a name="input_layer_skip_destroy"></a> [layer\_skip\_destroy](#input\_layer\_skip\_destroy) | Whether to retain the old version of a previously deployed Lambda Layer. | `bool` | `false` | no |
Expand Down Expand Up @@ -853,6 +857,8 @@ No modules.
| <a name="input_s3_object_tags_only"></a> [s3\_object\_tags\_only](#input\_s3\_object\_tags\_only) | Set to true to not merge tags with s3\_object\_tags. Useful to avoid breaching S3 Object 10 tag limit. | `bool` | `false` | no |
| <a name="input_s3_prefix"></a> [s3\_prefix](#input\_s3\_prefix) | Directory name where artifacts should be stored in the S3 bucket. If unset, the path from `artifacts_dir` is used | `string` | `null` | no |
| <a name="input_s3_server_side_encryption"></a> [s3\_server\_side\_encryption](#input\_s3\_server\_side\_encryption) | Specifies server-side encryption of the object in S3. Valid values are "AES256" and "aws:kms". | `string` | `null` | no |
| <a name="input_s3_signing_bucket"></a> [s3\_signing\_bucket](#input\_s3\_signing\_bucket) | Bucket where to upload the signed s3 file. If omitted default to var.s3\_bucket | `string` | `null` | no |
| <a name="input_s3_signing_prefix"></a> [s3\_signing\_prefix](#input\_s3\_signing\_prefix) | Prefix for the generated signed object. If omitted default to var.s3\_prefix | `string` | `null` | no |
| <a name="input_skip_destroy"></a> [skip\_destroy](#input\_skip\_destroy) | Set to true if you do not wish the function to be deleted at destroy time, and instead just remove the function from the Terraform state. Useful for Lambda@Edge functions attached to CloudFront distributions. | `bool` | `null` | no |
| <a name="input_snap_start"></a> [snap\_start](#input\_snap\_start) | (Optional) Snap start settings for low-latency startups | `bool` | `false` | no |
| <a name="input_source_path"></a> [source\_path](#input\_source\_path) | The absolute path to a local file or directory containing your Lambda source code | `any` | `null` | no |
Expand Down
1 change: 0 additions & 1 deletion examples/code-signing/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ Note that this example may create resources which cost money. Run `terraform des
|------|------|
| [aws_lambda_code_signing_config.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_code_signing_config) | resource |
| [aws_s3_object.unsigned](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/s3_object) | resource |
| [aws_signer_signing_job.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/signer_signing_job) | resource |
| [aws_signer_signing_profile.this](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/signer_signing_profile) | resource |
| [random_pet.this](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/pet) | resource |

Expand Down
54 changes: 21 additions & 33 deletions examples/code-signing/main.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
locals {
lambda_code_signing_profile_name = replace(random_pet.this.id, "-", "")
}
provider "aws" {
region = "eu-west-1"

Expand All @@ -14,21 +17,23 @@ provider "aws" {
module "lambda" {
source = "../../"

function_name = random_pet.this.id
handler = "index.lambda_handler"
runtime = "python3.12"
code_signing_config_arn = aws_lambda_code_signing_config.this.arn
create_package = false
function_name = random_pet.this.id
handler = "index.lambda_handler"
runtime = "python3.12"
create_package = false
enable_code_signing = true
code_signing_config_arn = aws_lambda_code_signing_config.this.arn
lambda_code_signing_profile_name = local.lambda_code_signing_profile_name
s3_signing_prefix = "signed/"

store_on_s3 = true
s3_existing_package = {
bucket = aws_signer_signing_job.this.signed_object[0].s3[0].bucket
key = aws_signer_signing_job.this.signed_object[0].s3[0].key
bucket = module.s3_bucket.s3_bucket_id
key = aws_s3_object.unsigned.key
version_id = aws_s3_object.unsigned.version_id
}
}

################################################################################
# Lambda Code Signing
################################################################################
}

resource "aws_s3_object" "unsigned" {
bucket = module.s3_bucket.s3_bucket_id
Expand All @@ -41,38 +46,21 @@ resource "aws_s3_object" "unsigned" {
]
}

# ################################################################################
# # Lambda Code Signing
# ################################################################################

resource "aws_signer_signing_profile" "this" {
platform_id = "AWSLambda-SHA384-ECDSA"
# invalid value for name (must be alphanumeric with max length of 64 characters)
name = replace(random_pet.this.id, "-", "")
name = local.lambda_code_signing_profile_name

signature_validity_period {
value = 3
type = "MONTHS"
}
}

resource "aws_signer_signing_job" "this" {
profile_name = aws_signer_signing_profile.this.name

source {
s3 {
bucket = module.s3_bucket.s3_bucket_id
key = aws_s3_object.unsigned.id
version = aws_s3_object.unsigned.version_id
}
}

destination {
s3 {
bucket = module.s3_bucket.s3_bucket_id
prefix = "signed/"
}
}

ignore_signing_job_failure = true
}

resource "aws_lambda_code_signing_config" "this" {
allowed_publishers {
signing_profile_version_arns = [aws_signer_signing_profile.this.version_arn]
Expand Down
41 changes: 35 additions & 6 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,14 @@ locals {
s3_key = var.s3_existing_package != null ? try(var.s3_existing_package.key, null) : (var.store_on_s3 ? var.s3_prefix != null ? format("%s%s", var.s3_prefix, replace(local.archive_filename_string, "/^.*//", "")) : replace(local.archive_filename_string, "/^\\.//", "") : null)
s3_object_version = var.s3_existing_package != null ? try(var.s3_existing_package.version_id, null) : (var.store_on_s3 ? try(aws_s3_object.lambda_package[0].version_id, null) : null)

# s3_signing
s3_signing_enabled = local.s3_key != null && local.s3_bucket != null && var.enable_code_signing && var.lambda_code_signing_profile_name != null
s3_signing_bucket = var.s3_signing_bucket != null && local.s3_signing_enabled ? var.s3_signing_bucket : local.s3_bucket
s3_signing_prefix = var.s3_signing_prefix != null && local.s3_signing_enabled ? var.s3_signing_prefix : (var.s3_prefix != null ? var.s3_prefix : "")

lambda_s3_bucket = local.s3_signing_enabled ? aws_signer_signing_job.lambda_code_signing[0].signed_object[0].s3[0].bucket : local.s3_bucket
lambda_s3_key = local.s3_signing_enabled ? aws_signer_signing_job.lambda_code_signing[0].signed_object[0].s3[0].key : local.s3_key
lambda_s3_version = local.s3_signing_enabled ? null : local.s3_object_version # aws_signer_signing_job does not return a version id
}

resource "aws_lambda_function" "this" {
Expand Down Expand Up @@ -57,9 +65,9 @@ resource "aws_lambda_function" "this" {
filename = local.filename
source_code_hash = var.ignore_source_code_hash ? null : (local.filename == null ? false : fileexists(local.filename)) && !local.was_missing ? filebase64sha256(local.filename) : null

s3_bucket = local.s3_bucket
s3_key = local.s3_key
s3_object_version = local.s3_object_version
s3_bucket = local.lambda_s3_bucket
s3_key = local.lambda_s3_key
s3_object_version = local.lambda_s3_version

dynamic "image_config" {
for_each = length(var.image_config_entry_point) > 0 || length(var.image_config_command) > 0 || var.image_config_working_directory != null ? [true] : []
Expand Down Expand Up @@ -185,9 +193,9 @@ resource "aws_lambda_layer_version" "this" {
filename = local.filename
source_code_hash = var.ignore_source_code_hash ? null : (local.filename == null ? false : fileexists(local.filename)) && !local.was_missing ? filebase64sha256(local.filename) : null

s3_bucket = local.s3_bucket
s3_key = local.s3_key
s3_object_version = local.s3_object_version
s3_bucket = local.lambda_s3_bucket
s3_key = local.lambda_s3_key
s3_object_version = local.lambda_s3_version

depends_on = [null_resource.archive, aws_s3_object.lambda_package]
}
Expand Down Expand Up @@ -221,6 +229,27 @@ resource "aws_s3_object" "lambda_package" {
depends_on = [null_resource.archive]
}

resource "aws_signer_signing_job" "lambda_code_signing" {
count = local.s3_signing_enabled ? 1 : 0
profile_name = var.lambda_code_signing_profile_name

source {
s3 {
bucket = local.s3_bucket
key = local.s3_key
version = local.s3_object_version
}
}

destination {
s3 {
bucket = local.s3_signing_bucket
prefix = local.s3_signing_prefix
}
}
ignore_signing_job_failure = var.ignore_signing_job_failure
}

data "aws_cloudwatch_log_group" "lambda" {
count = local.create && var.create_function && !var.create_layer && var.use_existing_cloudwatch_log_group ? 1 : 0

Expand Down
34 changes: 34 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -847,3 +847,37 @@ variable "recursive_loop" {
type = string
default = null
}

###############
# Code Signing
###############

variable "enable_code_signing" {
description = "Must be used with a lambda storing code on s3. Set this to true for triggering a signing job creating a signed copy of the lambda zip. https://docs.aws.amazon.com/lambda/latest/dg/configuration-codesigning.html"
type = bool
default = false
}

variable "lambda_code_signing_profile_name" {
description = "Lambda code signing profile name https://console.aws.amazon.com/lambda/home#/code-signing-configurations"
type = string
default = null
}

variable "s3_signing_bucket" {
description = "Bucket where to upload the signed s3 file. If omitted default to var.s3_bucket"
type = string
default = null
}

variable "s3_signing_prefix" {
description = "Prefix for the generated signed object. If omitted default to var.s3_prefix"
type = string
default = null
}

variable "ignore_signing_job_failure" {
description = "Set this argument to true to ignore signing job failures and retrieve failed status and reason"
type = bool
default = false
}
5 changes: 5 additions & 0 deletions wrappers/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ module "wrapper" {
docker_image = try(each.value.docker_image, var.defaults.docker_image, "")
docker_pip_cache = try(each.value.docker_pip_cache, var.defaults.docker_pip_cache, null)
docker_with_ssh_agent = try(each.value.docker_with_ssh_agent, var.defaults.docker_with_ssh_agent, false)
enable_code_signing = try(each.value.enable_code_signing, var.defaults.enable_code_signing, false)
environment_variables = try(each.value.environment_variables, var.defaults.environment_variables, {})
ephemeral_storage_size = try(each.value.ephemeral_storage_size, var.defaults.ephemeral_storage_size, 512)
event_source_mapping = try(each.value.event_source_mapping, var.defaults.event_source_mapping, {})
Expand All @@ -62,6 +63,7 @@ module "wrapper" {
function_tags = try(each.value.function_tags, var.defaults.function_tags, {})
handler = try(each.value.handler, var.defaults.handler, "")
hash_extra = try(each.value.hash_extra, var.defaults.hash_extra, "")
ignore_signing_job_failure = try(each.value.ignore_signing_job_failure, var.defaults.ignore_signing_job_failure, false)
ignore_source_code_hash = try(each.value.ignore_source_code_hash, var.defaults.ignore_source_code_hash, false)
image_config_command = try(each.value.image_config_command, var.defaults.image_config_command, [])
image_config_entry_point = try(each.value.image_config_entry_point, var.defaults.image_config_entry_point, [])
Expand All @@ -73,6 +75,7 @@ module "wrapper" {
kms_key_arn = try(each.value.kms_key_arn, var.defaults.kms_key_arn, null)
lambda_at_edge = try(each.value.lambda_at_edge, var.defaults.lambda_at_edge, false)
lambda_at_edge_logs_all_regions = try(each.value.lambda_at_edge_logs_all_regions, var.defaults.lambda_at_edge_logs_all_regions, true)
lambda_code_signing_profile_name = try(each.value.lambda_code_signing_profile_name, var.defaults.lambda_code_signing_profile_name, null)
lambda_role = try(each.value.lambda_role, var.defaults.lambda_role, "")
layer_name = try(each.value.layer_name, var.defaults.layer_name, "")
layer_skip_destroy = try(each.value.layer_skip_destroy, var.defaults.layer_skip_destroy, false)
Expand Down Expand Up @@ -123,6 +126,8 @@ module "wrapper" {
s3_object_tags_only = try(each.value.s3_object_tags_only, var.defaults.s3_object_tags_only, false)
s3_prefix = try(each.value.s3_prefix, var.defaults.s3_prefix, null)
s3_server_side_encryption = try(each.value.s3_server_side_encryption, var.defaults.s3_server_side_encryption, null)
s3_signing_bucket = try(each.value.s3_signing_bucket, var.defaults.s3_signing_bucket, null)
s3_signing_prefix = try(each.value.s3_signing_prefix, var.defaults.s3_signing_prefix, null)
skip_destroy = try(each.value.skip_destroy, var.defaults.skip_destroy, null)
snap_start = try(each.value.snap_start, var.defaults.snap_start, false)
source_path = try(each.value.source_path, var.defaults.source_path, null)
Expand Down