|
| 1 | +# Lambda@Edge On CloudFront |
| 2 | + |
| 3 | +This project demonstrates how to use Lambda@Edge and a CloudFront distribution |
| 4 | +to manipulate a request at the edge. We pass a querystring from one HTML page to |
| 5 | +a second HTML page using a redirect initiated via the Lambda@Edge viewer request |
| 6 | +function. |
| 7 | + |
| 8 | +## Pre-requisites |
| 9 | + |
| 10 | +* Terraform 0.12.x |
| 11 | +* An AWS account |
| 12 | + |
| 13 | +## Deploying |
| 14 | + |
| 15 | +**NOTE**: You must use the AWS Northern Virginia region (`us-east-1`) because in |
| 16 | +order to replicate Lambda@Edge functions to all regions, AWS requires that you |
| 17 | +are deploying your functions into this region only. This requirement may be |
| 18 | +relaxed in the future but this is the reality at the moment. |
| 19 | + |
| 20 | +### Prepare to run terraform |
| 21 | + |
| 22 | +These steps include: |
| 23 | + |
| 24 | +* Install Terraform 0.12.x |
| 25 | +* Clone this repository |
| 26 | +* Change into the `terraform/` directory |
| 27 | +* Run `terraform init` |
| 28 | +* Exporting environment variable for your AWS_PROFILE and AWS_REGION. This looks |
| 29 | + something like: |
| 30 | + |
| 31 | + `export AWS_PROFILE=blah && export AWS_REGION=us-east-1` |
| 32 | + |
| 33 | + Another option is to use [aws-vault](https://github.com/99designs/aws-vault) |
| 34 | + to manage AWS credentials. I personally use aws-vault, as you will see in the |
| 35 | + commands used below. |
| 36 | + |
| 37 | +### Deploy |
| 38 | + |
| 39 | +1. Run the following commands to deploy: |
| 40 | + |
| 41 | +``` |
| 42 | +aws-vault exec profile_name -- terraform plan -out=devplan.$(date +%F.%H.%M.%S).out |
| 43 | +``` |
| 44 | + |
| 45 | +This will create a Terraform plan file, which you can then apply with the command: |
| 46 | + |
| 47 | +``` |
| 48 | +aws-vault exec profile_name -- terraform apply devplan.2020-01-19.08.44.07.out |
| 49 | +``` |
| 50 | + |
| 51 | +**NOTE**: Terraform apply` it can take up to 20 or 30 minutes to replicate the |
| 52 | +Lambda@Edge function across all the (supported) AWS regions. You may not want to |
| 53 | +replicate and that would be fine, but doesn't fit the model of using all AWS |
| 54 | +regions to run Lambda at their edge locations. If you don't create the Lambda |
| 55 | +function in the `us-east-1` (N. Virginia) region, as far as I understand (at |
| 56 | +this time) it will not be replicated to all AWS regions. |
| 57 | + |
| 58 | +The distribution name will be shown in the output at the end, something such as: |
| 59 | + |
| 60 | +``` |
| 61 | +Outputs: |
| 62 | +
|
| 63 | +cloudfront_distribution_id = E2U0H2YCG3AYFU |
| 64 | +s3_bucket = terraform-20200118165546224400000003 |
| 65 | +``` |
| 66 | + |
| 67 | +Then you will need to determine the distribution domain name. This can be shown |
| 68 | +with the command, using the ID shown in the above output: |
| 69 | + |
| 70 | +``` |
| 71 | +aws-vault exec --no-session experiments_user1 -- aws cloudfront get-distribution --id E2U0H2YCG3AYFU |
| 72 | +``` |
| 73 | + |
| 74 | +Look in the JSON output for the Distribution.DomainName, it appears like: |
| 75 | + |
| 76 | +``` |
| 77 | +"DomainName": "d11e7fgi9rskgz.cloudfront.net", |
| 78 | +``` |
| 79 | + |
| 80 | +2. After the cloudfront distribution is deployed successfully, you need to place |
| 81 | + the HTML and script resources in the S3 bucket. You need to know the S3 |
| 82 | + bucket previous step to do this. Run the command: |
| 83 | + |
| 84 | +``` |
| 85 | +aws-vault exec profile_name -- aws s3 cp index.html s3://terraform-20200118165546224400000003/ --acl public-read |
| 86 | +aws-vault exec profile_name -- aws s3 cp other.html s3://terraform-20200118165546224400000003/ --acl public-read |
| 87 | +aws-vault exec profile_name -- aws s3 cp script.js s3://terraform-20200118165546224400000003/ --acl public-read |
| 88 | +``` |
| 89 | + |
| 90 | +### Re-deploying |
| 91 | + |
| 92 | +Remember from the above NOTE, when running `terraform apply` it can take up to |
| 93 | +20 or 30 minutes to replicate the Lambda@Edge function across all the |
| 94 | +(supported) AWS regions. You may not want to replicate and that would be fine, |
| 95 | +but doesn't fit the model of using all AWS regions to run Lambda at their edge |
| 96 | +locations. If you don't create the Lambda function in the `us-east-1` (N. |
| 97 | +Virginia) region, as far as I understand (at this time) it will not be |
| 98 | +replicated to all AWS regions. |
| 99 | + |
| 100 | +## Viewing the site |
| 101 | + |
| 102 | +Browse to your index page using the CloudFront DomainName you obtained above. In |
| 103 | +our example that URL is(this URL is no longer valid!!! I have since removed the |
| 104 | +CloudFront distribution.): |
| 105 | + |
| 106 | +https://d11e7fgi9rskgz.cloudfront.net/index.html |
| 107 | + |
| 108 | +Type a GitHub user name in the input box, and hit the Submit button. You will be |
| 109 | +redirected to the other.html page, and the querystring will be used to query the |
| 110 | +GitHub API, returning that user's information in the response section of the web |
| 111 | +page. |
| 112 | + |
| 113 | +### Troubleshooting |
| 114 | + |
| 115 | +If you don't see the output you expect, i.e. the GitHub user information, there |
| 116 | +are a couple ways to find problems. |
| 117 | + |
| 118 | +1. Open the Developer Console in Chrome (or whatever browser you are using) |
| 119 | +2. Go to AWS CloudWatch Logs, open the Log Group `/aws/lambda/us-east-1.viewer_request_lambda` or `/aws/lambda/us-east-1.origin_response_lambda`, and view the recent logs, to see if there are server side errors. |
| 120 | + |
| 121 | +## Tearing down the infrastructure |
| 122 | + |
| 123 | +Deleting the replicated Lambda functions takes time, just like deploying the |
| 124 | +Lambda to all replicated regions does. In order to perform this deletion in a |
| 125 | +timely fashion, you first need to remove the function association in the |
| 126 | +CloudFront distribution via the AWS console. Browse to CloudFront in the AWS |
| 127 | +console. Then click on your distribution ID from above. Go to the "Behaviors" |
| 128 | +tab and select the "Origin or Origin Group" `s3_origin`, then choose "Edit". |
| 129 | +Finally at the bottom of the "Edit Behavior" page, click on the X for both the |
| 130 | +"Viewer Request" and "Origin Response" CloudFront Events. Once these are removed |
| 131 | +select "Yes, Edit", which is apparently the "Save" button in CloudFront. |
| 132 | + |
| 133 | +Now, wait 20-30 minutes before running `terraform destroy` to remove the |
| 134 | +infrastucture via Terraform. |
| 135 | + |
| 136 | +This wait time is required because Terraform will attempt to remove the Lambda |
| 137 | +function before the CloudFront distribution, and this won't work because the |
| 138 | +function association is still defined between the CloudFront distribution and |
| 139 | +the Lambda function. We must remove this association first before attempting to |
| 140 | +tear down all the infrastructure via Terraform. |
| 141 | + |
| 142 | +If you don't do this step, you would likely see the following error message: |
| 143 | + |
| 144 | +``` |
| 145 | +Error: Error deleting Lambda Function: InvalidParameterValueException: Lambda was unable to delete arn:aws:lambda:us-east-1:592431548397:function:origin_response_lambda:5 because it is a replicated function. Please see our documentation for Deleting Lambda@Edge Functions and Replicas. |
| 146 | + status code: 400, request id: e47befaa-79f8-42c3-84f8-774df27f31d4 |
| 147 | +``` |
| 148 | + |
| 149 | +Either wait 20-30 minutes to re-run `terraform destroy` or remove the |
| 150 | +association with the CloudFront distribution as described above. |
| 151 | + |
| 152 | +Enjoy! |
0 commit comments