Skip to content

Instantly share code, notes, and snippets.

@sakamaki-kazuyoshi
Created June 7, 2020 03:50
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save sakamaki-kazuyoshi/ea80f8d1e8ca571006796d4402b919d9 to your computer and use it in GitHub Desktop.
Save sakamaki-kazuyoshi/ea80f8d1e8ca571006796d4402b919d9 to your computer and use it in GitHub Desktop.
AWS WAF environment for logging to S3.
AWSTemplateFormatVersion: '2010-09-09'
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Common Configuration(Resource prefix)"
Parameters:
- ProjectName
- EnvironmentName
- Label:
default: "EC2 Configuration"
Parameters:
- SecurityGroupInboudRule
- EC2KeyPair
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
ProjectName:
Type: String
Default: 'test'
EnvironmentName:
Type: String
AllowedValues: [dev,stg,prd]
Default: 'dev'
SecurityGroupInboudRule:
Type: String
Default: '0.0.0.0/0'
Description: Enter the SSH reception rule of the web server.
EC2KeyPair:
Type: AWS::EC2::KeyPair::KeyName
# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
# IAM
# ------------------------------------------------------------#
WebRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Version: "2012-10-17"
Statement:
-
Effect: "Allow"
Principal:
Service:
- "ec2.amazonaws.com"
Action:
- "sts:AssumeRole"
Path: "/"
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
RoleName: !Sub ${ProjectName}-${EnvironmentName}-web-role
WebInstanceProfile:
Type: "AWS::IAM::InstanceProfile"
Properties:
Path: "/"
Roles:
- !Ref WebRole
InstanceProfileName: !Sub ${ProjectName}-${EnvironmentName}-web-role
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
VPC:
Type: 'AWS::EC2::VPC'
Properties:
CidrBlock: 10.0.0.0/16
EnableDnsSupport: 'true'
EnableDnsHostnames: 'true'
InstanceTenancy: default
Tags:
- Key: Name
Value: !Sub ${ProjectName}-${EnvironmentName}-vpc
# ------------------------------------------------------------#
# Internet Gateway
# ------------------------------------------------------------#
InternetGateway:
Type: 'AWS::EC2::InternetGateway'
Properties:
Tags:
- Key: Name
Value: !Sub ${ProjectName}-${EnvironmentName}-igw
AttachInternetGateway:
Type: 'AWS::EC2::VPCGatewayAttachment'
Properties:
InternetGatewayId: !Ref InternetGateway
VpcId: !Ref VPC
# ------------------------------------------------------------#
# Subnet
# ------------------------------------------------------------#
PublicSubnetA:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref VPC
AvailabilityZone: 'ap-northeast-1a'
CidrBlock: 10.0.0.0/24
MapPublicIpOnLaunch: 'true'
Tags:
- Key: Name
Value: !Sub ${ProjectName}-${EnvironmentName}-public-subnet-a
PublicSubnetC:
Type: 'AWS::EC2::Subnet'
Properties:
VpcId: !Ref VPC
AvailabilityZone: 'ap-northeast-1c'
CidrBlock: 10.0.1.0/24
MapPublicIpOnLaunch: 'true'
Tags:
- Key: Name
Value: !Sub ${ProjectName}-${EnvironmentName}-public-subnet-c
# ------------------------------------------------------------#
# RouteTable
# ------------------------------------------------------------#
PublicRouteTable:
Type: 'AWS::EC2::RouteTable'
Properties:
VpcId: !Ref VPC
Tags:
- Key: Name
Value: !Sub ${ProjectName}-${EnvironmentName}-public-rtb
RouteAddInternetGateway:
Type: 'AWS::EC2::Route'
Properties:
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
RouteTableId: !Ref PublicRouteTable
AssociatePublicSubnetAToPublicRouteTable:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnetA
AssociatePublicSubnetCToPublicRouteTable:
Type: 'AWS::EC2::SubnetRouteTableAssociation'
Properties:
RouteTableId: !Ref PublicRouteTable
SubnetId: !Ref PublicSubnetC
# ------------------------------------------------------------#
# Securitygroup
# ------------------------------------------------------------#
WebSecuritygroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub ${ProjectName}-${EnvironmentName}-web-sg
GroupDescription: !Sub ${ProjectName}-${EnvironmentName}-web-sg
Tags:
- Key: Name
Value: !Sub ${ProjectName}-${EnvironmentName}-web-sg
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '22'
ToPort: '22'
CidrIp: !Sub ${SecurityGroupInboudRule}
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
SourceSecurityGroupId: !Ref ALBSecuritygroup
Description: 'from ALB'
ALBSecuritygroup:
Type: AWS::EC2::SecurityGroup
Properties:
GroupName: !Sub ${ProjectName}-${EnvironmentName}-alb-sg
GroupDescription: !Sub ${ProjectName}-${EnvironmentName}-alb-sg
Tags:
- Key: Name
Value: !Sub ${ProjectName}-${EnvironmentName}-alb-sg
VpcId: !Ref VPC
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: '80'
ToPort: '80'
CidrIp: '0.0.0.0/0'
Description: 'from Internet'
# ------------------------------------------------------------#
# LoadBalancer
# ------------------------------------------------------------#
LoadBalancer:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub ${ProjectName}-${EnvironmentName}-alb
Scheme: internet-facing
Subnets:
- !Ref PublicSubnetA
- !Ref PublicSubnetC
SecurityGroups:
- !Ref ALBSecuritygroup
LoadBalancerAttributes:
- Key: access_logs.s3.enabled
Value: true
- Key: access_logs.s3.bucket
Value: !Ref ALBLogBucket
# - Key: deletion_protection.enabled
# Value: true
Tags:
- Key: Name
Value: !Sub ${ProjectName}-${EnvironmentName}-alb
# ------------------------------------------------------------#
# TargetGroup
# ------------------------------------------------------------#
TargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Name: !Sub ${ProjectName}-${EnvironmentName}-alb-tg
Port: 80
Protocol: HTTP
Tags:
- Key: Name
Value: !Sub ${ProjectName}-${EnvironmentName}-alb-tg
Targets:
- Id: !Ref WebInstance1
Port: 80
VpcId: !Ref VPC
# ------------------------------------------------------------#
# Listener
# ------------------------------------------------------------#
Listener:
Type: "AWS::ElasticLoadBalancingV2::Listener"
Properties:
DefaultActions:
- TargetGroupArn: !Ref TargetGroup
Type: forward
LoadBalancerArn: !Ref LoadBalancer
Port: 80
Protocol: HTTP
# ------------------------------------------------------------#
# S3 Bucket
# ------------------------------------------------------------#
ALBLogBucket:
Type: 'AWS::S3::Bucket'
Properties:
BucketName: !Sub ${ProjectName}-${EnvironmentName}-alb-${AWS::AccountId}
AccessControl: Private
LifecycleConfiguration:
Rules:
- Id: LifeCycleRule
Status: Enabled
ExpirationInDays: '365'
ALBLogBucketPolicy:
Type: "AWS::S3::BucketPolicy"
Properties:
Bucket: !Ref ALBLogBucket
PolicyDocument:
Id: "Allow-Put-ELB-logs"
Version: "2012-10-17"
Statement:
- Action:
- "s3:PutObject"
Effect: "Allow"
Resource: !Join [ "", [ "arn:aws:s3:::" , !Ref ALBLogBucket, "/AWSLogs/", !Ref "AWS::AccountId" ,"/*"] ]
Principal:
AWS: "582318560864" #Elastic Load Balancing Account ID(ap-northeast-1)
# ------------------------------------------------------------#
# EC2
# ------------------------------------------------------------#
WebInstance1:
Type: "AWS::EC2::Instance"
Properties:
AvailabilityZone: ap-northeast-1a
ImageId: ami-0a1c2ec61571737db #AL2
InstanceType: t3.micro
KeyName: !Ref EC2KeyPair
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeType: gp2
VolumeSize: 8
NetworkInterfaces:
- AssociatePublicIpAddress: "true"
DeviceIndex: "0"
GroupSet:
- Ref: WebSecuritygroup
SubnetId:
Ref: PublicSubnetA
IamInstanceProfile: !Ref WebInstanceProfile
Tags:
- Key: Name
Value: !Sub ${ProjectName}-${EnvironmentName}-web
UserData:
Fn::Base64: |
#!/bin/bash
yum update -y
yum install -y httpd
echo "<html><body>Hello world</body></html>" > /var/www/html/index.html
systemctl enable httpd
systemctl start httpd
AWSTemplateFormatVersion: '2010-09-09'
# ------------------------------------------------------------#
# Metadata
# ------------------------------------------------------------#
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Common Configuration(Resource prefix)"
Parameters:
- ProjectName
- EnvironmentName
- Label:
default: "WAF v2 Configuration"
Parameters:
- AlbArn
- Label:
default: "Kinesis Data Firehose Configuration"
Parameters:
- BufferSize
- BufferInterval
- CompressionFormat
# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------#
Parameters:
ProjectName:
Type: String
Default: 'test'
EnvironmentName:
Type: String
AllowedValues: [dev,stg,prd]
Default: 'dev'
AlbArn:
Type: String
Default: 'arn:aws:elasticloadbalancing:ap-northeast-1:XXXXXXXXXXXX:loadbalancer/app/XXXXXXXXXXXX'
Description: Enter ALB ARN to associate with WEBACL.
BufferSize:
Type: String
Default: '5'
BufferInterval:
Type: String
Default: '60'
CompressionFormat:
Type: String
AllowedValues: [GZIP,HADOOP_SNAPPY,Snappy,UNCOMPRESSED,ZIP]
Default: 'GZIP'
# ------------------------------------------------------------#
# Resources
# ------------------------------------------------------------#
Resources:
# ------------------------------------------------------------#
# WAF v2
# ------------------------------------------------------------#
WebACL:
Type: AWS::WAFv2::WebACL
Properties:
DefaultAction:
Allow: {}
Description: "Used by ALB of web server"
Name: !Sub ${ProjectName}-${EnvironmentName}-web-acl
Scope: REGIONAL
# Tags:
# - Tag
VisibilityConfig:
SampledRequestsEnabled: true
CloudWatchMetricsEnabled: true
MetricName: !Sub ${ProjectName}-${EnvironmentName}-web-acl
WebACLAssociation:
Type: AWS::WAFv2::WebACLAssociation
Properties:
ResourceArn: !Ref AlbArn
WebACLArn: !GetAtt WebACL.Arn
# ------------------------------------------------------------#
# S3
# ------------------------------------------------------------#
WAFLogBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub ${ProjectName}-${EnvironmentName}-waf-${AWS::AccountId}
# BucketEncryption:
# ServerSideEncryptionConfiguration:
# - ServerSideEncryptionByDefault:
# SSEAlgorithm: AES256
AccessControl: Private
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
LifecycleConfiguration:
Rules:
- Id: LifeCycleRule
Status: Enabled
ExpirationInDays: '365'
# ------------------------------------------------------------#
# IAM
# ------------------------------------------------------------#
KinesisDataFirehoseRole:
Type: "AWS::IAM::Role"
Properties:
AssumeRolePolicyDocument:
Statement:
-
Effect: "Allow"
Principal:
Service:
- "firehose.amazonaws.com"
Action:
- "sts:AssumeRole"
Condition:
StringEquals:
sts:ExternalId: !Ref AWS::AccountId
Path: "/"
Policies:
-
PolicyName: "Permissions-Policy-For-Firehose"
PolicyDocument:
Statement:
-
Effect: "Allow"
Action:
- "s3:AbortMultipartUpload"
- "s3:GetBucketLocation"
- "s3:GetObject"
- "s3:ListBucket"
- "s3:ListBucketMultipartUploads"
- "s3:PutObject"
- "logs:PutLogEvents"
Resource:
- !Join
- ''
- - 'arn:aws:s3:::'
- !Ref WAFLogBucket
- !Join
- ''
- - 'arn:aws:s3:::'
- !Ref WAFLogBucket
- '/*'
- !Join
- ''
- - 'arn:aws:logs:'
- !Ref AWS::Region
- ':'
- !Ref AWS::AccountId
- ':log-group:'
- !Ref CloudWatchLogsLogGroup
- ':log-stream:*'
RoleName: !Sub ${ProjectName}-${EnvironmentName}-delivery-stream-role
# ------------------------------------------------------------#
# Kinesis Data Firehose
# ------------------------------------------------------------#
WAFLogDeliveryStream:
Type: AWS::KinesisFirehose::DeliveryStream
Properties:
DeliveryStreamName: !Sub aws-waf-logs-${ProjectName}-${EnvironmentName}-delivery-stream
DeliveryStreamType: DirectPut
ExtendedS3DestinationConfiguration:
BucketARN: !GetAtt WAFLogBucket.Arn
BufferingHints:
SizeInMBs: !Ref BufferSize
IntervalInSeconds: !Ref BufferInterval
CloudWatchLoggingOptions:
Enabled: true
LogGroupName: !Ref CloudWatchLogsLogGroup
LogStreamName: !Ref CloudWatchLogsLogStream
CompressionFormat: !Ref CompressionFormat
Prefix: 'year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/hour=!{timestamp:HH}/'
ErrorOutputPrefix: 'year=!{timestamp:yyyy}/month=!{timestamp:MM}/day=!{timestamp:dd}/hour=!{timestamp:HH}/!{firehose:error-output-type}'
RoleARN: !GetAtt KinesisDataFirehoseRole.Arn
# ------------------------------------------------------------#
# CloudWatch Logs
# ------------------------------------------------------------#
CloudWatchLogsLogGroup:
Type: AWS::Logs::LogGroup
Properties:
LogGroupName: !Join [ "", [ "/aws/kinesisfirehose/" , !Sub '${ProjectName}-${EnvironmentName}-delivery-stream'] ]
RetentionInDays: 90
CloudWatchLogsLogStream:
Type: AWS::Logs::LogStream
Properties:
LogGroupName: !Ref CloudWatchLogsLogGroup
LogStreamName: "S3Delivery"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment