pat
pat

Reputation: 16226

How can I use a git repository as an AWS Lambda source within Terraform?

I'm working within Terraform to configure an AWS Lambda - and initially, I've had the JS file that is the entirety of the lambda function within my Terraform directory:

data "archive_file" "auth_requests" {
  type        = "zip"
  source_file = "${path.module}/auth_requests/index.js"
  output_path = "${path.module}/auth_requests.zip"
}

resource "aws_lambda_function" "auth_requests" {
  function_name    = "auth_requests"
  filename         = "${data.archive_file.auth_requests.output_path}"
  role             = "${aws_iam_role.auth_requests.arn}"
  handler          = "index.handler"
  source_code_hash = "${data.archive_file.auth_requests.output_base64sha256}"
  runtime          = "nodejs8.10"
}

However, it's clear that the Lambda function should get its own git repo, rather than living within our broader Terraform repo. Is there a way to use Terraform to source files from a git repo (and then brought into the generated archive)?

I could define the lambda's GitHub repo as a resource, but then what would be the next steps for getting it cloned/updated so the archive_file can refer to it? Or can a Terraform module be repurposed for something like this?

Upvotes: 10

Views: 6700

Answers (2)

waterproof
waterproof

Reputation: 5184

Another option is to use Terraform for your infrastructure setup & maintenance, but then manage deploys directly through Github Actions.

Your Terraform setup will just bootstrap an initial version of the function code, with subsequent updates coming straight from GitHub. Use the ignore_changes meta-argument so that Terraform doesn't get mad about the drift.

terraform-repo/lambda.tf will set up the lambda but ignore changes from deploy:

resource "aws_lambda_function" "lambda" {
  function_name = ...
  role          = ...
  handler       = ...

  # just include a basic "hello world, this is a stub" handler in here
  filename  = '${module}/lambda_stub.zip' 

  lifecycle {
    ignore_changes = [
      'last_modified',
      'source_code_hash'
    ]
  }
}

Code-repo/.github/workflows/deploy_lambda.yml will actually do the deploy:

name: Deploy Lambda

on:
    push:
        branches:
            - main
    workflow_dispatch:

jobs:
  deploy_zip:
    name: deploy lambda function
    runs-on: ubuntu-latest

    steps:
      - uses: actions/checkout@v2

      - name: Zip up the code
        run: zip -r build.zip ./src

      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Update Lambda code
        run: aws lambda update-function-code --function-name=${{ secrets.LAMBDA_NAME }} --zip-file=fileb://build.zip

This way you can deploy quickly without doing an entire terraform plan cycle, and you can still use terraform to update and maintain your infrastructure.

Upvotes: 1

moebius
moebius

Reputation: 2269

Assuming you use a Github repository to store your JS function, you can make use of the Github Content API to download a zip of the repo using curl:

curl -L -o <output zip filename> https://<github repo url>/zipball/master

You can achieve this in Terraform using the External provider instead of the Archive provider:

data "external" "download_function" {
  program = ["curl", "-L", "-o", 
"${path.module}/auth_requests.zip", "${var.github_repo_url}"]
}

The downside is that you now have an external dependency (curl).

Upvotes: 1

Related Questions