Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(docs): Add serverless application guide #786

Merged
merged 3 commits into from
Jun 22, 2021

Conversation

ansgarm
Copy link
Member

@ansgarm ansgarm commented Jun 18, 2021

Adds a guide explaining the end to end serverless example.

rendered version
Repo with end to end serverless example: https://github.com/hashicorp/cdktf-integration-serverless-example (also linked in guide)

What do you think having this guide inside the newly created docs/full-guide directory? Happy to move it elsewhere if that seems off.

Resolves #733

@ansgarm ansgarm changed the title Add serverless application guide chore(docs): Add serverless application guide Jun 18, 2021
@jsteinich
Copy link
Collaborator

Looks interesting. Some possible future changes to the example:

  • Lock down the S3 bucket so that all requests need to go through CloudFront.
  • Use the S3 bucket object resource instead of syncing
  • Use IAM Floyd or similar to provide code first iam policies
  • Call out that the different environments are different stack

@ansgarm
Copy link
Member Author

ansgarm commented Jun 18, 2021

Thank you for the great feedback, @jsteinich!

Lock down the S3 bucket so that all requests need to go through CloudFront.

We need to use the web hosting feature of the S3 bucket to serve the index.html for all unknown paths (due to the frontend being a single page application). I could not find a way to restrict the S3 bucket website hosting to only CloudFront and directly serving the files does not work for the application. Is there a way to achieve this that I overlooked?

Use the S3 bucket object resource instead of syncing

I thought about that as well. However it didn't feel right. Currently the frontend has ~10ish files that are deployed to the S3 Bucket, however that number could grow substantially for a bigger application. This would result in the same number of (generated) S3 bucket object resources in Terraform.
One alternative could be to build a custom resource / custom Terraform resource which takes care of the copying. As far as I know the AWS CDK bundles files in a zip and uses a Lambda that extracts the files into an S3 Bucket for a similar use case.

Use IAM Floyd or similar to provide code first iam policies

Great idea. Noted.

Call out that the different environments are different stack

Done.

@jsteinich
Copy link
Collaborator

I thought about that as well. However it didn't feel right. Currently the frontend has ~10ish files that are deployed to the S3 Bucket,

Makes sense. For some reason I was thinking it was single file

@jsteinich
Copy link
Collaborator

I could not find a way to restrict the S3 bucket website hosting to only CloudFront and directly serving the files does not work for the application. Is there a way to achieve this that I overlooked?

Here's some code that we have:

private VariableConditionResource<CloudfrontOriginAccessIdentity> ApplyBucketPolicy(S3Bucket bucket)
        {
            {//public
                var publicBucketPolicy = new PolicyDocument
                {
                    Statements = {new S3().ToGetObject().OnObject(Config.WebSiteDomain, "*").ForPublic()}
                };

                new VariableConditionResource<S3BucketPolicy>(!Config.UseCloudFront,
                    new S3BucketPolicy(this, "public_s3_policy", new S3BucketPolicyConfig
                    {
                        Bucket = bucket.Id,
                        Policy = publicBucketPolicy.ToJson()
                    }), true);
            }

            {//cloudfront
                new VariableConditionResource<S3BucketPublicAccessBlock>(Config.UseCloudFront,
                    new S3BucketPublicAccessBlock(this, "access_block", new S3BucketPublicAccessBlockConfig
                    {
                        Bucket = bucket.Id,
                        IgnorePublicAcls = true
                    }));

                var accessIdentity = new VariableConditionResource<CloudfrontOriginAccessIdentity>(Config.UseCloudFront,
                    new CloudfrontOriginAccessIdentity(this, "cf_access_identity", new CloudfrontOriginAccessIdentityConfig
                    {
                        Comment = "Access S3 bucket content only through CloudFront"
                    }));

                var cfBucketPolicy = new PolicyDocument
                {
                    Statements =
                    {
                        new S3().ToGetObject().OnObject(Config.WebSiteDomain, "*")
                            .For(accessIdentity.StringValue(nameof(accessIdentity.Resource.IamArn)))
                    }
                };
                
                new VariableConditionResource<S3BucketPolicy>(Config.UseCloudFront,
                    new S3BucketPolicy(this, "cf_s3_policy", new S3BucketPolicyConfig
                    {
                        Bucket = bucket.Id,
                        Policy = cfBucketPolicy.ToJson()
                    }));

                return accessIdentity;
            }
        }

//within cloud front distribution
Origin = new ICloudfrontDistributionOrigin[]
                {
                    new CloudfrontDistributionOrigin
                    {
                        DomainName = bucket.BucketDomainName,
                        OriginId = $"s3-origin-{bucket.Id}",
                        OriginPath = "",
                        
                        S3OriginConfig = new ICloudfrontDistributionOriginS3OriginConfig[]
                        {
                            new CloudfrontDistributionOriginS3OriginConfig
                            {
                                OriginAccessIdentity = cfAccessIdentity.StringValue(nameof(cfAccessIdentity.Resource.CloudfrontAccessIdentityPath))
                            }
                        }
                    }
                },

@ansgarm
Copy link
Member Author

ansgarm commented Jun 22, 2021

Thanks @jsteinich!
Added it to the ideas for future iterations.

Copy link
Contributor

@DanielMSchmidt DanielMSchmidt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Quite a different style from my version, but I like it!

@ansgarm ansgarm merged commit 3c91ba6 into main Jun 22, 2021
@ansgarm ansgarm deleted the add-serverless-application-guide branch June 22, 2021 18:29
@github-actions
Copy link
Contributor

I'm going to lock this pull request because it has been closed for 30 days. This helps our maintainers find and focus on the active issues. If you've found a problem that seems related to this change, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.

@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 10, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

End-to-end serverless workflow
3 participants