Serverless InSpec using Native Ruby on AWS Lambda

InSpec is a compliance as code tool that helps organizations perform compliance checks in an automated fashion. Last year I detailed creating an AWS Lambda function that ran an InSpec scan by compiling a version of Ruby and then making that available to the Lambda function to run InSpec since it is written in Ruby. Toward the end of last year I was excited to hear that AWS was officially supporting Ruby as a native programming language for Lambda functions (https://aws.amazon.com/blogs/compute/announcing-ruby-support-for-aws-lambda/).

All the code referenced in this post can be found in this github repository (https://github.com/martezr/serverless-inspec).

Serverless Framework

With the previous iteration of serverless InSpec I created a cloudformation template that handled a lot of the heavy lifting to create the lambda function but even then there a number of tasks that weren’t automated. As I was learning how AWS Layers worked with Ruby I came across a blog post that covers how to use the ServerLess Framework (https://serverless.com/) to handle pretty much all of the dirty work for me (https://blog.francium.tech/deploying-ruby-gems-with-native-extensions-on-aws-lambda-using-the-serverless-toolkit-9079e34db2ab).

The result is a single yaml file that declares the Lambda function deployment and all of it’s associated pieces (IAM role, Lambda Layer, Log Group, etc.). The ServerLess Framework uses a Cloud Formation stack to manage and update the deployment.

The ServerLess Framework makes the deployment extremely simple but we still need to get everything setup like compiling the gems for the Lambda layer and installing the Serverless Framework. To simplify the build process I’ve created a “builder” AWS EC2 instance to do all the buidling and deployment.

Builder

The builder is an AWS EC2 instance that is used for the two primary tasks needed to be accomplished to deploy the Lambda function. The first one is installing the serverless framework and the second is building all of the gems required for InSpec. A docker container is used to build all of the gems.

AWS EC2 Instance Terraform

The github repository contains Terraform code for provisioning an EC2 instance for the builder. The Terraform code creates an IAM role with the following permisions to allow the the serverless framework running on the EC2 instance to provision the Lambda function.

Once Docker has been installed and started on the EC2 instance we need to go through the process of building the InSpec gems in a folder structure that works with what the AWS Lambda function is expecting. We need to create a Gemfile that will be used by bundler to build the gems.

source 'https://rubygems.org'
gem 'inspec'

Once the Gemfile has been created we just need to run the lambci/lambda docker container to build the gems. The code below is based upon the folder structure in the github repo (https://github.com/martezr/serverless-inspec) of the example.

Lambda Deployment

With everything setup and ready to go we just need to deploy the Lambda function using the serverless command sls deploy which will package our code along with layer and upload them to an S3 bucket. Once they’ve been uploaded the lambda function and layer will be created.

Change directory to /serverless-inspec/code and modify the serverless.yml file by changing the INSPEC_PROFILE to the desired InSpec profile to run and the S3_DATA_BUCKET to the S3 bucket where the JSON output will be stored. The ruby code currently only supports scanning AWS and doesn’t not support scanning instances at this point in time.