この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。
WafCharm is AWS WAF automation service
Benifits:
●Stronger Defense Create and set rules that are optimal for the user's environment.
●Automation by AI Complete automation of WAF operations from applying rules to handling new vulnerabilities.
●Extensive Support System Reliable support system in case of false-positives. 24/7 technical support (excluding entry plans)
Hands on:

CloudFormationTemplate for Deploying AWS Resources:
AWSTemplateFormatVersion: 2010-09-09
Description: WafCharm production machine
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Kinesis Data Firehose Configuration"
Parameters:
- BufferSize
- BufferInterval
- CompressionFormat
Parameters:
SystemPrefix:
Description: "System prefix of each resource names."
Type: String
Default: "xxx"
ExportServerStackName:
Description: the name of Server Stack
Type: String
Default: xxx-server-stack
StreamName:
Type: "String"
# AllowedPattern: "aws-waf-logs-[A-Za-z0-9]+"
Default: "aws-waf-logs-xxx-wafcharm"
BufferSize:
Type: String
Default: '5'
BufferInterval:
Type: String
Default: '60'
CompressionFormat:
Type: String
AllowedValues: [GZIP,HADOOP_SNAPPY,Snappy,UNCOMPRESSED,ZIP]
Default: 'GZIP'
Resources:
# --------
# WAF
# --------
WebACL:
Type: AWS::WAFv2::WebACL
Properties:
Name: !Sub '${SystemPrefix}-wafcharm'
DefaultAction:
Allow: {}
Description: AWS WAFv2 WebACL
Scope: REGIONAL
VisibilityConfig:
CloudWatchMetricsEnabled: true
MetricName: !Sub '${SystemPrefix}'
SampledRequestsEnabled: true
WAFAssociation:
Type: AWS::WAFv2::WebACLAssociation
Properties:
WebACLArn: !GetAtt WebACL.Arn
ResourceArn :
Fn::ImportValue: !Sub ${ExportServerStackName}-LoadBalancerArn
S3Bucket:
# https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-s3-bucket.html
Type: "AWS::S3::Bucket"
DependsOn: "WAFAssociation"
DeletionPolicy: "Delete"
Properties:
BucketName: !Sub 'aws-waf-logs-${AWS::AccountId}'
LifecycleConfiguration:
Rules:
-
ExpirationInDays: "365"
Id: s3-lifecycle-rule
NoncurrentVersionExpirationInDays: "365"
Status: "Enabled"
IAMRoleForKinesis:
Type: "AWS::IAM::Role"
DependsOn: "S3Bucket"
DeletionPolicy: "Delete"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
Service: "firehose.amazonaws.com"
Action: "sts:AssumeRole"
Condition:
StringEquals:
sts:ExternalId: !Ref "AWS::AccountId"
MaxSessionDuration: 3600
Path: "/role/"
Policies:
-
PolicyName: !Sub policy-kinesis-${StreamName}
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action: "glue:GetTableVersions"
Resource: "*"
-
Effect: "Allow"
Action:
- "s3:AbortMultipartUpload"
- "s3:GetBucketLocation"
- "s3:GetObject"
- "s3:ListBucket"
- "s3:ListBucketMultipartUploads"
- "s3:PutObject"
Resource:
- !Sub arn:aws:s3:::aws-waf-logs-${AWS::AccountId}
- !Sub arn:aws:s3:::aws-waf-logs-${AWS::AccountId}/*
-
Effect: "Allow"
Action: "logs:PutLogEvents"
Resource: !Sub arn:aws:logs:${AWS::Region}:${AWS::AccountId}:log-group:/aws/kinesisfirehose/${StreamName}:*
-
Effect: "Allow"
Action:
- "kinesis:DescribeStream"
- "kinesis:GetShardIterator"
- "kinesis:GetRecords"
Resource: !Sub arn:aws:kinesis:${AWS::Region}:${AWS::AccountId}:stream/${StreamName}
RoleName: FirehoseRoleForWafCharm
KinesisFirehose:
# https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-kinesisfirehose-deliverystream.html
Type: "AWS::KinesisFirehose::DeliveryStream"
DeletionPolicy: "Delete"
Properties:
DeliveryStreamName: !Ref StreamName
DeliveryStreamType: "DirectPut"
S3DestinationConfiguration:
BucketARN: !Sub arn:aws:s3:::aws-waf-logs-${AWS::AccountId}
BufferingHints:
IntervalInSeconds: !Ref BufferInterval
SizeInMBs: !Ref BufferSize
CloudWatchLoggingOptions:
Enabled: True
LogGroupName: !Sub /aws/kinesisfirehose/${StreamName}
LogStreamName: !Ref StreamName
CompressionFormat: !Ref CompressionFormat
# ErrorOutputPrefix: !Sub error/${StreamName}/
Prefix: !Sub ${StreamName}/
RoleARN: !GetAtt IAMRoleForKinesis.Arn
Tags:
- Key: Name
Value: xxx-firehose-waf-logs
IAMRoleForLambda:
Type: "AWS::IAM::Role"
DependsOn: "KinesisFirehose"
DeletionPolicy: "Delete"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
Service: "lambda.amazonaws.com"
Action: "sts:AssumeRole"
ManagedPolicyArns:
- "arn:aws:iam::aws:policy/AWSLambdaExecute"
MaxSessionDuration: 3600
Path: "/role/"
# PermissionsBoundary: String
Policies:
-
PolicyName: "wafcharm-waflog-s3-read"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- "s3:GetObject"
Resource:
- !Sub arn:aws:s3:::aws-waf-logs-${AWS::AccountId}/*
-
PolicyName: "wafcharm-waf-log-s3-put"
PolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Action:
- "s3:*"
Resource:
- "arn:aws:s3:::wafcharm.com/"
- "arn:aws:s3:::wafcharm.com/*"
RoleName: "LambdaRoleForWafCharm"
Lambda:
# https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-function.html
Type: "AWS::Lambda::Function"
DeletionPolicy: "Delete"
Properties:
Code:
ZipFile: |
'use strict';
const toBucket = process.env.WAFCHARM_BUCKET || 'wafcharm.com';
const toPath = process.env.WAFCHARM_PATH || 'waflog/acceptance/v2';
const acl = 'bucket-owner-full-control';
const AWS = require('aws-sdk');
const s3 = new AWS.S3({
apiVersion: '2006-03-01',
});
exports.handler = (event) => {
let fromParams = {
Bucket: event.Records[0].s3.bucket.name,
Key: event.Records[0].s3.object.key
};
let match = event.Records[0].s3.object.key.match(/\d{4}\/\d{2}\/\d{2}\/\d{2}\/[^\/]*$/);
if (!match) {
console.error('Not match the AWS WAF full log event. : ', event.Records[0].s3.object.key);
return;
}
s3.getObject(fromParams, (err, data) => {
if (err) {
console.error('Cannot get object.');
console.error(err);
return;
}
let toParams = {
Bucket: toBucket,
Key: [toPath, match[0]].join('/'),
ACL: acl,
Body: data.Body
};
send();
function send() {
s3.putObject(toParams, (err, data) => {
if (err) {
console.error('Cannot put object.');
console.error(err);
send();
} else {
return;
}
});
}
});
};
Description: "For WafCharm"
FunctionName: "xxx-lambda-wafcharm"
Handler: "index.handler"
MemorySize: 128
Role: !GetAtt IAMRoleForLambda.Arn
Runtime: "nodejs14.x"
Tags:
- Key: name
Value: xxx-lambda-wafcharm
Timeout: 60
WAFCharmLoggingConfiguration:
Type: AWS::WAFv2::LoggingConfiguration
Properties:
LogDestinationConfigs:
- !GetAtt KinesisFirehose.Arn
ResourceArn: !GetAtt WebACL.Arn
LambdaPermission:
# https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-lambda-permission.html
Type: "AWS::Lambda::Permission"
DeletionPolicy: "Delete"
Properties:
Action: "lambda:InvokeFunction"
# EventSourceToken: String
FunctionName: !GetAtt Lambda.Arn
Principal: "s3.amazonaws.com"
SourceAccount: !Ref "AWS::AccountId"
SourceArn: !GetAtt S3Bucket.Arn
Resources Created using Console
Lambda build (trigger)
Iam User
https://www.wafcharm.com/en/blog/aws-iam-setting-for-wafcharm/ 1. open IAM from Services
- click on add user
-
Write user name e.g. WAFCharm and check Access key - Programmatic access
-
Click next permissions
-
Attach existing policy directly:
-
AWSWafFullAccess
-
S3ObjectReadOnly
-
you can skip tags
-
Review and Create User
WAFCharm Reports and email example
https://dev.classmethod.jp/articles/wafcharm-freetrial/