From 403ac23eae44135190da07e162193ff0adc58740 Mon Sep 17 00:00:00 2001 From: Marwin Baumann Date: Mon, 30 Dec 2024 13:50:08 +0100 Subject: [PATCH] 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 = {