Abstract Image for Deploying AWS CloudFormation through GitLab

Lambda web scraper project (week 5)

What Happened Last Week

I've continued building Python-based Lambda functions on Amazon in a GitLab project aws-lambda-price-grabber...

The first part of the week I created the AWS Cloud Formation scripts necessary to be able to recreate this solution. I wanted to get the tool to save prices but creating the template took up more time than I expected. 

I also noticed I had neglected to unit test some parts and started refactoring to be able to write some new tests. A code coverage utility might have highlighted the fact earlier! I am learning Python progressively but quickly ran into problems with my new unit tests. They were not running, lesson learnt: Not only does the filename of a unit test need to start with the word test_ but also the method names.

Stuff I had done in previous weeks like downloading the libraries, zipping and manually uploading is no longer required, so I changed my scripts in the build directory. One the other things I did was to add an open-source license to the project.

Setting up using the AWS CloudFormation Stack

A stack is a collection of AWS resources that you can manage as a single unit. This allows you to create a template for a solution, which is what I did last week.

There are 2 ways you can setup; run my deployment/aws-create-foundation.json template using the CloudFormation console. OR having created a new user with administrator-level access and access keys, you can do this via the AWS CLI, which is the way I would recommend since if you are going to install, then you are likely to want to make changes and the CLI will help you do everything faster:

aws cloudformation create-stack --stack-name grabber-foundation  --template-body file://./deployment/aws-create-foundation.json --capabilities CAPABILITY_NAMED_IAM --parameters ParameterKey=S3BucketName,ParameterValue=aws-lambda-price-grabber

aws cloudformation delete-stack --stack-name grabber-foundation

The parameter value aws-lambda-price-grabber needs to be changed. An Amazon S3 bucket name is globally unique, no two people can use the same name. 

One problem I was not able to programmatically solve is updating the S3 bucket name which appears in the CI/CD pipeline and the CloudFormation template for creating the Lambda functions (you'll need to do that):

Once the above commands are run and the files updated, then you simply need to run the CI/CD pipeline.

How to trigger a GitLab CI/CD pipeline

Lessons learnt while creating a CloudFormation template

(1). You don't have to learn to create the CloudFormation (CF) scripts by hand, there is a CloudFormer tool that can reverse engineer the resources you have set up. I decided not to use it because it requires an EC2 machine which would cost. In retrospect, it probably would have been more cost efficient to try it because it took me about 9 hours to figure out everything to make my stack template.

(2). I found the AWS role documentation confusing, in particular, what the AssumeRolePolicyDocument was all about:

"CFNRole": {
  "Type": "AWS::IAM::Role",
  "Properties": {
    "RoleName": "AssumeRolePolicyDocument",
    "AssumeRolePolicyDocument": {
      "Version": "2012-10-17",
      "Statement": [
          "Effect": "Allow",
          "Principal": {
            "Service": "lambda.amazonaws.com"
          "Action": "sts:AssumeRole"

The CloudFormation AssumeRolePolicyDocument attribute for roles is found on the IAM screen under the tab "Trust Relationships", click the blue button to "edit", then copy paste to your template.

The CloudFormation AssumeRolePolicyDocument attribute for roles is found on the IAM screen under the tab

(3). The last lesson I want to share is about linking multiple policies with a role. In a CloudFormation template, you can't do that!

Over the last couple of weeks while setting up the role for my Lambda functions, I was creating a separate role for each kind of thing I wanted them to do:

  • Read/Write to S3 bucket.
  • Creating log entries.
  • Permissions to execute other functions.

I liked that because you then know exactly what the purpose of the permissions was for. Unfortunately, I found when running my CloudFormation template that only one of the policies I wanted was ever hooked up to my new role. So I merged the permissions into one policy. 

Deep Dive into Cloud Formation

Coming Next

I want to finish unit testing the Lambda function that invokes the grabber, get the solution saving prices it getting and send alerts.