How to use CloudFormation to deploy Frontend Apps to S3 and Serverless Application Repository
If you ever wanted to automatically deploy front-end web applications along with CloudFormation resources, your time has come. We created a custom CloudFormation resource that uploads files into an S3 bucket. You no longer need to deploy a SPA app or a static website separately from the back-end. Just do it all together with standard
sam deploy or
aws cloudformation deploy commands.
The custom resource works by using a Python Lambda Layer that will handle the uploads of your files to an S3 bucket, so you don’t have to write any additional code. The layer is easy to use in SAM and Cloudformation templates, even for beginners. We also published an example project that demonstrates how to package and deploy web site code using Cloudformation.
The deployment layer is available under the MIT license. You can get the source code from the GitHub repository and create it in your AWS account, or just use the public version available from the following ARN:
How it works
We want to upload front-end files to S3. The standard S3 resources in CloudFormation are used only to create and configure buckets, so you can’t use them to upload files. But CloudFormation can automatically version and upload Lambda function code, so we can trick it to pack front-end files by creating a Lambda function and point to web site assets as its source code.
That Lambda, of course, won’t really be able to run, because it contains just the web site files. This is where our layer comes in. When you attach it to the Lambda function, it will make it executable. Running the Lambda function will upload the source code to an S3 bucket.
The only thing left is to ensure that the function is invoked during a CloudFormation stack deployment. We can do that by creating a custom resource linked to a Lambda function. The layer we created is intended to run in this mode, so it automatically supports CloudFormation custom resource workflows. With the custom resource, you can configure the upload parameters, such as the target bucket, access control lists and caching properties, so it’s easy to create web sites.
Cloudformation usually updates custom resources only when their parameters change, not when the underlying Lambda function changes. Because we’re using the web site assets as the source of the Lambda function, we need to additionally ensure that any changes to those assets automatically trigger the update. To do that, we’ll make SAM publish a new named version of the Lambda function with each update of the site assets, using the
AutoPublishAlias flag. We now get an automatically incrementing number whenever asset files change, so we can add that version as a parameter of the custom resource, and CloudFormation will trigger the function and upload the changed files automatically.
How to use this in your web application
Define a new CloudFormation template and add AWS Serverless Transformation
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::Serverless-2016-10-31' Resources:
Add a Serverless Function Resource, call it
SiteSource and as its
Layerproperty pointing to the
CodeUri, pointing to a folder inside the project (for example
web-site), containing the frontend files,
- set the
python3.6, because the layer is using it, and,
- set the
600(10 minutes, as we want to be sure in case our website is too big or our network is bit slow).
Policiesto the Properties too. In the Policies, specify
S3FullAccessPolicypolicy template with a parameter
BucketNamereferencing the target bucket for uploads,
- Set an
AutoPublishAliaswith the value of
live. This will generate a new version of the Lambda and make it available as a retrievable property on every CloudFormation deployment.
SiteSource Lambda Function should like like the following code:
SiteSource: Type: AWS::Serverless::Function Properties: Layers: - arn:aws:lambda:us-east-1:145266761615:layer:s3-deployment:4 CodeUri: web-site/ AutoPublishAlias: live Runtime: python3.6 Handler: deployer.resource_handler Timeout: 600 Policies: - S3FullAccessPolicy: BucketName: !Ref TargetBucket
Define a AWS::CloudFormation::CustomResource with a name
DeploymentResource. Set its
Properties to have:
ServiceTokenwhich takes the
Arnattribute from the
Versionproperty referencing a string variable
TargetBucketproperty referencing a the target bucket,
Aclset to a pre-canned S3 access policy. For example,
public-readfor publicly accessible web sites and,
CacheControlMaxAgeset to 600.
DeploymentResource: Type: AWS::CloudFormation::CustomResource Properties: ServiceToken: !GetAtt SiteSource.Arn Version: !Ref "SiteSource.Version" TargetBucket: !Ref TargetBucket Acl: 'public-read' CacheControlMaxAge: 600
The last thing to add is an S3 Bucket Resource in the template, where we want to deploy our frontend code. You can call it
TargetBucket: Type: AWS::S3::Bucket
Here is the complete code:
AWSTemplateFormatVersion: 2010-09-09 Transform: 'AWS::Serverless-2016-10-31' Resources: TargetBucket: Type: AWS::S3::Bucket SiteSource: Type: AWS::Serverless::Function Properties: Layers: - arn:aws:lambda:us-east-1:145266761615:layer:s3-deployment:4 CodeUri: web-site/ AutoPublishAlias: live Runtime: python3.6 Handler: deployer.resource_handler Timeout: 600 Policies: - S3FullAccessPolicy: BucketName: !Ref TargetBucket DeploymentResource: Type: AWS::CloudFormation::CustomResource Properties: ServiceToken: !GetAtt SiteSource.Arn Version: !Ref "SiteSource.Version" TargetBucket: !Ref TargetBucket Acl: 'public-read' CacheControlMaxAge: 600
Publishing Frontend Apps to AWS Serverless Application Repository
The biggest benefit of this stack is that it allows you to publish your frontend applications or components to the AWS Serverless Application Repository (SAR, from now on). Previously, it was very hard to deploy any SPAs, static websites or even frontend components to SAR. Just before Re:Invent 2018, AWS announced support for CloudFormation Custom Resources, allowing you to extend Cloudformation. Using that, our stack allows you to deploy any kind of React.js, Vue.js, Angular or any kind of frontend, and combine it with your backend stacks too. Additionally, using them as Nested Applications, you can combine them with other published serverless applications that are available on Serverless Application Repository.
You can also see this example in the Github repository
/example folder by clicking here.
You can just use the usual SAM or Cloudformation deployment commands to create this stack on AWS.