Serverless & Terraform for your “functions” CI

The perfect CI for Serverless architectures (Image credits)

Serverless is a framework allowing you to deploy “functions” on various different cloud providers such as AWS Lambda or Google Cloud Functions in an easy & automated manner. Terraform allows you to automate the deployment of cloud-specific configurations such as AWS SNS topics, SQS queues, IAM roles, etc…

Terraform output

This article won’t go into the details of Terraform, you can read more in the documentation. The key point is that when “running” your Terraform, you will be able to return values: they are called outputs.

You can get the output variables as a JSON object by running this command:

$ terraform output -json

Now, let’s see how we can use this within Serverless.

Serverless `custom` configuration

Within your serverless.yml configuration, you can set custom variables. Using the file(...) processor, you can also run a JavaScript file.

Hint: what if such JavaScript file was reading the output of the terraform output -json command?

# serverless.yaml
# ...
# ...
FOO: ${self:custom.fromTerraform.foo_value}
fromTerraform: ${file(./terraform-outputs-as-variables.js)}

In the example above, an environment variable FOO will be available to all your functions. The value will be the foo_value variable returned by our JavaScript file. So how is this file looking like?

The JavaScript glue

This JavaScript file will be responsible for running the terraform output command, parsing it and returning the values in a format understandable by Serverless.

This file above will, based on the environment variable SERVERLESS_ENVIRONMENT , run the command in the production or staging folder, containing your different Terraform configurations.

We use it for more than environment variables

The serverless.yml example above is showing how to use such value coming from terraform output as environment variables. Indeed, you can use it for much more. We are, for example, using it for VPCs and Lambda IAM roles:

# serverless.yml
# ...
# ...
- ${self:custom.fromTerraform.security_group_id}
- ","
- ${self:custom.fromTerraform.subnet_ids}
# ...
handler: path/to/function.handler
role: ${self:custom.fromTerraform.tunstall_dump_lamba_role_arn}
- sns: ${self:custom.fromTerraform.tunstall_ingress_sns_topic_arn}
onError: ${self:custom.fromTerraform.sns_dlq_tunstall_dump_arn}

Enjoy! But don’t rush to functions, think about your monolith ;-)