Search code examples
amazon-web-servicesaws-lambdaterraformterraform-provider-aws

Add lambda permission for a list of ARNs and add as a dependency of bucket notification


I have a list of ARNs I need to add lambda permission AND consider as a dependency for the bucket notification but unsure how to tie both.

This is my variable:

variable "lambda_filters" {
  type = list(object({ lambda_function_arn : string, prefix : string, suffix : string }))
}

This is the permission and the notification:

resource "aws_lambda_permission" "allow_bucket" {
  statement_id  = "AllowS3Invoke"
  action        = "lambda:InvokeFunction"
  principal     = "s3.amazonaws.com"
  source_arn    = "arn:aws:s3:::${var.bucket}"
     
  I HAVE A LIST AND NOT ONLY ONE ---> function_name = <MY ARN>
}
    
resource "aws_s3_bucket_notification" "bucket_notification" {
  bucket = var.bucket
    
  dynamic "lambda_function" {
    for_each = var.lambda_filters
    iterator = it
    
    content {
      lambda_function_arn = it.value.lambda_function_arn
      events              = ["s3:ObjectCreated:*"]
      filter_prefix       = it.value.prefix
      filter_suffix       = it.value.suffix
    }
    
    REFERENCE SOMEHOW HERE --> depends_on = [aws_lambda_permission.allow_bucket]
  }
}

As you can see in aws_s3_bucket_notification, I want to add depends_on based on all buckets I have to add permission.

Lambda is being created in another module and ARN is the output of that:

output "lambda_arn" {
  value = aws_lambda_function.my_lambda.qualified_arn
}

Module is being used like this:

module "s3_bucket_notifications" {
  source = "../bucket_notifications"
    
  lambda_filters = [
    {
      lambda_function_arn : module.my_lambda.lambda_arn,
      prefix : "blah/blah", suffix : ".zip"
    }
  ]
}

How do I create lambda permissions for all ARNs inside that list and reference from bucket notification?


Solution

  • What I would suggest is a bit of refactoring of a part of the code to make it easier to work with the rest of the code you have. I would start with redefining the lambda_filters variable in such a way it is a map instead of a list, as using it with for_each will be easier:

    variable "lambda_filters" {
      type        = map(map(string))
      description = "(optional) describe your variable"
    
      default = {
        "lambda1" = {
          "lambda_function_arn" = "arn:aws:events:eu-west-1:111122223333:rule"
          "prefix"              = "blah/blah"
          "suffix"              = ".zip"
        }
      }
    }
    

    Then, when calling the module for bucket notification, you could try something like:

    module "s3_bucket_notifications" {
      source = "../bucket_notifications"
    
      lambda_filters = {
        "${module.my_lambda.lambda_function_name}" = {
          "lambda_function_arn" = module.my_lambda.lambda_arn
          "prefix" = "blah/blah"
          "suffix" = ".zip"
        }
      }
    }
    

    Of course, for this to work, you would have to define an output value in the Lambda module, i.e., module.my_lambda.lambda_function_name.

    The last part can be reconfigured to use for_each in the aws_lambda_permission resource:

    resource "aws_lambda_permission" "allow_bucket" {
      for_each      = var.lambda_filters
      statement_id  = "AllowS3Invoke"
      action        = "lambda:InvokeFunction"
      principal     = "s3.amazonaws.com"
      source_arn    = "arn:aws:s3:::${var.bucket}"
      function_name = each.key
    }
    

    While the aws_s3_bucket_notification resource can be rewritten like this:

    resource "aws_s3_bucket_notification" "bucket_notification" {
      bucket = var.bucket
    
      dynamic "lambda_function" {
        for_each = var.lambda_filters
        content {
          lambda_function_arn = lambda_function.value.lambda_function_arn
          events              = ["s3:ObjectCreated:*"]
          filter_prefix       = lambda_function.value.prefix
          filter_suffix       = lambda_function.value.suffix
        }
      }
    
      depends_on = [
        aws_lambda_permission.allow_bucket
      ]
    }