Tuesday, March 23, 2021

Create AWS WebACL for CloudFront using AWS SDK v2

 


 
In this post we will use AWS GO API V2 to create a WebACL, and then we will associate it with a CloudFront distribution.

Before starting, make sure to setup credentials and region as specified in this post.


We will use the AWS SDK version 2, so the imports should be:



import (
"context"
"fmt"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/config"
"github.com/aws/aws-sdk-go-v2/service/cloudfront"
"github.com/aws/aws-sdk-go-v2/service/wafv2"
"github.com/aws/aws-sdk-go-v2/service/wafv2/types"
)

const aclName = "my-webacl"

type Acl struct {
}



Start by setting a connection to AWS:



awsConfig, err := config.LoadDefaultConfig(context.Background(), config.WithRegion("us-east-1"))
if err != nil {
panic(err)
}



Next, create the WebACL. We create an example of WebACL rule to block any request with query string that have a specific suffix.



func (a *Acl) createWebAcl(wafClient *wafv2.Client) string {
statement := types.Statement{
ByteMatchStatement: &types.ByteMatchStatement{
FieldToMatch: &types.FieldToMatch{
QueryString: &types.QueryString{},
},
PositionalConstraint: "ENDS_WITH",
SearchString: []byte("/3"),
TextTransformations: []types.TextTransformation{
{
Priority: 1,
Type: "NONE",
},
},
},
}

rule := types.Rule{
Name: aws.String("rule-1"),
Priority: 1,
Action: &types.RuleAction{
Block: &types.BlockAction{},
},
Statement: &statement,
VisibilityConfig: &types.VisibilityConfig{
CloudWatchMetricsEnabled: false,
SampledRequestsEnabled: false,
MetricName: aws.String("my-rule-metric"),
},
}

aclInput := wafv2.CreateWebACLInput{
DefaultAction: &types.DefaultAction{
Block: &types.BlockAction{},
},
Name: aws.String(aclName),
Rules: []types.Rule{rule},
Scope: "CLOUDFRONT",
VisibilityConfig: &types.VisibilityConfig{
CloudWatchMetricsEnabled: false,
SampledRequestsEnabled: false,
MetricName: aws.String("my-rule-metric"),
},
}

acl, err := wafClient.CreateWebACL(context.Background(), &aclInput)
if err != nil {
panic(err)
}

fmt.Printf("acl output %+v\n", *acl)

return * acl.Summary.ARN
}



Next we can update the CloudFront distribution to use this WebACL.

Notice that you cannot use the WebACL API to associate the WebACL to the CloudFront distribution (why? ask AWS team. I guess they did not want to make it easy).



func (a *Acl) updateDistribution(awsConfig *aws.Config, aclId string) {
getConfigInput := cloudfront.GetDistributionConfigInput{
Id: aws.String("E1Y55CUPVONMHF"),
}
cloudFrontClient := cloudfront.NewFromConfig(*awsConfig)

distributionConfigOutput, err := cloudFrontClient.GetDistributionConfig(context.Background(), &getConfigInput)
if err != nil {
panic(err)
}

fmt.Printf("distribution acl: %v\n", *distributionConfigOutput.DistributionConfig.WebACLId)
distributionInput := cloudfront.UpdateDistributionInput{
DistributionConfig: distributionConfigOutput.DistributionConfig,
Id: aws.String("E1Y55CUPVONMHF"),
IfMatch: distributionConfigOutput.ETag,
}
distributionInput.DistributionConfig.WebACLId = aws.String(aclId)

_, err = cloudFrontClient.UpdateDistribution(context.Background(), &distributionInput)
if err != nil {
panic(err)
}
}



That's it, we have a WebACL assigned to our CloudFront distribution.



Final Notes


I've added this post, since there are just no good examples of how to do this.

I hope you will find this useful.

No comments:

Post a Comment