├── terraform.tfstate ├── .gitignore ├── go.mod ├── Dockerfile ├── providers.tf ├── main.go ├── .github └── workflows │ └── docker.yml ├── Makefile ├── README.md ├── go.sum └── main.tf /terraform.tfstate: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | bin 2 | .DS_Store 3 | .terraform 4 | .vscode 5 | .idea/ -------------------------------------------------------------------------------- /go.mod: -------------------------------------------------------------------------------- 1 | module github.com/esenac/aws-lambda-go 2 | 3 | go 1.13 4 | 5 | require github.com/aws/aws-lambda-go v1.28.0 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM hashicorp/terraform 2 | 3 | LABEL maintainer="esenac" 4 | 5 | WORKDIR /srv 6 | 7 | ADD providers.tf . 8 | 9 | RUN terraform init 10 | -------------------------------------------------------------------------------- /providers.tf: -------------------------------------------------------------------------------- 1 | terraform { 2 | required_providers { 3 | aws = { 4 | version = "~> 2.0" 5 | } 6 | archive = { 7 | version = "~> 1.3.0" 8 | } 9 | } 10 | } 11 | 12 | provider "aws" { 13 | region = "us-east-1" 14 | } 15 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "context" 5 | "encoding/json" 6 | "net/http" 7 | "time" 8 | 9 | "github.com/aws/aws-lambda-go/events" 10 | "github.com/aws/aws-lambda-go/lambda" 11 | ) 12 | 13 | type timeEvent struct { 14 | Time string `json:"time"` 15 | } 16 | 17 | func handleRequest(ctx context.Context, request events.APIGatewayProxyRequest) (events.APIGatewayProxyResponse, error) { 18 | t := timeEvent{Time: time.Now().String()} 19 | b, err := json.Marshal(t) 20 | if err != nil { 21 | return events.APIGatewayProxyResponse{}, err 22 | } 23 | return events.APIGatewayProxyResponse{ 24 | StatusCode: http.StatusOK, 25 | Body: string(b), 26 | }, nil 27 | } 28 | 29 | func main() { 30 | lambda.Start(handleRequest) 31 | } 32 | -------------------------------------------------------------------------------- /.github/workflows/docker.yml: -------------------------------------------------------------------------------- 1 | name: Docker Image CI 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | 7 | jobs: 8 | 9 | build: 10 | 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - uses: actions/checkout@v2 15 | - name: Login to DockerHub 16 | uses: docker/login-action@v1 17 | with: 18 | username: ${{ secrets.DOCKERHUB_USERNAME }} 19 | password: ${{ secrets.DOCKERHUB_TOKEN }} 20 | - name: Set up QEMU 21 | uses: docker/setup-qemu-action@master 22 | with: 23 | platforms: all 24 | - name: Set up Docker Buildx 25 | id: buildx 26 | uses: docker/setup-buildx-action@master 27 | - name: Build the Docker image 28 | uses: docker/build-push-action@v2 29 | with: 30 | builder: ${{ steps.buildx.outputs.name }} 31 | context: . 32 | platforms: linux/amd64,linux/arm64 33 | push: true 34 | tags: esenac/terraform-aws:latest -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | build: 2 | docker build -t esenac/aws-lambda-go . 3 | 4 | compile: 5 | docker run -e GOOS=linux -e GOARCH=amd64 -v $$(pwd):/app -w /app golang:1.16 go build -ldflags="-s -w" -o bin/aws-lambda-go 6 | 7 | plan: compile 8 | docker run -v $$(pwd)/main.tf:/srv/main.tf -v $$(pwd)/terraform.tfstate:/srv/terraform.tfstate -v $$(pwd)/bin:/srv/bin -e AWS_ACCESS_KEY_ID=$$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$$AWS_SECRET_ACCESS_KEY -e AWS_DEFAULT_REGION=$$AWS_DEFAULT_REGION esenac/terraform-aws plan 9 | 10 | apply: compile 11 | docker run -v $$(pwd)/main.tf:/srv/main.tf -v $$(pwd)/terraform.tfstate:/srv/terraform.tfstate -v $$(pwd)/bin:/srv/bin -e AWS_ACCESS_KEY_ID=$$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$$AWS_SECRET_ACCESS_KEY -e AWS_DEFAULT_REGION=$$AWS_DEFAULT_REGION esenac/terraform-aws apply -auto-approve 12 | 13 | destroy: 14 | docker run -v $$(pwd)/main.tf:/srv/main.tf -v $$(pwd)/terraform.tfstate:/srv/terraform.tfstate -v $$(pwd)/bin:/srv/bin -e AWS_ACCESS_KEY_ID=$$AWS_ACCESS_KEY_ID -e AWS_SECRET_ACCESS_KEY=$$AWS_SECRET_ACCESS_KEY -e AWS_DEFAULT_REGION=$$AWS_DEFAULT_REGION esenac/terraform-aws destroy -auto-approve -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # aws-lambda-go 2 | 3 | Sample project to deploy an AWS Lambda function in Go using Terraform. 4 | 5 | ## How to 6 | 7 | ### Overview 8 | 9 | Commands are defined in `Makefile` and allow to perform Terraform commands in a Docker image, installing the required providers once. This is acheived by mounting files in the docker instead of the whole project folder, preventing to override `providers.tf` file (it's used in Dockerfile to install Terraform plugins). 10 | 11 | ### Build Docker image 12 | 13 | You have to build the Docker image containing Terraform and the required providers, so that you don't have to download Terraform binary to your machine. 14 | Anyway, this step is not required if you pull the latest image from [Docker Hub](https://hub.docker.com/repository/docker/esenac/terraform-aws). 15 | 16 | 17 | ### Compile source code 18 | 19 | In order to compile your source code, run `make compile`. This command executes `go build` command in a Go docker, so that you don't have to install Go on your machine. 20 | 21 | _Note: this step isn't mandatory for `plan` and `apply` commands, since it's automatically executed._ 22 | 23 | ### Terraform commands 24 | 25 | Terraform `plan`, `apply` and `destroy` commands are available on the corresponding `make` commands. 26 | 27 | ## TODO 28 | 29 | We still have to handle remote state, that's why `terraform.tfstate` is mounted in the Docker. -------------------------------------------------------------------------------- /go.sum: -------------------------------------------------------------------------------- 1 | github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= 2 | github.com/aws/aws-lambda-go v1.28.0 h1:fZiik1PZqW2IyAN4rj+Y0UBaO1IDFlsNo9Zz/XnArK4= 3 | github.com/aws/aws-lambda-go v1.28.0/go.mod h1:jJmlefzPfGnckuHdXX7/80O3BvUUi12XOkbv4w9SGLU= 4 | github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 5 | github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU= 6 | github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 7 | github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= 8 | github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 9 | github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= 10 | github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 11 | github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= 12 | github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc= 13 | github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 14 | github.com/stretchr/testify v1.6.1 h1:hDPOHmpOpP40lSULcqw7IrRb/u7w6RpDC9399XyoNd0= 15 | github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= 16 | github.com/urfave/cli/v2 v2.2.0/go.mod h1:SE9GqnLQmjVa0iPEY0f1w3ygNIYcIJ0OKPMoW2caLfQ= 17 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 18 | gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 19 | gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= 20 | gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 21 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776 h1:tQIYjPdBoyREyB9XMu+nnTclpTYkz2zFM+lzLJFO4gQ= 22 | gopkg.in/yaml.v3 v3.0.0-20200615113413-eeeca48fe776/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 23 | -------------------------------------------------------------------------------- /main.tf: -------------------------------------------------------------------------------- 1 | data "archive_file" "zip" { 2 | type = "zip" 3 | source_file = "bin/aws-lambda-go" 4 | output_path = "aws-lambda-go.zip" 5 | } 6 | 7 | resource "aws_lambda_function" "time" { 8 | function_name = "time" 9 | filename = "aws-lambda-go.zip" 10 | handler = "aws-lambda-go" 11 | source_code_hash = "data.archive_file.zip.output_base64sha256" 12 | role = "${aws_iam_role.iam_for_lambda.arn}" 13 | runtime = "go1.x" 14 | memory_size = 128 15 | timeout = 10 16 | } 17 | 18 | resource "aws_iam_role" "iam_for_lambda" { 19 | name = "iam_for_lambda" 20 | 21 | assume_role_policy = <