From 0211af9de3e4bbc6b6c175dfaeb93b8320a1278a Mon Sep 17 00:00:00 2001 From: mptier <62100541+marlonparmentier@users.noreply.github.com> Date: Fri, 27 Dec 2024 15:00:41 +0100 Subject: [PATCH 1/5] Update Role ARN variable to object to allow proper usage of count --- dummy_payload.zip | Bin 0 -> 151 bytes main.tf | 4 ++-- outputs.tf | 2 +- variables.tf | 11 +++++++++-- 4 files changed, 12 insertions(+), 5 deletions(-) create mode 100644 dummy_payload.zip diff --git a/dummy_payload.zip b/dummy_payload.zip new file mode 100644 index 0000000000000000000000000000000000000000..48738fd903c3c4cccf54aaf558e6bc0cd2a1806d GIT binary patch literal 151 zcmWIWW@Zs#-~d8&zzGycDb3BT)GMhd@zOkdc5R4;$C@)I{e2i&7#RNl5AbH^c=T<@ p4q>1=ULX$eW@Hj!K$wLr2Qmv4z)cSDW@Q6OF#@4EkoE$r0|0bf8Y2Jz literal 0 HcmV?d00001 diff --git a/main.tf b/main.tf index 933df0d..6cca89e 100644 --- a/main.tf +++ b/main.tf @@ -11,7 +11,7 @@ locals { } module "lambda_role" { - count = length(compact([var.role_arn])) == 0 ? 1 : 0 + count = var.role == null ? 1 : 0 source = "github.com/schubergphilis/terraform-aws-mcaf-role?ref=v0.3.3" name = join("-", compact([var.role_prefix, "LambdaRole", var.name])) @@ -140,7 +140,7 @@ resource "aws_lambda_function" "default" { memory_size = var.memory_size publish = var.publish reserved_concurrent_executions = var.reserved_concurrency - role = length(compact([var.role_arn])) > 0 ? var.role_arn : module.lambda_role[0].arn + role = var.role != null ? var.role.role_arn : module.lambda_role[0].arn runtime = var.runtime s3_bucket = var.s3_bucket s3_key = var.s3_key diff --git a/outputs.tf b/outputs.tf index 526bfa0..bb760ac 100644 --- a/outputs.tf +++ b/outputs.tf @@ -19,7 +19,7 @@ output "qualified_arn" { } output "role_arn" { - value = length(compact([var.role_arn])) > 0 ? var.role_arn : module.lambda_role[0].arn + value = var.role != null ? var.role.role_arn : module.lambda_role[0].arn description = "ARN of the lambda execution role" } diff --git a/variables.tf b/variables.tf index e31986e..d9a3839 100644 --- a/variables.tf +++ b/variables.tf @@ -140,10 +140,17 @@ variable "retries" { description = "Maximum number of retries for the Lambda invocation" } -variable "role_arn" { - type = string +variable "role" { + type = object({ + role_arn = string + }) default = null description = "An optional lambda execution role" + + validation { + condition = var.role == null || can(regex("^arn:aws:iam::[0-9]{12}:(role)/.+$", var.role.role_arn)) + error_message = "If provided, role_arn must match an AWS Principal ARN" + } } variable "role_prefix" { From fc891f501db37c1985e6213fc819a3e53505024a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Fri, 27 Dec 2024 14:01:08 +0000 Subject: [PATCH 2/5] docs(readme): update module usage --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index c07b639..539be22 100644 --- a/README.md +++ b/README.md @@ -66,7 +66,7 @@ IMPORTANT: We do not pin modules to versions in our examples. We highly recommen | [publish](#input\_publish) | Whether to publish creation/change as new lambda function version | `bool` | `false` | no | | [reserved\_concurrency](#input\_reserved\_concurrency) | The amount of reserved concurrent executions for this lambda function | `number` | `null` | no | | [retries](#input\_retries) | Maximum number of retries for the Lambda invocation | `number` | `null` | no | -| [role\_arn](#input\_role\_arn) | An optional lambda execution role | `string` | `null` | no | +| [role](#input\_role) | An optional lambda execution role |
object({
role_arn = string
})
| `null` | no | | [role\_prefix](#input\_role\_prefix) | Default prefix for the role | `string` | `null` | no | | [runtime](#input\_runtime) | The function runtime to use | `string` | `"python3.10"` | no | | [s3\_bucket](#input\_s3\_bucket) | The S3 bucket location containing the function's deployment package | `string` | `null` | no | From d16088512dca79ca9441dfd36268b59e27698fe2 Mon Sep 17 00:00:00 2001 From: mptier <62100541+marlonparmentier@users.noreply.github.com> Date: Mon, 30 Dec 2024 09:43:58 +0100 Subject: [PATCH 3/5] remove dummy payload --- dummy_payload.zip | Bin 151 -> 0 bytes 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 dummy_payload.zip diff --git a/dummy_payload.zip b/dummy_payload.zip deleted file mode 100644 index 48738fd903c3c4cccf54aaf558e6bc0cd2a1806d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 151 zcmWIWW@Zs#-~d8&zzGycDb3BT)GMhd@zOkdc5R4;$C@)I{e2i&7#RNl5AbH^c=T<@ p4q>1=ULX$eW@Hj!K$wLr2Qmv4z)cSDW@Q6OF#@4EkoE$r0|0bf8Y2Jz From 403ac23eae44135190da07e162193ff0adc58740 Mon Sep 17 00:00:00 2001 From: Marwin Baumann Date: Mon, 30 Dec 2024 13:50:08 +0100 Subject: [PATCH 4/5] improve lambda execution role configuration --- UPGRADING.md | 34 +++++++++++++++---- examples/basic/versions.tf | 2 +- examples/role/main.tf | 22 +++++++++++++ examples/role/versions.tf | 14 ++++++++ main.tf | 20 +++++++----- outputs.tf | 2 +- variables.tf | 67 +++++++++++++++++--------------------- versions.tf | 2 +- 8 files changed, 108 insertions(+), 55 deletions(-) create mode 100644 examples/role/main.tf create mode 100644 examples/role/versions.tf diff --git a/UPGRADING.md b/UPGRADING.md index 767f836..b601ba0 100644 --- a/UPGRADING.md +++ b/UPGRADING.md @@ -1,17 +1,39 @@ # Upgrading Notes -This document captures breaking changes. +This document captures required refactoring on your part when upgrading to a module version that contains breaking changes. + + +## Upgrading to v2.0.0 + +### Variables (v2.0.0) + +The following variables have been replaced: + +* `permissions_boundary` → `execution_role.permissions_boundary` +* `policy` → `execution_role.policy` +* `role_arn` → `execution_role_custom.arn` +* `role_prefix` → `execution_role.name_prefix` + +The following variables have been introduced: + +* `execution_role.additional_policy_arns`. Add additional policy arns to the execution role. +* `execution_role.path`. Customizable role path. + +The following variables have been removed: + +* `create_policy`. This variable is not deemed necessary anymore, creating the policy is controlled by providing an `execution_role.policy`. + ## Upgrading to v1.0.0 -### Behaviour +### Behaviour (v1.0.0) The need to provide a `providers = { aws.lambda = aws }` argument has been removed. When using v1.0.0 or higher the provider will simply default to aws and if a different provider is needed, one can be provisioned by passing down `providers = { aws = aws.lambda }`. -### Variables +### Variables (v1.0.0) The following variable defaults have been modified: -- `log_retention` -> default: `365` (previous: `14`). In order to comply with AWS Security Hub control CloudWatch.16. -- `runtime` -> default: `python3.10` (previous: `python3.9`) -- `tags` -> default: `{}` (previous: ``). We recommend to set tags on the specified AWS provider. +* `log_retention` → default: `365` (previous: `14`). In order to comply with AWS Security Hub control CloudWatch.16. +* `runtime` → default: `python3.10` (previous: `python3.9`). +* `tags` → default: `{}` (previous: ``). We recommend to set tags on the specified AWS provider. diff --git a/examples/basic/versions.tf b/examples/basic/versions.tf index 7ed2a3f..913278e 100644 --- a/examples/basic/versions.tf +++ b/examples/basic/versions.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 0.13.0" + required_version = ">= 1.3.0" required_providers { aws = { diff --git a/examples/role/main.tf b/examples/role/main.tf new file mode 100644 index 0000000..cda9aee --- /dev/null +++ b/examples/role/main.tf @@ -0,0 +1,22 @@ +provider "aws" { + region = "eu-west-1" +} + +data "aws_iam_policy_document" "lambda_iam_policy" { + statement { + sid = "EC2DescribeRegionsAccess" + actions = ["ec2:DescribeRegions"] + resources = ["*"] + } +} + +module "lambda" { + source = "../.." + + name = "example" + + execution_role = { + path = "/custom/" + policy = data.aws_iam_policy_document.lambda_iam_policy.json + } +} diff --git a/examples/role/versions.tf b/examples/role/versions.tf new file mode 100644 index 0000000..913278e --- /dev/null +++ b/examples/role/versions.tf @@ -0,0 +1,14 @@ +terraform { + required_version = ">= 1.3.0" + + required_providers { + aws = { + source = "hashicorp/aws" + version = ">= 4.9.0" + } + archive = { + source = "hashicorp/archive" + version = ">= 2.0.0" + } + } +} diff --git a/main.tf b/main.tf index 6cca89e..c24f508 100644 --- a/main.tf +++ b/main.tf @@ -11,22 +11,24 @@ locals { } module "lambda_role" { - count = var.role == null ? 1 : 0 + count = var.execution_role_custom == null ? 1 : 0 - source = "github.com/schubergphilis/terraform-aws-mcaf-role?ref=v0.3.3" - name = join("-", compact([var.role_prefix, "LambdaRole", var.name])) - create_policy = var.create_policy - permissions_boundary = var.permissions_boundary + source = "schubergphilis/mcaf-role/aws" + version = "~> 0.4.0" + + name = join("-", compact([var.execution_role.name_prefix, "LambdaRole", var.name])) + path = var.execution_role.path + permissions_boundary = var.execution_role.permissions_boundary postfix = false principal_identifiers = ["edgelambda.amazonaws.com", "lambda.amazonaws.com"] principal_type = "Service" - role_policy = var.policy + role_policy = var.execution_role.policy tags = var.tags - policy_arns = compact([ + policy_arns = setunion(compact([ var.cloudwatch_logs ? "arn:aws:iam::aws:policy/service-role/AWSLambda${local.execution_type}ExecutionRole" : null, var.tracing_config_mode != null ? "arn:aws:iam::aws:policy/AWSXRayDaemonWriteAccess" : null, - ]) + ]), var.execution_role.additional_policy_arns) } resource "aws_cloudwatch_log_group" "default" { @@ -140,7 +142,7 @@ resource "aws_lambda_function" "default" { memory_size = var.memory_size publish = var.publish reserved_concurrent_executions = var.reserved_concurrency - role = var.role != null ? var.role.role_arn : module.lambda_role[0].arn + role = var.execution_role_custom != null ? var.execution_role_custom.arn : module.lambda_role[0].arn runtime = var.runtime s3_bucket = var.s3_bucket s3_key = var.s3_key diff --git a/outputs.tf b/outputs.tf index bb760ac..17b3b4d 100644 --- a/outputs.tf +++ b/outputs.tf @@ -19,7 +19,7 @@ output "qualified_arn" { } output "role_arn" { - value = var.role != null ? var.role.role_arn : module.lambda_role[0].arn + value = var.execution_role_custom != null ? var.execution_role_custom.arn : module.lambda_role[0].arn description = "ARN of the lambda execution role" } diff --git a/variables.tf b/variables.tf index d9a3839..7f75d22 100644 --- a/variables.tf +++ b/variables.tf @@ -21,12 +21,6 @@ variable "code_signing_config_arn" { description = "ARN for a Code Signing Configuration" } -variable "create_policy" { - type = bool - default = null - description = "Overrule whether the Lambda role policy has to be created" -} - variable "create_s3_dummy_object" { type = bool default = true @@ -69,6 +63,36 @@ variable "ephemeral_storage_size" { description = "The size of the Lambda function Ephemeral storage" } +variable "execution_role" { + type = object({ + additional_policy_arns = optional(set(string), []) + name_prefix = optional(string) + path = optional(string, "/") + permissions_boundary = optional(string) + policy = optional(string) + }) + default = {} + description = "Configuration for lambda execution IAM role" + + validation { + condition = can(regex("^/.*?/$", var.execution_role.path)) || var.execution_role.path == "/" + error_message = "The \"path\" must start and end with \"/\" or be \"/\"." + } +} + +variable "execution_role_custom" { + type = object({ + arn = string + }) + default = null + description = "Optional existing IAM role for Lambda execution. Overrides the role configured in the execution_role variable." + + validation { + condition = var.execution_role_custom == null || can(regex("^arn:aws:iam::[0-9]{12}:(role)/.+$", var.execution_role_custom.arn)) + error_message = "If provided, \"arn\" must match an AWS Principal ARN" + } +} + variable "filename" { type = string default = null @@ -110,18 +134,6 @@ variable "name" { description = "The name of the lambda" } -variable "permissions_boundary" { - type = string - default = null - description = "The permissions boundary to set on the role" -} - -variable "policy" { - type = string - default = null - description = "A valid lambda policy JSON document. This policy is used if you don't specify a role_arn" -} - variable "publish" { type = bool default = false @@ -140,25 +152,6 @@ variable "retries" { description = "Maximum number of retries for the Lambda invocation" } -variable "role" { - type = object({ - role_arn = string - }) - default = null - description = "An optional lambda execution role" - - validation { - condition = var.role == null || can(regex("^arn:aws:iam::[0-9]{12}:(role)/.+$", var.role.role_arn)) - error_message = "If provided, role_arn must match an AWS Principal ARN" - } -} - -variable "role_prefix" { - type = string - description = "Default prefix for the role" - default = null -} - variable "runtime" { type = string default = "python3.10" diff --git a/versions.tf b/versions.tf index 7ed2a3f..913278e 100644 --- a/versions.tf +++ b/versions.tf @@ -1,5 +1,5 @@ terraform { - required_version = ">= 0.13.0" + required_version = ">= 1.3.0" required_providers { aws = { From 869f96e3ad51ae6cceaaa3ec408b1556c7a26a03 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Mon, 30 Dec 2024 12:56:59 +0000 Subject: [PATCH 5/5] docs(readme): update module usage --- README.md | 11 ++++------- 1 file changed, 4 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 539be22..edb10d6 100644 --- a/README.md +++ b/README.md @@ -9,7 +9,7 @@ IMPORTANT: We do not pin modules to versions in our examples. We highly recommen | Name | Version | |------|---------| -| [terraform](#requirement\_terraform) | >= 0.13.0 | +| [terraform](#requirement\_terraform) | >= 1.3.0 | | [archive](#requirement\_archive) | >= 2.0.0 | | [aws](#requirement\_aws) | >= 4.9.0 | @@ -24,7 +24,7 @@ IMPORTANT: We do not pin modules to versions in our examples. We highly recommen | Name | Source | Version | |------|--------|---------| -| [lambda\_role](#module\_lambda\_role) | github.com/schubergphilis/terraform-aws-mcaf-role | v0.3.3 | +| [lambda\_role](#module\_lambda\_role) | schubergphilis/mcaf-role/aws | ~> 0.4.0 | ## Resources @@ -47,7 +47,6 @@ IMPORTANT: We do not pin modules to versions in our examples. We highly recommen | [architecture](#input\_architecture) | Instruction set architecture of the Lambda function | `string` | `"x86_64"` | no | | [cloudwatch\_logs](#input\_cloudwatch\_logs) | Whether or not to configure a CloudWatch log group | `bool` | `true` | no | | [code\_signing\_config\_arn](#input\_code\_signing\_config\_arn) | ARN for a Code Signing Configuration | `string` | `null` | no | -| [create\_policy](#input\_create\_policy) | Overrule whether the Lambda role policy has to be created | `bool` | `null` | no | | [create\_s3\_dummy\_object](#input\_create\_s3\_dummy\_object) | Whether or not to create a S3 dummy object | `bool` | `true` | no | | [dead\_letter\_target\_arn](#input\_dead\_letter\_target\_arn) | The ARN of an SNS topic or SQS queue to notify when an invocation fails | `string` | `null` | no | | [description](#input\_description) | A description of the lambda | `string` | `""` | no | @@ -55,19 +54,17 @@ IMPORTANT: We do not pin modules to versions in our examples. We highly recommen | [destination\_on\_success](#input\_destination\_on\_success) | ARN of the destination resource for successful asynchronous invocations | `string` | `null` | no | | [environment](#input\_environment) | A map of environment variables to assign to the lambda | `map(string)` | `null` | no | | [ephemeral\_storage\_size](#input\_ephemeral\_storage\_size) | The size of the Lambda function Ephemeral storage | `number` | `null` | no | +| [execution\_role](#input\_execution\_role) | Configuration for lambda execution IAM role |
object({
additional_policy_arns = optional(set(string), [])
name_prefix = optional(string)
path = optional(string, "/")
permissions_boundary = optional(string)
policy = optional(string)
})
| `{}` | no | +| [execution\_role\_custom](#input\_execution\_role\_custom) | Optional existing IAM role for Lambda execution. Overrides the role configured in the execution\_role variable. |
object({
arn = string
})
| `null` | no | | [filename](#input\_filename) | The path to the function's deployment package within the local filesystem | `string` | `null` | no | | [handler](#input\_handler) | The function entrypoint in your code | `string` | `"main.handler"` | no | | [kms\_key\_arn](#input\_kms\_key\_arn) | The ARN of the KMS key used to encrypt the cloudwatch log group and environment variables | `string` | `null` | no | | [layers](#input\_layers) | List of Lambda layer ARNs to be used by the Lambda function | `list(string)` | `[]` | no | | [log\_retention](#input\_log\_retention) | Number of days to retain log events in the specified log group | `number` | `365` | no | | [memory\_size](#input\_memory\_size) | The memory size of the lambda | `number` | `null` | no | -| [permissions\_boundary](#input\_permissions\_boundary) | The permissions boundary to set on the role | `string` | `null` | no | -| [policy](#input\_policy) | A valid lambda policy JSON document. This policy is used if you don't specify a role\_arn | `string` | `null` | no | | [publish](#input\_publish) | Whether to publish creation/change as new lambda function version | `bool` | `false` | no | | [reserved\_concurrency](#input\_reserved\_concurrency) | The amount of reserved concurrent executions for this lambda function | `number` | `null` | no | | [retries](#input\_retries) | Maximum number of retries for the Lambda invocation | `number` | `null` | no | -| [role](#input\_role) | An optional lambda execution role |
object({
role_arn = string
})
| `null` | no | -| [role\_prefix](#input\_role\_prefix) | Default prefix for the role | `string` | `null` | no | | [runtime](#input\_runtime) | The function runtime to use | `string` | `"python3.10"` | no | | [s3\_bucket](#input\_s3\_bucket) | The S3 bucket location containing the function's deployment package | `string` | `null` | no | | [s3\_key](#input\_s3\_key) | The S3 key of an object containing the function's deployment package | `string` | `null` | no |