node.jsaws-lambdaterraformterraform-provider-awsinfrastructure-as-code

Merging multiple aws iam roles for lambdas in terraform


I have following configuration in terraform:

locals {
  common_env_vars = {
    DATABASE_NAME     = var.database_name
  }

  lambda_config = {
    filename         = "empty.zip"
    source_code_hash = ""
    handler          = "index.handler"
    runtime          = "nodejs20.x"
    timeout          = var.default_timeout / 1000
    role             = aws_iam_role.lambda_exec_role.arn
    environment = {
      variables = local.common_env_vars
    }
  }

  lambda_functions = {
    "GetUser" = { function_name = "GetUser" }
    "CreateUser" = { function_name = "CreateUser" }
  }
}

resource "aws_lambda_function" "functions" {
  for_each = local.lambda_functions

  function_name    = each.value.function_name
  filename         = local.lambda_config.filename
  source_code_hash = local.lambda_config.source_code_hash
  handler          = local.lambda_config.handler
  runtime          = local.lambda_config.runtime
  timeout          = local.lambda_config.timeout
  role             = local.lambda_config.role


  environment {
    variables = merge(
      local.lambda_config.environment.variables,
      lookup(local.lambda_specific_env_vars, each.key, {})
    )
  }
}

Where I use shared iam role role = aws_iam_role.lambda_exec_role.arn

What I need to achieve is add specific permissions for create-user lambda only. I've tried to create a separate role and merge it with the default one but couldn't find a proper way to do it. Any help would be greatly appreciated!


Solution

  • It's unclear what you mean by "merging" the roles. If you have two roles, and you want one of the Lambda functions to use one role, and all the other Lambda functions to use the other role, then I don't see how the act of "merging" anything comes into play here at all.

    You just need a conditional in the role assignment. Something like this:

    resource "aws_lambda_function" "functions" {
      for_each = local.lambda_functions
    
      function_name = each.value.function_name
    
      // Use a specific role if the function name is "CreateUser" otherwise use the default role
      role = each.value.function_name == "CreateUser" ? aws_iam_role.create_user_lambda_role.arn : local.lambda_config.role
    
    }
    

    Or if you want all this to be configured in your locals, you could do something like this (just like you are doing for the Lambda specific environment variables):

    locals {
      lambda_functions = {
        "GetUser" = { function_name = "GetUser" }
        "CreateUser" = { function_name = "CreateUser", role = aws_iam_role.create_user_lambda_role.arn }
      }
    }
    
    resource "aws_lambda_function" "functions" {
      for_each = local.lambda_functions
    
      function_name = each.value.function_name
    
      // Check if this function configuration has a "role" attribute, and use it if it does, otherwise use the default role.
      role = lookup(each.value, "role", local.lambda_config.role)
    
    }
    

    Regarding the use of multiple roles, you can only assign one role to a Lambda function. The role attribute takes the ARN of a single AWS IAM role, not a list of them. Your 10th Lambda function will need to be assigned a role that includes all the permissions from role X as well as any additional permissions it needs. You might want to look at managing that at the IAM Policy level, rather than the IAM Role level.