Using AWS ECS Fargate with Cloudfront and WAF
Introduction
I have already presented the concepts of AWS ECS in my previous post, which you can review for more information. In this article, I will guide you on how to deploy a docker image with AWS ECS on Cloudfront using WAF, monitored by Cloudwatch. Additionally, we will setup alerts to automatically send emails and notifications to Telegram when a WAF rule is matched.
Prerequisites
You can continue using the NestJS source code that I guided you through in previous articles or use your own project. After pushing the docker image to ECR, please proceed to the following sections.
Detail
The workflow will be as follows:
- Requests are sent to Cloudfront.
- Here, the rules in WAF take effect to block requests with security issues, preventing them from reaching our Load Balancer.
- Cloudwatch will aggregate results based on metrics; if the required threshold is reached, it will send an email and a notification to Telegram for alerting.
- If the request has no issues, Cloudfront will attach a secret header to that request and point it to the Load Balancer; only then will the request be processed to return the corresponding response.
First, create a .env file with the following information:
The information regarding CDK_DEFAULT_REGION, CDK_US_REGION, BUCKET, IMAGE, CUSTOM_HEADER, and VERIFY_SECRET is similar to what I mentioned in previous posts; please replace them with your corresponding values.
TELEGRAM_TOKEN, CHAT_ID: This is the Telegram information used to send messages.
EMAIL: Any email address of yours.
Use AWS CDK to create the file lib/ecs-fargate-stack.ts
- Parts such as creating the vpc, fargateService, granting permissions for the task, health checks, and granting permissions for the S3 Bucket are also similar to the previous article I used.
- GetCFPrefixList: We will still only allow Cloudfront's prefix list to access the Load Balancer.
- The only new part is saving this.loadBalancer to be used when creating the next stack.
Next is the file lib/telegram-notifier-lambda.ts used to handle sending notifications to Telegram.
- The main content of this part is simply using Telegram information to call the API and send messages to the group chat.
- You can freely change the content in the text section as appropriate; this is the message content that will show up on Telegram.
Next is the file lib/waf-cloudfront-cloudwatch-stack.ts
- wafv2.CfnWebACL: Creates a Web Access Control List for the Cloudfront scope including free Managed Rules developed by AWS itself. Adding them to the Web ACL will provide your NestJS application with a comprehensive "shield" from the exploitation layer to the behavioral layer.
- AWSManagedRulesCommonRuleSet
- This is the most important and mandatory rule set.
- Function: Protects against common vulnerabilities in the OWASP Top 10 category. It blocks requests with unusual sizes, strange control characters, or file system intrusion attempts (Local File Inclusion).
- AWSManagedRulesSQLiRuleSet
- Protects your data layer from code injection attacks.
- Function: Detects and stops SQL Injection (SQLi) attempts in the Query String, Body, or Header. Very important if your NestJS app connects to MySQL, PostgreSQL, or MongoDB.
- AWSManagedRulesAmazonIpReputationList
- Uses "collective intelligence" from Amazon's massive network.
- Function: AWS collects a list of IP addresses acting as Botnets, malware distribution sources, or IPs that have previously attacked other AWS customers. This rule automatically blocks these "tainted" IPs before they reach your CloudFront.
- AWSManagedRulesKnownBadInputsRuleSet
- Prevents automated vulnerability scanning tools.
- Function: Hackers often use automated scripts to find .env files, /admin, or sensitive configuration files. This rule set identifies patterns of common attack tools and blocks them immediately.
- Custom rule GeneralRateLimitRule
- Used to block IP Addresses that access too many times within a fixed period. Here I use 10 requests in 5 minutes for easy testing; you can change it according to your needs.
- I have specifically explained how this rule works in previous posts; you can review them for more information.
- cfDist: This creates the Cloudfront distribution, which needs the loadBalancer created from the previous stack, and adds a dependency to ensure Cloudfront is only created after the WAF has been created.
- telegramLambda: Note to update the path to the telegram file created above.
- sns.Topic: Creates an SNS Topic and adds 2 subscriptions so that when a message is sent to the topic, it will trigger an email and call the lambda function to send a message to Telegram.
- cloudwatch.Alarm:
- metricName: "BlockedRequests" only triggers when a request is blocked.
- The parameters below mean it will calculate the total number of blocked requests in 1 minute; if it is greater than or equal to 1, it will alert. This is the configuration I use for testing; you can update it according to your needs.
- statistic: "Sum"
- period: cdk.Duration.minutes(1)
- threshold: 1
- comparisonOperator: cloudwatch.ComparisonOperator.GREATER_THAN_OR_EQUAL_TO_THRESHOLD
- addAlarmAction: When the alert is activated, it will send a message to the SNS Topic.
You can use AWS Cli to see the managed rules that AWS supports for Cloudfront.
Next is the file lib/ecs-fargate-waf-cloudfront-stack.ts to create 2 stacks in 2 different regions.
Update the file bin/aws-cdk.ts
You need to run bootstrap again first because we need to deploy stacks into 2 different regions.
After deploying, the result looks like this:
Note that after deploying the stack, an email will be sent to the address you used to subscribe to the SNS Topic; you need to confirm it to receive other emails when there are notifications (which is when a request is blocked).
The resources have been successfully created on the AWS Console.
Checking the API shows the following results.
When a request is blocked, there will be corresponding notifications sent to email and Telegram.
Happy coding!
Comments
Post a Comment