├── examples └── basic │ ├── lambda │ ├── __init__.py │ └── main.py │ ├── requirements.txt │ ├── outputs.tf │ ├── main.tf │ └── README.md ├── outputs.tf ├── .gitignore ├── policy.json ├── LICENSE ├── variables.tf ├── README.md └── main.tf /examples/basic/lambda/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/basic/requirements.txt: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /examples/basic/outputs.tf: -------------------------------------------------------------------------------- 1 | output "api_gateway" { 2 | value = "${module.lambda_python.url}" 3 | } 4 | -------------------------------------------------------------------------------- /outputs.tf: -------------------------------------------------------------------------------- 1 | output "url" { 2 | value = "${aws_api_gateway_deployment.deployment.invoke_url}${aws_api_gateway_resource.resource.path}" 3 | } 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | venv 2 | backend.conf 3 | .terraform 4 | .terraform.tfstate.lock.info 5 | terraform.tfstate 6 | terraform.tfstate.backup 7 | terraform.tfvars 8 | lambda.zip -------------------------------------------------------------------------------- /policy.json: -------------------------------------------------------------------------------- 1 | { 2 | "Version": "2012-10-17", 3 | "Statement": [ 4 | { 5 | "Effect": "Allow", 6 | "Action": "sts:AssumeRole", 7 | "Principal": { 8 | "Service": "lambda.amazonaws.com" 9 | }, 10 | "Sid": "" 11 | } 12 | ] 13 | } -------------------------------------------------------------------------------- /examples/basic/main.tf: -------------------------------------------------------------------------------- 1 | module "lambda_python" { 2 | source = "../../" 3 | 4 | aws_profile = "default" 5 | aws_region = "eu-west-1" 6 | 7 | pip_path = ".venv/bin/pip" 8 | 9 | lambda_name = "lambda_example" 10 | lambda_api_name = "lambda_example_api" 11 | lambda_iam_name = "lambda_example_iam" 12 | 13 | api_stage_name = "dev" 14 | api_resource_path = "example" 15 | api_http_method = "POST" 16 | } 17 | -------------------------------------------------------------------------------- /examples/basic/README.md: -------------------------------------------------------------------------------- 1 | # Basic Python Lambda function example 2 | 3 | Configuration in this directory deploys simple python script to AWS Lambda. Script writes all requests into cloudwatch logs. 4 | 5 | ## Usage 6 | 7 | To run this example you need to execute: 8 | ```bash 9 | $ terraform init 10 | $ terraform plan -out=basic.tfplan 11 | $ terraform apply -auto-approve basic.tfplan 12 | ``` 13 | 14 | Note that this configuration might create resources which cost money. Run `terraform destroy` when you don't need these resources anymore. 15 | 16 | ## Outputs 17 | 18 | | Name | Description | 19 | |------|-------------| 20 | | api\_gateway | The API Gateway for receiving webhooks by Lambda function | 21 | 22 | ## Test 23 | 24 | Send POST request to `` url to test Lambda function. If you send data using flag `-d ` you should receive same data as a response. 25 | ```bash 26 | $ curl -X POST -d pong 27 | 28 | "pong" 29 | ``` 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Vitaly Khabarov 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /examples/basic/lambda/main.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | ''' 3 | Echo service as a Lambda function 4 | ''' 5 | 6 | import os 7 | import sys 8 | import json 9 | import logging 10 | from pprint import pformat 11 | 12 | # Hack to use dependencies from lib directory 13 | BASE_PATH = os.path.dirname(__file__) 14 | sys.path.append(BASE_PATH + "/lib") 15 | 16 | LOGGER = logging.getLogger(__name__) 17 | logging.getLogger().setLevel(logging.INFO) 18 | 19 | def response(status=200, headers=None, body=''): 20 | ''' 21 | http://www.awslessons.com/2017/lambda-api-gateway-internal-server-error/ 22 | ''' 23 | if not body: 24 | return {'statusCode': status} 25 | 26 | if headers is None: 27 | headers = {'Content-Type': 'application/json'} 28 | 29 | return { 30 | 'statusCode': status, 31 | 'headers': headers, 32 | 'body': json.dumps(body) 33 | } 34 | 35 | def lambda_handler(event, context): 36 | ''' 37 | This function is called on HTTP request. 38 | It logs the request and an execution context. Then it returns body of the request. 39 | ''' 40 | LOGGER.info("%s", pformat({"Context" : vars(context), "Request": event})) 41 | return response(status=200, body=event['body']) 42 | 43 | 44 | if __name__ == '__main__': 45 | # Do nothing if executed as a script 46 | pass 47 | -------------------------------------------------------------------------------- /variables.tf: -------------------------------------------------------------------------------- 1 | variable "aws_profile" { 2 | type = string 3 | default = "default" 4 | description = "Name of configured AWS profile to use for Lambda provision" 5 | } 6 | 7 | variable "aws_region" { 8 | type = string 9 | default = "eu-west-1" 10 | description = "Region where to provision Lambda" 11 | } 12 | 13 | variable "pip_path" { 14 | type = string 15 | default = "/usr/local/bin/pip" 16 | description = "Path to your pip installation" 17 | } 18 | 19 | variable "lambda_name" { 20 | type = string 21 | default = "lambda_test" 22 | description = "Lambda function name" 23 | } 24 | 25 | variable "lambda_iam_name" { 26 | type = string 27 | default = "lambda_iam" 28 | description = "Name of IAM for Lambda" 29 | } 30 | 31 | variable "lambda_api_name" { 32 | type = string 33 | default = "lambda_api" 34 | description = "Name of API Gateway for Lambda" 35 | } 36 | 37 | variable "api_stage_name" { 38 | type = string 39 | default = "dev" 40 | description = "API Gateway Stage" 41 | } 42 | 43 | variable "api_resource_path" { 44 | type = string 45 | default = "lambda_resource" 46 | description = "API Gateway Path" 47 | } 48 | 49 | variable "api_http_method" { 50 | type = string 51 | default = "GET" 52 | description = "Method to trigger Lambda through API Gateway" 53 | } 54 | 55 | variable "iam_additional_policy" { 56 | type = string 57 | default = "" 58 | description = "Additional IAM Policy for Lambda function" 59 | } 60 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Terraform module for AWS Lambda Python function deployment 2 | 3 | Terraform module which prepares and deploys python lambda function and prepares all necessities for it in AWS infrastructure. 4 | 5 | ## Features 6 | * Downloads python dependencies from requirements.txt to `lambda/lib` directory 7 | * Archives lambda function with all dependencies into `lambda.zip` 8 | * Creates IAM policy, lambda function, API Gateway and CloudWatch log group 9 | * Creates IAM policy with additional rules 10 | * Deploy lambda function 11 | * Possible to use with python virtualenv 12 | 13 | ## Usage 14 | 15 | ### Preparation 16 | * Put logic into `lambda_handler` in `lambda/main.py` 17 | * Put your Lambda function requirements into `requirements.txt` 18 | 19 | ### Configuration example 20 | ```hcl 21 | module "lambda_python" { 22 | source = "express42/lambda-python/aws" 23 | 24 | aws_profile = "default" 25 | aws_region = "eu-west-1" 26 | 27 | pip_path = "/usr/bin/pip" 28 | 29 | lambda_name = "lambda_example" 30 | lambda_api_name = "lambda_example_api" 31 | lambda_iam_name = "lambda_example_iam" 32 | 33 | api_stage_name = "dev" 34 | api_resource_path = "example" 35 | api_http_method = "POST" 36 | 37 | iam_additional_policy = <