Skip to content

feat: improved cost saving - pay per request #28

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

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 27 additions & 14 deletions .projenrc.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,39 @@
import { awscdk } from 'projen';
import { awscdk } from "projen";

const PROJECT_NAME = 'cdk-aws-wafv2-geofence-lib';
const PROJECT_NAME = "cdk-aws-wafv2-geofence-lib";
const PROJECT_DESCRIPTION =
'The cdk-aws-wafv2-geofence-lib is an AWS CDK construct library that adds a AWS WAFv2 with GeoBlocking and AWS Managed Rules for AppSync, API Gateway or an ALB.';
"The cdk-aws-wafv2-geofence-lib is an AWS CDK construct library that adds a AWS WAFv2 with GeoBlocking and AWS Managed Rules for AppSync, API Gateway or an ALB.";

const project = new awscdk.AwsCdkConstructLibrary({
author: 'ZeroDotFive',
authorAddress: 'ayoub.umoru@zerodotfive.com',
cdkVersion: '2.127.0',
author: "ZeroDotFive",
authorAddress: "ayoub.umoru@zerodotfive.com",
cdkVersion: "2.127.0",
majorVersion: 1,
defaultReleaseBranch: 'main',
defaultReleaseBranch: "main",
authorOrganization: true,
jsiiVersion: '~5.3.0',
jsiiVersion: "~5.3.0",
name: PROJECT_NAME,
projenrcTs: true,
repositoryUrl: 'https://github.com/ZDF-OSS/cdk-aws-wafv2-geofence-lib.git',
homepage: 'https://zerodotfive.com',
repositoryUrl: "https://github.com/ZDF-OSS/cdk-aws-wafv2-geofence-lib.git",
homepage: "https://zerodotfive.com",
description: PROJECT_DESCRIPTION,
keywords: ['aws', 'cdk', 'awscdk', 'aws-cdk', 'wafv2', 'aws-waf', 'aws-wafv2', 'geoblock'],
gitignore: [
'cdk.out/',
keywords: [
"aws",
"cdk",
"awscdk",
"aws-cdk",
"wafv2",
"aws-waf",
"aws-wafv2",
"geoblock",
],
bundledDeps: ['openai'],
gitignore: ["cdk.out/"],
bundledDeps: ["openai"],
});

project.github?.actions.set(
"actions/upload-artifact",
"actions/upload-artifact@v4.3.6"
);

project.synth();
118 changes: 66 additions & 52 deletions src/components/chatgpt-waf-log-evaluation.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import * as path from 'path';
import * as cdk from 'aws-cdk-lib';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import { Rule, Schedule } from 'aws-cdk-lib/aws-events';
import { LambdaFunction } from 'aws-cdk-lib/aws-events-targets';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Construct } from 'constructs';
import * as path from "path";
import * as cdk from "aws-cdk-lib";
import * as dynamodb from "aws-cdk-lib/aws-dynamodb";
import { Rule, Schedule } from "aws-cdk-lib/aws-events";
import { LambdaFunction } from "aws-cdk-lib/aws-events-targets";
import * as iam from "aws-cdk-lib/aws-iam";
import * as lambda from "aws-cdk-lib/aws-lambda";
import { Construct } from "constructs";

