How to create and deploy an AWS CloudFormation custom provider in less than 5 minutes
Tags: aws
Published: 2023-12-25 11:44:07

---
title: How to create and deploy an AWS CloudFormation custom provider in less than 5 minutes
published: true
date: 2023-03-08 23:08:00 UTC
tags: AWS
canonical_url: https://xebia.com/blog/how-to-create-and-deploy-an-aws-cloudformation-custom-provider-in-less-the-5-minutes/
---

In this blog I will show you how to create and deploy an AWS CloudFormation custom provider in less than 5 minutes using a Python [copier](https://copier.readthedocs.io/) template. To create a custom resource in CloudFormation, is really simple. You just implement a create, update and delete method in a Lambda and you are done. But that is the easy part: you still have to create zip files, unit tests, documentation, demo’s, CI/CD deployment pipelines and more. This [copier](https://copier.readthedocs.io/) template has it all!

- it creates the [source code](#source-code-directory) for a custom resource provider
- all the [build commands](#available-build-commands) you need to build, test and deploy your provider
- it provides [re-recordable unit tests](#re-recordable-unit-tests)using [botocore stubber recorder](https://pypi.org/project/botocore-stubber-recorder/)
- it [deploys lambdas](#deploy-provider-to-all-regions) to buckets in all AWS regions in the world
- it supports [semantic versioning](#version-your-custom-resource-provider) using [git-release-tag](https://github.com/binxio/git-release-tag)
- it provides a ready-to-deploy [CI/CD pipeline](#deploy-cicd-pipeline) on [AWS Codebuild](https://aws.amazon.com/codebuild/)

## getting started!

Let’s say you want to create a custom resource for a Custom Domain of an AWS AppRunner service, because it does not yet exist. To get started, type:

```
$ pip install copier
$ copier https://github.com/binxio/cloudformation-custom-provider-template /tmp/cfn-app-runner-custom-domain-provider

🎤 the name of your custom resource type?
   AppRunnerCustomDomain
🎤 The name of your resource provider project?
   cfn-app-runner-custom-domain-provider
🎤 The name of your Python module?
   cfn_app_runner_custom_domain_provider
🎤 a short description for the custom provider?
   manages app runner custom domains
🎤 Python version to use
   3.9
🎤 Your full name?
   Mark van Holsteijn
🎤 Your email address?
   mark.vanholsteijn@xebia.com
🎤 the URL to git source repository?
   https://github.com/binxio/cfn-app-runner-custom-domain-provider
🎤 the AWS profile name
   integration-test
🎤 the AWS region name
   eu-central-1
🎤 prefix for the S3 bucket name to store the lambda zipfiles?
   binxio-public
🎤 Access to lambda zip files?
   public

> Running task 1 of 1: [[! -d .git]] && ( git init && git add . && git commit -m 'initial import' && git tag 0.0.0) || exit 0
Initialized empty Git repository in /tmp/cfn-app-runner-custom-domain-provider/.git/
[main (root-commit) b2ce863] initial import
 21 files changed, 619 insertions(+)
...

```

### source code directory

The copier generates the following source code directory:

```
.
├── Dockerfile.lambda # creates the zip file
├── Makefile.mk # generic build steps for the provider
├── Makefile # customization of build steps
├── Pipfile # python virtual environment definition
├── cloudformation
│   ├── cfn-app-runner-custom-domain-provider.yaml # to deploy the provider
│   ├── cicd-pipeline.yaml # to deploy the Codebuild CI/CD pipeline
│   └── demo.yaml # to deploy the demo
├── doc
│   └── AppRunnerCustomDomain.md # start documentation of resource
├── pyproject.toml # Python project definition
├── setup.cfg # Python package settings
├── tox.ini # Python test definitions
├── src
│   └── cfn_app_runner_custom_domain_provider
│   ├── __init__.py
│   ├── app_runner_custom_domain.py # custom resource definition source
│   └── logger.py
├── tests
│   └── crud
│   ├── __init__.py
│   ├── base
│   │   └── __init__.py
│   └── test_crud.py # custom resource definition test

```

That is all that is needed to create a project with a working custom provider for the resource `AppRunnerCustomDomain`. When you change to the directory and type:

```
$ pipenv install -d
$ make deploy-provider
$ make demo

```

Your provider will be up-and-running in less than 5 minutes!

## Available build commands

to see a list of all of available build commands, type:

```
$ make help

build - build the lambda zip file
fmt - formats the source code using black
test - run python unit tests
test-record - run python unit tests, while recording the boto3 calls
test-templates - validate CloudFormation templates

deploy - AWS lambda zipfile to bucket
deploy-all-regions - AWS lambda zipfiles to all regional buckets
undeploy-all-regions - deletes AWS lambda zipfile of this release from all buckets in all regions

deploy-provider - deploys the custom provider
delete-provider - deletes the custom provider

deploy-pipeline - deploys the CI/CD deployment pipeline
delete-pipeline - deletes the CI/CD deployment pipeline

deploy-demo - deploys the demo stack
delete-demo - deletes the demo stack

tag-patch-release - create a tag for a new patch release
tag-minor-release - create a tag for a new minor release
tag-major-release - create a tag for new major release

```

### Run the unit tests

To run the unit tests, type:

```
$ make test

```

The unit test will test the scaffold implementation generated by the [botocore stubber recorder](https://pypi.org/project/botocore-stubber-recorder/). To create unit tests for your resource, edit the source code in `./tests/`. To implement your custom resource, edit the source code under `./src/`.

### Re-recordable unit tests

Once you have your custom resource provider, it undoubtedly does some AWS API calls. The [botocore stubber recorder](https://pypi.org/project/botocore-stubber-recorder/) library records the actual calls and generate the stub. The unit tests can be run in recording mode, where the test is against a real AWS account. To run your unit tests as integration test against a live system and record the stubs, type:

```
$ make test-record

```

To run the unit tests with the newly created stubs, type:

```
$ make test

```

The integration tests are run against the AWS profile and region you specified. To add a new test, type:

```
$ botocore-stubber-recorder --test-name failed_create

```

### Deploy the zip file to the bucket

To copy the zip file with the source code of the AWS Lambda of the custom resource provider, the buckets must already exist. If they do not, type:

```
$ aws s3 mb s3://<bucket-prefix>-<bucket-region>

```

The build system expects the bucket name to consists of the prefix and the region name. This allows the provider to be made available for use in all regions.

### Deploy the custom resource provider into the account

To configure the run-time parameters and permissions of the your provider, change the CloudFormation template in the directory `./cloudformation`. Once that is done, type:

```
$ make deploy-provider

```

### Deploy the custom resource demo

To deploy a CloudFormation stack with an example use of the custom resource, type:

```
$ make deploy-demo

```

### Version your custom resource provider

Semantic versioning of the provider is implemented using the utility [git-release-tag](https://github.com/binxio/git-release-tag). To version your custom resource provider, you can use the following commands:

```
make tag-patch-release - create a tag for a new patch release
make tag-minor-release - create a tag for a new minor release
make tag-major-release - create a tag for new major release

```

This will: \* runs the pre-tag command in the file `./release`, to update all files with references to the semantic version \* commit all outstanding changes in the workspace \* tag the commit with the new version. To show the current version of the workspace, type:

```
make show-version

```

### Deploy provider to all regions

To deploy the current version of your provider to all regions, type:

```
make deploy-all-regions

```

This assumes you have buckets in all regions with the defined prefix.

### Deploy CI/CD pipeline

To deploy the CI/CD pipeline based on AWS Codebuild, make sure that the AWS account can access the source repository. If that is the case, type:

```
make deploy-pipeline

```

Now, every time you tag a new release, it will automatically be deployed to all regions.

## Conclusion

This [copier](https://copier.readthedocs.io/) template provides everything you need to quickly build, deploy and maintain a new custom AWS CloudFormation Provider! If you have any questions, problems or feedback feel free to contact me or add issues at https://github.com/binxio/cloudformation-custom-provider-template. If you want to create your resource provider in Golang, we also have a [solution](https://xebia.com/blog/how-to-create-and-deploy-a-golang-aws-cloudformation-custom-provider-in-less-the-5-minutes/) for that!

* * *

Photo by [Saffu](https://unsplash.com/@saffu?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText) on [Unsplash](https://unsplash.com/photos/E4kKGI4oGaU?utm_source=unsplash&utm_medium=referral&utm_content=creditCopyText)

The post [How to create and deploy an AWS CloudFormation custom provider in less than 5 minutes](https://xebia.com/blog/how-to-create-and-deploy-an-aws-cloudformation-custom-provider-in-less-the-5-minutes/) appeared first on [Xebia](https://xebia.com).