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

(feature/0457-support-amazon-cloudfront-function): Support Amazon Clo… #1127

1 change: 1 addition & 0 deletions docs/configuration/cloud-providers/aws.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ sidebar_label: Amazon Web Services
- API Gateway
- Access control lists
- CloudFront distributions
- CloudFront functions
- CloudWatch Dashboards
- CloudWatch alarms
- CloudWatch metrics
Expand Down
1 change: 1 addition & 0 deletions policy.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
"apigateway:GET",
"cloudwatch:GetMetricStatistics",
"cloudfront:ListDistributions",
"cloudfront:Functions",
"cloudfront:ListTagsForResource",
"cloudwatch:DescribeAlarms",
"cloudwatch:ListTagsForResource",
Expand Down
1 change: 1 addition & 0 deletions providers/aws/aws.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ func listOfSupportedServices() []providers.FetchDataFunction {
ec2.Instances,
eks.KubernetesClusters,
cloudfront.Distributions,
cloudfront.Functions,
dynamodb.Tables,
ecs.Clusters,
ecs.TaskDefinitions,
Expand Down
115 changes: 115 additions & 0 deletions providers/aws/cloudfront/functions.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package cloudfront

import (
"context"
"fmt"
"time"

log "github.com/sirupsen/logrus"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/cloudfront"
"github.com/aws/aws-sdk-go-v2/service/cloudwatch"
"github.com/aws/aws-sdk-go-v2/service/cloudwatch/types"
. "github.com/tailwarden/komiser/models"
. "github.com/tailwarden/komiser/providers"
"github.com/tailwarden/komiser/utils"
)

const (
freeTierInvocations = 2000000
jolo-dev marked this conversation as resolved.
Show resolved Hide resolved
costPerInvocation = 0.0000001
)

func Functions(ctx context.Context, client ProviderClient) ([]Resource, error) {
resources := make([]Resource, 0)
var config cloudfront.ListFunctionsInput
cloudfrontClient := cloudfront.NewFromConfig(*client.AWSClient)

tempRegion := client.AWSClient.Region
client.AWSClient.Region = "us-east-1"
cloudwatchClient := cloudwatch.NewFromConfig(*client.AWSClient)
client.AWSClient.Region = tempRegion
Copy link
Contributor

Choose a reason for hiding this comment

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

🙌


for {
output, err := cloudfrontClient.ListFunctions(ctx, &config)
if err != nil {
return resources, err
}

for _, function := range output.FunctionList.Items {
metricsInvocationsOutput, err := cloudwatchClient.GetMetricStatistics(ctx, &cloudwatch.GetMetricStatisticsInput{
StartTime: aws.Time(utils.BeginningOfMonth(time.Now())),
EndTime: aws.Time(time.Now()),
MetricName: aws.String("FunctionInvocations"),
Namespace: aws.String("AWS/CloudFront"),
Dimensions: []types.Dimension{
types.Dimension{
Name: aws.String("FunctionName"),
Value: function.Name,
},
},
Period: aws.Int32(3600),
Statistics: []types.Statistic{
types.StatisticSum,
},
})

if err != nil {
log.Warnf("Couldn't fetch invocations metric for %s", *function.Name)
return resources, err
}

invocations := 0.0
if metricsInvocationsOutput != nil && len(metricsInvocationsOutput.Datapoints) > 0 {
invocations = *metricsInvocationsOutput.Datapoints[0].Sum
}
if invocations > freeTierInvocations {
invocations -= freeTierInvocations
}

monthlyCost := invocations * costPerInvocation

outputTags, err := cloudfrontClient.ListTagsForResource(ctx, &cloudfront.ListTagsForResourceInput{
Resource: function.FunctionMetadata.FunctionARN,
})

tags := make([]Tag, 0)

if err == nil {
for _, tag := range outputTags.Tags.Items {
tags = append(tags, Tag{
Key: *tag.Key,
Value: *tag.Value,
})
}
}

resources = append(resources, Resource{
Provider: "AWS",
Account: client.Name,
Service: "CloudFront",
ResourceId: *function.FunctionMetadata.FunctionARN,
Region: client.AWSClient.Region,
Name: *function.Name,
Cost: monthlyCost,
Tags: tags,
FetchedAt: time.Now(),
Link: fmt.Sprintf("https://%s.console.aws.amazon.com/cloudfront/v3/home?region=%s#/functions/%s", client.AWSClient.Region, client.AWSClient.Region, *function.Name),
})
}

if aws.ToString(output.FunctionList.NextMarker) == "" {
break
}
config.Marker = output.FunctionList.NextMarker
}
log.WithFields(log.Fields{
"provider": "AWS",
"account": client.Name,
"region": client.AWSClient.Region,
"service": "CloudFront",
"resources": len(resources),
}).Info("Fetched resources")
return resources, nil
}