VPCフローログの通信拒否のログを検知してSNSで通知を行ってみた
どうもさいちゃんです。皆さん VPC フローログきちんと確認できていますか?
ログの管理や分析って難しいですよね。普段の業務に加えてログを定期的にチェックする時間や人手が無いという方もいるのではないでしょうか?
SIEM ソリューション等を活用して定期的なログの分析や可視化をする事はもちろん大切です。しかし、多くの組織で十分な対応が難しい現状があります。
- 通信拒否など特定の挙動が記録された時だけ通知して欲しい
 - PoC 段階でいきなりセキュリティグループや NACL の設定で絞りすぎると必要な通信までブロックしてしまわないか心配なので挙動を確認したい
 
など様々なシーンで活用できる通信拒否が起こった場合のメール通知の実装方法についてご紹介します。
実現したいこと
今回は VPC フローログを CloudWatch Logs へ送り、メトリクスフィルターを使用して通信拒否があった場合に SNS 通知を行うという方法で通信拒否の通知を行ってみます。
どの程度のタイムラグがあるのかなども確認してみたのでご参考になれば幸いです。
前提
本ブログでは下記の前提条件があるものとして設定の方法をご紹介します。
- 該当 VPC で VPC フローログが有効になっている事
 - VPC フローログのすべてのログを AWS のデフォルト形式で CloudWatchLogs へ送信している事
 - 上記設定に伴い、適切な IAM ロールがフローログに設定されている事
 - SNS トピックが作成されており、適切な E メールアドレスが登録されていること
 
やってみた
メトリクスフィルターを利用した CloudWatch アラームの設定
VPC フローログの送信先となる CloudWatch ロググループの詳細画面からメトリクスフィルタータブを選択し、 メトリクスフィルターを作成を選択します。

フィルターパターン配下のように入力します。
[version, account, eni, source, destination, srcport, destport, protocol,packets, bytes, windowstart, windowend, action="REJECT", flowlogstatus]
パターンのテストが可能ですが、この時点で VPC フローログに REJECT(拒否)のログが記録されてなければ、テスト結果の欄にはフィルターパターンに一致する結果がないと表示されます。
REJECT のログがある場合はこんな感じで結果を抽出してくれます。

次へ進み、適切な値を設定します。
今回は「test-reject-packets-filter」という名前でメトリクスフィルターを作ります。
後はこんな感じで作成しました。
| 項目 | 値 | 備考 | 
|---|---|---|
| メトリクス名前空間 | VPCFlowLogs | |
| メトリクス名 | RejectPackets | |
| メトリクス値 | 1 | |
| デフォルト値 | 0 | 

次へ進み設定値に問題がなければこのまま作成します。

下記の様に先ほどまでなかったメトリクスが表示されるようになりました。


次に CloudWatch アラームの設定を行います。
※REJECT ログが一度も記録されていない状態だと作成したメトリクスがメトリクス一覧表示されません。
メトリクス一覧に表示されないとコンソールからアラームの作成ができないため、CLI か CloudFormation を使用して CloudWatch アラームを作成しましょう。
今回は CLI コマンドを使用してアラームを作成します。
$ aws cloudwatch put-metric-alarm \
     --alarm-name "VPC-Reject-Packets-Alarm" \
     --alarm-description "VPCフローログの通信拒否監視アラーム" \
     --metric-name "RejectPackets" \
     --namespace "VPCFlowLogs" \
     --statistic Sum \
     --period 60 \
     --threshold 0 \
     --comparison-operator GreaterThanThreshold \
     --evaluation-periods 1 \
     --datapoints-to-alarm 1 \
     --alarm-actions <snsトピックarn> \
     --treat-missing-data notBreaching \
     --actions-enabled

アラームが作成されたので早速テストしていきます。
テスト
今回は簡単に REJECT ログを記録させるためにセキュリティグループを閉じた状態でパブリックサブネットにある EC2 インスタンスへ SSH 接続を試みてみます。
こんな感じでインバウンドルールに何も追加せずにセキュリティグループを作成します。

このセキュリティグループをアタッチしたインスタンスを立ち上げます。
パブリック IP の付与さえしておけばセキュリティグループ以外の設定はなんでもいいです。

では SSH 接続してみます。
$ ssh ec2-user@XX.XXX.XXX.XX -p 22 -i <キーペア名>
# 実行結果
ssh: connect to host XX.XXX.XXX.XX port 22: Connection timed out
タイムアウトしました。CloudWatch アラームを確認してみます。

何度かテストしたので少しグラフは分かりづらいですが、アラーム状態になってますね。

メールも飛んできました。
REJECT が CloudWatch Logs に記録されるまでは若干のタイムラグがありますが、記録後はすぐにアラーム状態になり、メールが飛んでくるのでラグはほとんど感じませんでした。
CFn テンプレートでの実装例
上記の設定を CFn テンプレートで簡単に実装できるようにテンプレートを作成してみました。
AWSTemplateFormatVersion: 2010-09-09
Description: ""Monitors and alerts on VPC network traffic rejections.
Parameters:
  SnsTopicArn:
    Type: String
  LogGroupName:
    Type: String
Resources:
  # Metric filter
  VPCRejectPacketsMetricFilter:
    Type: AWS::Logs::MetricFilter
    Properties:
      LogGroupName: !Ref  LogGroupName
      FilterPattern: '[version, account, eni, source, destination, srcport, destport, protocol, packets, bytes, windowstart, windowend, action="REJECT", flowlogstatus]'
      MetricTransformations:
        -
          MetricNamespace: VPCFlowLogs
          MetricName: RejectPackets
          MetricValue: 1 
          DefaultValue: 0
  # CloudWatch alarm
  RejectPacketsAlarm:
    Type: AWS::CloudWatch::Alarm
    Properties:
      AlarmName: "VPC-Reject-Packets-Alarm"
      AlarmDescription: "VPCフローログの通信拒否監視アラーム"
      Namespace: "VPCFlowLogs"
      MetricName: "RejectPackets"
      Period: 60
      Statistic: "Sum"
      Threshold: 0
      ComparisonOperator: "GreaterThanThreshold"
      EvaluationPeriods: 1
      DatapointsToAlarm: 1
      ActionsEnabled: true
      TreatMissingData: notBreaching
      AlarmActions:
        - !Ref SnsTopicArn
最後に
VPC フローログの監視は、AWS セキュリティにおいて非常に重要です。今回は、CloudWatch メトリクスフィルターと SNS 通知を活用することで、通信拒否イベントをリアルタイムに検出し、迅速に対応できる仕組みを作ってみました。
本ブログがどなたかのお役に立てれば幸いです。