export interface IChatGPTWafLogEvaluationProps {
rule_scope: string;
Expand All @@ -20,87 +20,101 @@ export class ChatGPTWafLogEvaluation extends Construct {
prefix: string;
log_group: string;
chatgpt_log_check_intervall_minutes: number;
constructor(scope: Construct, id: string, props: IChatGPTWafLogEvaluationProps) {
constructor(
scope: Construct,
id: string,
props: IChatGPTWafLogEvaluationProps
) {
super(scope, id);
this.rule_scope = props.rule_scope;
this.prefix = 'alpha';
this.prefix = "alpha";
this.log_group = props.log_group;
this.chatgpt_log_check_intervall_minutes = props.chatgpt_log_check_intervall_minutes;
this.chatgpt_log_check_intervall_minutes =
props.chatgpt_log_check_intervall_minutes;

//Define DynamoDB
const table = new dynamodb.Table(this, 'waf-autoblock-db', {
const table = new dynamodb.Table(this, "waf-autoblock-db", {
tableName: `${this.prefix}-waf_ip_protection`,
partitionKey: { name: 'ip', type: dynamodb.AttributeType.STRING },
sortKey: { name: 'product', type: dynamodb.AttributeType.STRING },
partitionKey: { name: "ip", type: dynamodb.AttributeType.STRING },
sortKey: { name: "product", type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
});
this.table_name = table.tableName;

const waf_log_checker_lambda_role = new iam.Role(
this,
'waf-log-checker-lambda-role',
"waf-log-checker-lambda-role",
{
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
description: 'Lambda role that checks WAFv2 logs, talks to ChatGPT and stores results to DynamoDB.',
assumedBy: new iam.ServicePrincipal("lambda.amazonaws.com"),
description:
"Lambda role that checks WAFv2 logs, talks to ChatGPT and stores results to DynamoDB.",
managedPolicies: [
cdk.aws_iam.ManagedPolicy.fromAwsManagedPolicyName(
'service-role/AWSLambdaBasicExecutionRole',
"service-role/AWSLambdaBasicExecutionRole"
),
],
},
}
);


const chatGPTAPISecret = new cdk.aws_secretsmanager.Secret(
this,
'waf-chatgpt-secret',
"waf-chatgpt-secret",
{
description: 'Secret for ChatGPT API',
description: "Secret for ChatGPT API",
secretName: `${this.prefix}-chatgpt-api-key`,
},
}
);
waf_log_checker_lambda_role.addToPolicy(
new iam.PolicyStatement({
resources: ['*'],
actions: ['logs:*'],
}),
resources: ["*"],
actions: ["logs:*"],
})
);
if (props.notification_sns_arn) {
waf_log_checker_lambda_role.addToPolicy(
new iam.PolicyStatement({
resources: [props.notification_sns_arn],
actions: ['sns:Publish'],
}),
actions: ["sns:Publish"],
})
);
}

const waf_log_analysis_lambda = new lambda.Function(this, 'waf-log-check-lambda', {
runtime: lambda.Runtime.PYTHON_3_10,
code: lambda.Code.fromAsset(path.join(__dirname, '..', '..', 'lambda', 'log_analytics.zip')),
handler: 'index.handler',
role: waf_log_checker_lambda_role,
memorySize: 160,
architecture: lambda.Architecture.ARM_64,
//layers: [lambdaLayer],
description:
'Reads WAFv2 logs, makes ChatGPT evaluations and stores the results DynamoDB.',
environment: {
PRODUCT: 'ChatGPTBadIPs',
DB_NAME: table.tableName,
SCOPE: this.rule_scope,
LOG_GROUP: this.log_group,
SNS_ARN: props.notification_sns_arn,
SECRET_ID: chatGPTAPISecret.secretName,
LAST_LOG_MINUTES: this.chatgpt_log_check_intervall_minutes.toString(),
},
timeout: cdk.Duration.minutes(6),
});
const waf_log_analysis_lambda = new lambda.Function(
this,
"waf-log-check-lambda",
{
runtime: lambda.Runtime.PYTHON_3_10,
code: lambda.Code.fromAsset(
path.join(__dirname, "..", "..", "lambda", "log_analytics.zip")
),
handler: "index.handler",
role: waf_log_checker_lambda_role,
memorySize: 160,
architecture: lambda.Architecture.ARM_64,
//layers: [lambdaLayer],
description:
"Reads WAFv2 logs, makes ChatGPT evaluations and stores the results DynamoDB.",
environment: {
PRODUCT: "ChatGPTBadIPs",
DB_NAME: table.tableName,
SCOPE: this.rule_scope,
LOG_GROUP: this.log_group,
SNS_ARN: props.notification_sns_arn,
SECRET_ID: chatGPTAPISecret.secretName,
LAST_LOG_MINUTES: this.chatgpt_log_check_intervall_minutes.toString(),
},
timeout: cdk.Duration.minutes(6),
}
);

chatGPTAPISecret.grantRead(waf_log_analysis_lambda);
table.grantWriteData(waf_log_analysis_lambda);
table.grantReadData(waf_log_analysis_lambda);
new Rule(this, 'waf-chatgpt-analysis-rule', {
description: 'Schedule for the ChatGPT log analysis.',
schedule: Schedule.rate(cdk.Duration.minutes(this.chatgpt_log_check_intervall_minutes)),
new Rule(this, "waf-chatgpt-analysis-rule", {
description: "Schedule for the ChatGPT log analysis.",
schedule: Schedule.rate(
cdk.Duration.minutes(this.chatgpt_log_check_intervall_minutes)
),
targets: [new LambdaFunction(waf_log_analysis_lambda)],
});
}
Expand Down
Loading