0
0

More than 1 year has passed since last update.

VPCFlowLogsにCloudWatchLogsのAlarmを設定する(CloudFormation編)

Posted at

はじめに

前回コンソールから作成した、VPCの不正トラフィックを検出する環境を、CloudFormationで記述しました。

構成

今回は複数環境の作成を想定して、「共通で使うリソース」と「個別の環境で使うリソース」で分けて作成しました。

image.png

  • 共通で使うリソース
    • Log Group
    • SNS
    • VPCにアタッチする、フローログをLog Groupに送信する用のロール
      • 図上では、環境ごとの場所に入っています
  • 個別の環境で使うリソース
    • VPCとそれに関連するもの
    • S3バケット
    • メトリクスとアラート
      • 監視するロググループは一つなので、環境ごとのIDなどをフィルターに入れて分別しています。

CloudFormation

コードは以下になります、説明等に使われている英語の拙さはご容赦ください。

共通で使うリソース

01_createBaseEnvForTrail.yml

AWSTemplateFormatVersion: 2010-09-09
Description: Create Base Env for Trail on VPC

Resources: 
##################################################
# Role
##################################################
  ## VPCにアタッチする、VPCフローログをロググループに出力可能なロール作成
  VpcFlowlogsOutRole:
    Type: AWS::IAM::Role
    Properties:
      RoleName: for-vpcflowlogs
      Path: /
      AssumeRolePolicyDocument: 
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "vpc-flow-logs.amazonaws.com"
            Action: 'sts:AssumeRole'
      Policies:
        - PolicyName: out-vpcflowlogs
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - "logs:CreateLogGroup"
                  - "logs:CreateLogStream"
                  - "logs:PutLogEvents"
                  - "logs:DescribeLogGroups"
                  - "logs:DescribeLogStreams"
                Resource: '*'
      Tags:
          - Key: "usefor"
            Value: "VPC Flowlogs"

##################################################
# SNS
##################################################
  IllegalTraficSnsTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: illegal-trafic-sns-topic
      Tags:
          - Key: "usefor"
            Value: "send e-mail detection of illegal trafic"
##################################################
# Cloudwatch log Group
##################################################
  VpcFlowlogsLogGroup:
    Type: AWS::Logs::LogGroup
    Properties:
      LogGroupName: /custom/vpcflowlogs
      RetentionInDays: 3653   # 未指定時は「失効しない」

Outputs:
  RoleForVpcFlowlogsOnTrail:
    Value: !GetAtt VpcFlowlogsOutRole.Arn
    Export:
      Name: RoleForVpcFlowlogsOnTrail
  IllegalTraficSnsTopic:
    Value: !Ref IllegalTraficSnsTopic
    Export:
      Name: IllegalTraficSnsTopic
  VpcFlowlogsLogGroup:
    Value: !Ref VpcFlowlogsLogGroup
    Export:
      Name: VpcFlowlogsLogGroup

  • Outputは、個別の環境で使うリソース作成時に参照します。

個別の環境で使うリソース

02_createEachEnvForTrail.yml

AWSTemplateFormatVersion: 2010-09-09
Description: Create Each Env for Trail on VPC
Parameters:
  EnvId:
    Type: String
  VpcCidr:
    Type: String
    Default: 192.168.209.0/24
  SubnetACidr:
    Type: String
    Default: 192.168.209.0/26
  SubnetCCidr:
    Type: String
    Default: 192.168.209.64/26
  SubnetDCidr:
    Type: String
    Default: 192.168.209.128/26
Metadata:
  AWS::CloudFormation::Interface:
    ParameterGroups:
      -
        Label:
          default: User Setting.
        Parameters:
          - EnvId
          - VpcCidr
          - SubnetACidr
          - SubnetCCidr
          - SubnetDCidr

Resources:
##################################################
# VPC
##################################################
  Vpc:
    Type: AWS::EC2::VPC
    Properties: 
      CidrBlock: !Ref VpcCidr
      # EnableDnsHostnames: true
      # EnableDnsSupport: true
      Tags: 
        - Key: Name
          Value: !Sub "${EnvId}-vpc"
##################################################
# Security Group
##################################################
  SecGrpOnlyInternal:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupDescription: Enable access from EC2 Instance Connect IP
      GroupName: !Sub "${EnvId}-sg"
      VpcId: !Ref Vpc
      # For EC2 Instance Connect
      SecurityGroupIngress:
        -
          IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: 3.112.23.0/29
  SGBaseIngress:
    Type: 'AWS::EC2::SecurityGroupIngress'
    Properties:
      GroupId: !Ref SecGrpOnlyInternal
      IpProtocol: -1
      SourceSecurityGroupId: !GetAtt SecGrpOnlyInternal.GroupId
##################################################
# IGW
##################################################
  Igw:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags: 
        - Key: Name
          Value: !Sub ${EnvId}-igw
  IgwAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties: 
      InternetGatewayId: !Ref Igw
      VpcId: !Ref Vpc
##################################################
# Subnets
##################################################
  SubnetA:
    Type: AWS::EC2::Subnet
    Properties: 
      VpcId: !Ref Vpc
      AvailabilityZone: ap-northeast-1a
      CidrBlock: !Ref SubnetACidr
      MapPublicIpOnLaunch: false
      Tags: 
        - Key: Name
          Value: !Sub ${EnvId}-subnet-a
  SubnetC:
    Type: AWS::EC2::Subnet
    Properties: 
      VpcId: !Ref Vpc
      AvailabilityZone: ap-northeast-1c
      CidrBlock: !Ref SubnetCCidr
      MapPublicIpOnLaunch: false
      Tags: 
        - Key: Name
          Value: !Sub ${EnvId}-subnet-c
  SubnetD:
    Type: AWS::EC2::Subnet
    Properties: 
      VpcId: !Ref Vpc
      AvailabilityZone: ap-northeast-1d
      CidrBlock: !Ref SubnetDCidr
      MapPublicIpOnLaunch: false
      Tags: 
        - Key: Name
          Value: !Sub ${EnvId}-subnet-d
##################################################
# Routing
##################################################
  RouteTable:
    Type: AWS::EC2::RouteTable
    Properties: 
      VpcId: !Ref Vpc
      Tags: 
        - Key: Name
          Value: !Sub ${EnvId}-public-rtb
  RouteTableAssocA:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties: 
      RouteTableId: !Ref RouteTable
      SubnetId: !Ref SubnetA
  RouteTableAssocC:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties: 
      RouteTableId: !Ref RouteTable
      SubnetId: !Ref SubnetC
  RouteTableAssocD:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties: 
      RouteTableId: !Ref RouteTable
      SubnetId: !Ref SubnetD
  Route:
    Type: AWS::EC2::Route
    Properties: 
      RouteTableId: !Ref RouteTable
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref Igw

##################################################
# S3
##################################################
  PrivateBucket:
    Type: "AWS::S3::Bucket"
    Properties:
        BucketName: !Sub "for-${EnvId}-${AWS::AccountId}"
        BucketEncryption: 
            ServerSideEncryptionConfiguration: 
              - 
                ServerSideEncryptionByDefault: 
                    SSEAlgorithm: "AES256"
                BucketKeyEnabled: false
        PublicAccessBlockConfiguration:
          BlockPublicAcls: true
          BlockPublicPolicy: true
          IgnorePublicAcls: true
          RestrictPublicBuckets: true
  # SSLがないのはNG
  PrivateBucketPolicy:
    Type: 'AWS::S3::BucketPolicy'
    Properties:
      Bucket: !Ref PrivateBucket
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Sid: DenyNotSecureTransport
            Effect: Deny
            Principal: "*"
            Resource:
              - !Sub "arn:aws:s3:::${PrivateBucket}"
              - !Sub "arn:aws:s3:::${PrivateBucket}/*"
            Action: "*"
            Condition:
                Bool:
                    aws:SecureTransport: false

##################################################
# VPC Endpoint to S3
##################################################
  VPCS3Endpoint:
    Type: "AWS::EC2::VPCEndpoint"
    Properties:
      VpcEndpointType: Gateway
      RouteTableIds: 
        - !Ref RouteTable
      ServiceName: !Sub "com.amazonaws.${AWS::Region}.s3"
      VpcId: !Ref Vpc
      PolicyDocument:
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal: '*'
            Action:
              - "s3:*"
            Resource:
              - !Sub "arn:aws:s3:::${PrivateBucket}"
              - !Sub "arn:aws:s3:::${PrivateBucket}/*"

##################################################
# VPC FlowLogs
##################################################
  VpcFlowLogs:
    Type: "AWS::EC2::FlowLog"
    Properties:
      ResourceType: VPC
      ResourceId: !Ref Vpc
      TrafficType: ALL
      DeliverLogsPermissionArn: !ImportValue RoleForVpcFlowlogsOnTrail
      LogGroupName: !ImportValue VpcFlowlogsLogGroup
      LogFormat: '${account-id} ${action} ${az-id} ${bytes} ${dstaddr} ${dstport} ${end} ${flow-direction} ${instance-id} ${interface-id} ${log-status} ${packets} ${pkt-dst-aws-service} ${pkt-dstaddr} ${pkt-src-aws-service} ${pkt-srcaddr} ${protocol} ${region} ${srcaddr} ${srcport} ${start} ${sublocation-id} ${sublocation-type} ${subnet-id} ${tcp-flags} ${traffic-path} ${type} ${version} ${vpc-id}'
      Tags: 
        - Key: Name
          Value: !Sub ${EnvId}-flowlog
##################################################
# MetricFilter
##################################################
  MetricFilter:
    # フィルタ名は [CFnのスタック名]-[リソース名]-[ランダム文字列]が付く
    Type: AWS::Logs::MetricFilter
    Properties:
      LogGroupName: !ImportValue VpcFlowlogsLogGroup
      FilterPattern: !Sub "[account_id, action, az_id, bytes > 100000, dstaddr!=52.219.* && dstaddr!=3.5.* && dstaddr!=35.72.164.* && dstaddr!=35.73.115.* , dstport, end, flow_direction = egress, ..., vpc_id=${Vpc}]"
      MetricTransformations: 
        - MetricValue: 1
          MetricNamespace: Custom/VPC
          MetricName: !Sub ${EnvId}-vpc-IllegalTrafic
          DefaultValue: 0
##################################################
# Alarm
##################################################
  LogFilterAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      Namespace: Custom/VPC
      MetricName: !Sub ${EnvId}-vpc-IllegalTrafic
      Statistic: Sum
      Period: 300                                           # の間に
      ComparisonOperator: GreaterThanOrEqualToThreshold     # の状態を
      Threshold: 1                                          # 回超えることが
      EvaluationPeriods: 1                                  # 周期中
      DatapointsToAlarm: 1                                  # 回なら
      TreatMissingData: notBreaching
      AlarmActions: 
        - !ImportValue IllegalTraficSnsTopic
      AlarmName: !Sub ${EnvId}-vpc-IllegalTraficAlarm
      AlarmDescription: !Sub "${EnvId} vpc にて、不正トラフィック検出"

##################################################
# Role
##################################################
  ## EC2アタッチ用ロール作成
  Ec2Role:
    Type: AWS::IAM::Role
    Properties:
      RoleName: !Sub for-ec2-on-${EnvId}
      Path: /
      AssumeRolePolicyDocument: 
        Version: 2012-10-17
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - "ec2.amazonaws.com"
            Action: 'sts:AssumeRole'
      Policies:
        - PolicyName: s3fullaccess
          PolicyDocument:
            Version: 2012-10-17
            Statement:
              - Effect: Allow
                Action:
                  - "s3:*"
                Resource:
                  - !Sub "arn:aws:s3:::${PrivateBucket}"
                  - !Sub "arn:aws:s3:::${PrivateBucket}/*"
  ## インスタンスプロファイル作成
  MyInstanceProfile:
    Type: AWS::IAM::InstanceProfile
    Properties:
      Path: /
      Roles:
        - !Ref Ec2Role
  • VPCやサブネットのIPレンジは、パラメータで指定できるようにしました。
  • S3は、SSL暗号化通信されている通信のみ可としました。
  • VPCエンドポイントは、対応するS3バケットのみ使用可能なポリシーにしました。
  • セキュリティグループのインバウンドには、はEC2 Instance Connectを使用するため特定のIPレンジを許可しました。
  • フィルターは、「100KBを超える、S3のIP以外に対しての送信で、構築したVPCのトラフィック」としました。
    • 他のバケットへの送信はフィルターに引っかからないですが、VPCエンドポイントのポリシーで許可していないので、できない(はず)です。
  • アラームの設定値の説明は推測です。わかる方はご指摘いただけると助かります。

環境作成・確認手順

  1. 01_createBaseEnvForTrail.ymlを実行。
  2. 02_createEachEnvForTrail.ymlを、構築したい環境分だけ、EnvIdを指定して実行。今回は「cyclone」と「joker」という環境を作りました。
  3. 「cyclone」にEC2インスタンスを作成し、決められたS3以外にデータ送信すると、以下のように「cyclone」のアラームだけ反応しました。

image.png

片づけ

  1. 各環境のS3バケットを空にします。
  2. CloudFormationで、各環境のスタックを削除します。
  3. CloudFormationで、共通環境のスタックを削除します。

まとめ

「VPCの不正トラフィックを検出できる環境」を、CloudFormationで作成しました。
次はS3アクセスログで、同様のことを行おうと思います。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0