=============================================================================== Lambda Function =============================================================================== A flexible Terraform module for creating AWS Lambda functions with a kwargs-like approach for additional attributes, optional execution role creation, ARM64 architecture for optimal price-performance. Features ------------------------------------------------------------------------------- - **kwargs-like flexibility**: Use ``additional_attributes`` to pass any Lambda function attribute - **Type-safe core attributes**: Essential attributes are explicitly defined with proper types - **Dynamic configuration**: Support for VPC, file system, tracing, and more - **Backward compatible**: Works with minimal configuration or complex setups - **Comprehensive outputs**: Expose all useful Lambda function attributes - **Optional execution role**: Automatically create and configure Lambda execution role with security best practices - **Confused deputy protection**: IAM trust policies include account conditions to prevent security attacks - **Configuration validation**: Ensures required parameters are provided at plan time, not apply time - **Custom policies**: Attach custom execution policies to the Lambda role - **ARM64 by default**: Optimized for price-performance with Graviton2/Graviton3 processors - **Robust hash-based change detection**: Use an explicit hash for reliable, efficient deployments Modern Usage Example: Hash-Based Lambda Deployment ------------------------------------------------------------------------------- This pattern ensures your Lambda ZIP is only rebuilt and redeployed when the source code changes, using a dedicated folder hash module and builder module. .. code-block:: hcl module "lambda_one" { source = "./modules/lambda/function" function_name = "simple-lambda-one" description = "Simple Lambda function with minimal configuration..." create_execution_role = true zip_path = "path/to/zip_file.zip" source_code_hash = "hash_code" depends_on = [ module.folder_hash_lambda_one, module.my_lambda_one_builder ] } Why this pattern? ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - **Efficient builds:** The ZIP is only rebuilt when the source code changes. - **Reliable deployments:** Lambda is only updated when the code or configuration changes. - **Explicit and reproducible:** The hash is calculated in a dedicated module, making dependencies clear. .. note:: The ``source_code_hash`` variable must be provided by the user. This module does not read ``.base64sha256`` files automatically; you should pass the hash output from your builder or hash module. ARM64 Architecture Benefits ------------------------------------------------------------------------------- This module defaults to **ARM64 architecture** for the following benefits: - **💰 20-34% cost savings** compared to x86_64 - **⚡ Better performance** for most workloads - **🔋 Lower power consumption** and carbon footprint - **🔄 Faster cold starts** in many scenarios - **📦 Smaller deployment packages** for some runtimes You can still use x86_64 if needed for compatibility with specific libraries or requirements. Integration with Lambda Builder Module ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: hcl locals { root_path = abspath(path.module) build_path = "${local.root_path}/.build" lambdas_path = "${local.root_path}/project/lambdas" } # 1. Calculate a hash of all source files in the Lambda directory module "folder_hash_lambda_one" { source = "./modules/utils/folder_hash" source_dir = "${local.lambdas_path}/lambda_one" } # 2. Build the Lambda ZIP only when the source hash changes module "my_lambda_one_builder" { source = "./modules/lambda/builder" project_dir = local.root_path source_dir = "${local.lambdas_path}/lambda_one" build_dir = "${local.build_path}/project/lambdas/lambda_one" output_zip = "${local.build_path}/project/lambdas/lambda_one/my_lambda.zip" source_hash = module.folder_hash_lambda_one.folder_hash depends_on = [ module.folder_hash_lambda_one ] } # 3. Deploy the Lambda function, using the ZIP and hash module "lambda_one" { source = "./modules/lambda/function" function_name = "simple-lambda-one" description = "Simple Lambda function with minimal configuration..." create_execution_role = true zip_path = module.my_lambda_one_builder.zip_file source_code_hash = module.folder_hash_lambda_one.folder_hash depends_on = [ module.folder_hash_lambda_one, module.my_lambda_one_builder ] } Usage Examples ------------------------------------------------------------------------------- Basic Usage with External Role ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: hcl module "simple_lambda" { source = "./modules/lambda/function" function_name = "my-function" description = "A simple Lambda function (ARM64 by default)" role_arn = aws_iam_role.lambda_role.arn zip_path = "path/to/function.zip" source_code_hash = filebase64sha256("path/to/function.zip") } # Access outputs output "lambda_arn" { value = module.simple_lambda.arn } output "lambda_architecture" { value = module.simple_lambda.architectures # ["arm64"] } Basic Usage with Auto-Created Execution Role ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: hcl module "simple_lambda_with_role" { source = "./modules/lambda/function" function_name = "my-function" description = "A simple Lambda function with auto-created role" create_execution_role = true zip_path = "path/to/function.zip" source_code_hash = filebase64sha256("path/to/function.zip") } # Access execution role outputs output "execution_role_arn" { value = module.simple_lambda_with_role.execution_role_arn } Using x86_64 Architecture ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: hcl module "x86_lambda" { source = "./modules/lambda/function" function_name = "x86-function" description = "Lambda function using x86_64 architecture" create_execution_role = true architectures = ["x86_64"] # Override default ARM64 zip_path = "path/to/function.zip" source_code_hash = filebase64sha256("path/to/function.zip") } Advanced Usage with VPC and Custom Policies ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. code-block:: hcl module "vpc_lambda" { source = "./modules/lambda/function" function_name = "vpc-lambda" description = "Lambda function in VPC with custom policies" create_execution_role = true execution_policies = { "s3-access" = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = ["s3:GetObject", "s3:PutObject"] Resource = "arn:aws:s3:::my-bucket/*" } ] }) "dynamodb-access" = jsonencode({ Version = "2012-10-17" Statement = [ { Effect = "Allow" Action = ["dynamodb:GetItem", "dynamodb:PutItem"] Resource = "arn:aws:dynamodb:us-east-1:123456789012:table/my-table" } ] }) } zip_path = "path/to/function.zip" source_code_hash = filebase64sha256("path/to/function.zip") additional_attributes = { vpc_config = { subnet_ids = ["subnet-12345678", "subnet-87654321"] security_group_ids = ["sg-12345678"] } tracing_config = { mode = "Active" } reserved_concurrent_executions = 10 } } Available additional_attributes ------------------------------------------------------------------------------- The ``additional_attributes`` variable accepts any valid AWS Lambda function attribute. Block Attributes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``vpc_config`` - VPC configuration - ``file_system_config`` - EFS mount configuration - ``tracing_config`` - X-Ray tracing configuration - ``image_config`` - Container image configuration - ``dead_letter_config`` - Dead letter queue configuration Simple Attributes ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``reserved_concurrent_executions`` - Concurrency limit - ``publish`` - Publish version - ``layers`` - Lambda layers - ``kms_key_arn`` - KMS encryption key - ``package_type`` - Package type (Zip/Image) - ``image_uri`` - Container image URI - ``code_signing_config_arn`` - Code signing configuration Tags ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - ``tags`` - Additional tags (merged with base tags) Inputs ------------------------------------------------------------------------------- .. list-table:: :header-rows: 1 :widths: 20 40 15 15 10 * - Name - Description - Type - Default - Required * - function_name - Name of the Lambda function - string - n/a - yes * - description - Description of the Lambda function - string - n/a - yes * - role_arn - IAM role ARN for the Lambda function (required if create_execution_role = false) - string - null - no * - create_execution_role - Whether to create a Lambda execution role automatically - bool - false - no * - execution_policies - Map of custom execution policies to attach to the Lambda execution role - map(string) - {} - no * - handler - Handler function - string - "handler.handler" - no * - runtime - Lambda runtime - string - "python3.12" - no * - architectures - Instruction set architecture for the Lambda function - list(string) - ["arm64"] - no * - zip_path - Path to the Lambda deployment package - string - n/a - yes * - source_code_hash - Code hash of the deployment package - string - n/a - yes * - timeout - Execution timeout in seconds - number - 3 - no * - memory_size - Amount of memory in MB - number - 128 - no * - environment_variables - Environment variables - map(string) - {} - no * - tags - Tags to apply - map(string) - {} - no * - additional_attributes - Additional attributes (kwargs-like) - map(any) - {} - no Outputs ------------------------------------------------------------------------------- .. list-table:: :header-rows: 1 :widths: 30 70 * - Name - Description * - name - The Lambda Function name * - arn - The Lambda Function ARN * - invoke_arn - The Lambda Function invoke ARN (used for API Gateway integration) * - qualified_arn - The Lambda Function qualified ARN (includes version) * - version - The Lambda Function version * - last_modified - The date the Lambda Function was last modified * - source_code_size - The size of the Lambda Function deployment package in bytes * - runtime - The Lambda Function runtime * - handler - The Lambda Function handler * - architectures - The Lambda Function architectures (ARM64 for better price-performance) * - memory_size - The Lambda Function memory size in MB * - timeout - The Lambda Function timeout in seconds * - environment_variables - The Lambda Function environment variables * - vpc_config - The Lambda Function VPC configuration (if configured) * - layers - The Lambda Function layers (if configured) * - tags - The Lambda Function tags * - function_url - The Lambda Function URL (if configured via additional_attributes) * - reserved_concurrent_executions - The Lambda Function reserved concurrency limit (if configured) * - kms_key_arn - The Lambda Function KMS key ARN (if configured) * - signing_job_arn - The Lambda Function signing job ARN (if code signing is configured) * - signing_profile_version_arn - The Lambda Function signing profile version ARN (if code signing is configured) * - execution_role_arn - The Lambda execution role ARN (only when create_execution_role = true) * - execution_role_name - The Lambda execution role name (only when create_execution_role = true) * - execution_role_id - The Lambda execution role ID (only when create_execution_role = true) Execution Role Features ------------------------------------------------------------------------------- When ``create_execution_role = true``, the module automatically: 1. **Creates IAM Role**: Lambda execution role with secure assume role policy - Includes ``aws:SourceAccount`` condition to prevent confused deputy attacks - Follows AWS security best practices for service-to-service access 2. **Attaches Basic Policy**: ``AWSLambdaBasicExecutionRole`` for CloudWatch logs 3. **Attaches VPC Policy**: ``AWSLambdaVPCAccessExecutionRole`` if VPC is configured 4. **Attaches Custom Policies**: Any policies provided in ``execution_policies`` 5. **Applies Tags**: Uses the same tags as the Lambda function 6. **Validates Configuration**: Ensures ``role_arn`` is provided when ``create_execution_role = false`` Automatic Policy Attachments ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - **Basic Execution**: Always attached for CloudWatch logs - **VPC Access**: Automatically attached when VPC configuration is present - **Custom Policies**: Attached based on ``execution_policies`` variable ARM64 Architecture Considerations ------------------------------------------------------------------------------- Benefits ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - **Cost Savings**: 20-34% lower costs compared to x86_64 - **Performance**: Better performance for most workloads - **Efficiency**: Lower power consumption and carbon footprint - **Cold Starts**: Faster cold starts in many scenarios Compatibility ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - **Most AWS SDKs**: Fully compatible with ARM64 - **Popular Runtimes**: Python, Node.js, Java, .NET, Go, Ruby - **Layers**: Many public layers available for ARM64 - **Custom Binaries**: May need ARM64 versions of native libraries When to Use x86_64 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - **Native Dependencies**: Libraries that don't have ARM64 versions - **Legacy Code**: Applications with x86_64-specific optimizations - **Third-party Tools**: Tools that don't support ARM64 - **Testing**: When testing compatibility with existing x86_64 deployments Best Practices ------------------------------------------------------------------------------- 1. Use explicit attributes for commonly used configurations 2. Use additional_attributes for advanced or rarely used features 3. Document complex configurations in your module usage 4. Validate additional_attributes in your calling code 5. Use consistent naming for your additional attributes 6. Leverage outputs for integration with other AWS services 7. Use create_execution_role for simple Lambda functions 8. Use external roles for complex IAM requirements 9. Prefer ARM64 for cost and performance benefits 10. Test compatibility when migrating from x86_64 to ARM64