Making sure your web app is properly secured and performing quickly is a constant challenge. We frequently work with clients to address their unique requirements in this space. In a recent example, we turned to some efficient and cost-effective solutions to properly secure an app and even improve performance.
As technologists, we have all heard horror stories about application exploits, and many of us have experienced them firsthand. A few years ago, I encountered one myself when a colleague at another company came to me with a problem. The web application he supported showed signs of unauthorized access. After some digging, we discovered that the site had been hit with a SQL injection attack, allowing access to the application database and arbitrary PHP command execution, including the creation of admin users in the app. The system had been completely compromised, and while the root cause was a bug in their third-party application framework, there were additional steps that could have been taken to prevent this from happening. One of those that I recommended was the addition of a content delivery network (CDN) with an integrated web application firewall (WAF) that, if properly implemented, would both protect from application-layer vulnerabilities and help with ongoing performance issues they had also been experiencing. These incidents happen with alarming frequency, and they appear in many different forms. There are numerous other examples of other hacks and data breaches that underscore how critical it is these days to implement proper defenses for any web application.
Security, Performance & Automation
From an infrastructure architecture perspective, two of the most important aspects in any system or application are security and performance efficiency. AWS offers numerous security and performance benefits as a leading cloud provider, with Amazon CloudFront and AWS WAF serving as primary examples. These features integrate with each other to provide a solution that accelerates web application performance while also providing critical protections for many of the most common malicious attack vectors.
Another important element in cloud infrastructure deployment is automation—creating version controlled, reproducible environments through infrastructure-as-code. AWS has many entry points for automation, but the one most relevant to this topic is CloudFormation. This is a JSON or YAML template-driven feature that automates infrastructure stack creation, modification, and deletion through controlled, auditable events.
A client recently asked us to put together a solution for accelerating and protecting their public-facing web app. To give an overview of the relevant parts of the solution, we had the application hosted in an AWS VPC, running on EC2 instances. This also included a public-facing Elastic Load Balancer (ELB)—the newer Application Load Balancers (ALBs) would also work—that distributed traffic across the instances. We planned to add CloudFront and WAF to the environment, but a key part of protecting this type of setup is ensuring that traffic to the ELB must route through CloudFront and not bypass the WAF protections we put in place. There are a couple great approaches to this:
Limit access to the ELB using security groups containing CloudFront IPs.
Inject custom HTTP headers to requests at CloudFront to identify it as valid traffic and set the origin to require the custom header (see here for more info).
Design considerations made the first option more practical in our case, so we’ll delve into that, but both are worth exploring. Finally, to enable us to declare all the components of our solution and orchestrate our deployment, we used CloudFormation, which the environment already leveraged significantly.
Figure 1 – CloudFront and WAF linked to a web app environment
This AWS Security Blog article describes all the components and steps to lock down your security groups, but this is a manual setup process per environment. We took this a step further and integrated it into CloudFormation. Our EC2 instances and ELB were already defined, so the first step was to create a CloudFront distribution in the template. This is a customized resource tailored to the required client protocols, origin protocols, caching behavior, etc. In this case, both HTTP and HTTPS client protocols were required through to the origin ELB. Since the number of CloudFront IP ranges recently grew too large to fit into a single security group when using multiple protocols (i.e., HTTP and HTTPS), we needed two security groups applied to the ELB, each created in the template with the correct tags: “Name”: “cloudfront”, “AutoUpdate”: “true”, and “Protocol”: “http” or “https”.
We proceeded to create other resources described in the solution using CloudFormation, including the IAM policy, IAM role, the Lambda function (available from Amazon on GitHub), and the SNS subscription trigger. The Lambda function itself would be unwieldy to fit in the CloudFormation template, so we packaged that into an S3 bucket with versioning enabled, so that future updates to the function could be triggered using the S3 object version property. The function will assume the IAM role and target the security groups identified using the tags listed above. The security groups must be linked to the ELB within the template to take effect. To enable the SNS subscription as a Lambda trigger, there is an extra, not-quite-intuitive, step required to grant permission for the topic to invoke the function. This results in something like the following for the Lambda function and SNS subscription resources:
"Description": "Lambda function to update ELB security groups, restricting traffic through CloudFront/WAF",
After executing the change in CloudFormation, the function would be listed in the AWS Lambda Console. To test the function and pre-populate the security groups with CloudFront IP addresses, you can configure a sample event in the console and retrieve the md5 hash returned in the error message, then update the sample event with the md5 hash and execute again.
At that point, the web app performance was accelerated through the Amazon CloudFront CDN. Going forward, whenever Amazon updates CloudFront IP addresses, they will be published to the SNS topic, which will trigger the Lambda function and automatically update the ELB security groups. Traffic to the ELB will only be allowed through CloudFront, although configuring another security group on the ELB with an IP whitelist for testing purposes may be helpful. Linking other security groups also enables a phased approach to CloudFront and WAF implementation by still permitting client traffic directly to the ELB, allowing a DNS-based cutover in Route53 (or your DNS provider of choice) followed by removal of the open security group from the ELB.
The next goal was to secure the app from web-based attacks and DDoS. There are many ways to accomplish this, and to help achieve a comprehensive baseline level of protection, we implemented the AWS WAF Security Automations as a secondary CloudFormation stack. This solution integrates with CloudFront distributions and uses a combination of automated rules, patterns, and manual lists to help block many common attacks:
Cross-site scripting (XSS)
Scanners and probes
Known attacker origins (IP reputation lists)
Bots and scrapers
This is an AWS-managed template, so the deployment is generally quick, provided that you have a CloudFront distribution and certain traffic statistics about the app, such as peak requests per minute, etc. It is possible to select which protections to enable during the deployment, based on parameters in the CloudFormation template, and it is also possible to change the behavior of certain rules after deployment. For example, we changed the action of certain rules from Block to Count for a short time so we could monitor the rules for any client impact before fully enabling the protection. Additionally, we pointed the logging location for the WAF solution to our existing CloudFront access logs bucket, so that HTTP flood protection can monitor request thresholds and respond accordingly. A useful modification to Amazon’s WAF template in this scenario is to export the Web ACL ID for use in the stack containing the CloudFront distribution through a cross-stack reference. This would enable linking WAF to our CloudFront distribution and activating the protections for the web app without making manual changes in the console.
An Efficient and Cost-Effective Solution
This solution represents a flexible and scalable answer to increasing web app performance and security in a way that is easily reproducible for the client in additional environments. We were able to achieve these things using tools and frameworks that the client was already familiar with in an efficient and cost-effective way.
Are you interested in optimizing and securing your AWS deployments using automated, repeatable methods? Credera has extensive experience in cloud infrastructure design and implementation. If you have questions or would like to discuss cloud and infrastructure solutions, contact us at firstname.lastname@example.org.