カスタマーサクセス部の山﨑です。
AWS上で運用されるアプリケーションやリソースから出力されるログは、障害対応やセキュリティ対策、パフォーマンス分析などに欠かせない重要なデータです。しかしログの量は膨大になりがちで、必要な情報を素早く抽出・分析するためには効率的な方法が求められます。そこで活用できるのが Amazon CloudWatch Logs Insights です。
本記事では、CloudWatch Logs Insights の基本的なクエリ構文から、VPC Flow Logs を例にした具体的な分析手順まで、実践的なポイントを幅広くご紹介します。初心者の方でもわかりやすいようにクエリの書き方を丁寧に解説し、実際の運用に役立つヒントを随所に盛り込みました。ぜひ最後までお読みいただき、AWSでのログ管理・分析を効率化する手がかりにしていただければ幸いです。
1. Amazon CloudWatch Logs Insights とは
1.1 Amazon CloudWatch について
Amazon CloudWatchは、EC2インスタンスをはじめとしたAWSリソースとAWS上で稼働しているアプリケーションをモニタリングし、システムのパフォーマンスやリソース使用率の最適化を行うために必要な判断材料(データ)を提供します。
1.2 Amazon CloudWatch Logs について
CloudWatchは利用者が必要なデータをログ、メトリクス、イベントの形式で提供します。中でもログの形式でデータを提供する機能を担っているものがAmazon CloudWatch Logsです。
詳細は以下ブログを合わせてご覧ください。
1.3 Amazon CloudWatch Logs Insights について
Amazon CloudWatch Logs Insightsとは、CloudWatch Logsのロググループに対してクエリを実行することでログデータを分析したり、問題発生時の原因調査(トラブルシューティング)に利用したりすることができる機能です。
以下、CloudWatch Logs との機能比較です。
名称 | 機能概要 | 利用例 |
---|---|---|
CloudWatch Logs | AWSサービスのログを収集・管理する。 ※EC2インスタンスの場合は、統合CloudWatchエージェントを利用 |
・EC2のOSログを取得する。 ・RDSのエラーログを取得する。 |
CloudWatch Logs Insights | CloudWatch Logsに収集されたログに対してクエリを実行することでログ分析を行う。 | ・VPC Flow Logsのログに対してクエリを実行し、Rejectされた送信元IPアドレスを調査する。 |
クエリの実行にあたっては専用のクエリ言語を使ったコマンドを実行する必要があるため、利用にはある程度の慣れが必要になります。
以降はVPC Flow Logsのログに対してクエリを実行することを前提に順を追って説明していきます。
2. CloudWatch Logs Insights のクエリの書き方
2.1 基本構文
2.1.1 基本コマンド
CloudWatch Logs Insights language query syntax
コマンド | 説明 | クエリ例 |
---|---|---|
parse | ログフィールドからデータを抽出し、一時的に利用可能な1つ以上のフィールド(エフェメラルフィールド)を作成する | parse @message " * * * * * * * * * * * * " as version, accountId, interfaceId, srcAddr, dstAddr, srcPort, dstPort, protocol, packets, bytes, start, end, action, logStatus |
fields | ログイベントから取得したいログフィールドを抽出する | fields @timestamp, account_id, srcAddr, dstAddr, bytes, action, log_status |
filter | 1つ以上の条件に基づいてクエリ結果をフィルタリングする | filter srcAddr = '192.168.1.1' |
stats | 指定したログフィールドの値を利用して集計する | stats sum(bytes) by srcAddr |
sort | 指定したログフィールドの値に従ってクエリ結果を昇順、降順に並び替える | sort bytes desc |
limit | クエリ結果の抽出件数(デフォルト1,000件)に制限を設ける。 | limit 100 |
2.1.2 演算子
演算子は「filter」コマンドで利用されることが多いクエリです。
Boolean, comparison, numeric, datetime, and other functions
比較演算子 | 説明 | クエリ例 |
---|---|---|
= | Equal | filter bytes = 100 |
!= | NotEqual | filter bytes != 100 |
< | Less than | filter bytes < 100 |
> | Greater than | filter bytes > 100 |
<= | 以下 | filter bytes <= 100 |
>= | 以上 | filter bytes >= 100 |
論理演算子 | 説明 | クエリ例 |
---|---|---|
and | AND条件 | filter srcAddr = '192.168.1.1' and action = 'ACCEPT' |
or | OR条件 | filter srcAddr = '192.168.1.1' or srcAddr = '192.168.1.2' |
not | NOT条件 | filter srcAddr = '192.168.1.1' and not action = 'ACCEPT' |
正規表現 | 説明 | クエリ例 |
---|---|---|
like (not like) |
部分一致 | filter action like 'ACCEPT' |
in | 集合関係 | filter srcAddr in ['192.168.1.1', '192.168.1.2'] |
* | ワイルドカード | filter srcAddr like '192.168.*' |
2.2 クエリ例文
2.2.1 任意のログを10件表示
まずは、VPC Flow Logs のログ構造を確認してみます。
CloudWatch Logs Insights ではパイプ( | )を利用して、複数のコマンドをつなげていくことでクエリを作成していきます。
fields @timestamp, @message | limit 10 --- # 実行結果例(@message) 2 111111111111 eni-111122223333 10.0.20.236 172.16.0.89 49795 3389 6 3 152 1621151386 1621151388 ACCEPT OK
CloudWatch Logs Insights はスキャン量に対してAWS利用料金が発生します。2024年12月時点では、1GBあたり $0.0076 / GB のAWS利用料になります。 そのため、スキャンする際はできるだけ狭い時間範囲を指定して実行することをオススメします。
2.2.2 parse してみる
上記クエリの実行結果例をみると、VPC Flow Logs のログは合計で14個のフィールドから構成されていることが分かります。
これらに対し、parseコマンドを実行してメッセージから任意の名前でフィールドを抽出してみます。
parse @message "* * * * * * * * * * * * * *" as version, accountId, interfaceId, srcAddr, dstAddr, srcPort, dstPort, protocol, packets, bytes, start, end, action, logStatus
なお、VPC Flow Logs に出力するログフォーマットは変更可能なので、その場合は上記parseコマンドを修正する必要があります。 Flow log records - Amazon Virtual Private Cloud
2.2.3 parseで作成したフィールドを使ってクエリを実行してみる
特定のフィールドを表示する
fields @timestamp, accountId, srcAddr, dstAddr | sort @timestamp desc | limit 10
REJECTされたログを100件表示する
filter action="REJECT" | fields @timestamp, action, @message | limit 10
拒否されたリクエスト回数が多い送信元IPアドレスTOP10
filter action="REJECT" | stats count(*) as totalRequestCount by srcAddr | sort totalRequestCount desc | limit 10
3. 練習問題
百聞は一見にしかず、百聞百見は一経にしかず、ということで簡単な練習問題を用意しました!
実際にクエリ文を考えながら理解を深めていただければと思います。
3.1 シナリオ
- システム管理者がVPC内で発生しているネットワークトラフィックを調査しています。
- 外部からの通信が拒否されている状況を分析し、潜在的なセキュリティリスクを特定したいと考えています。
- この調査結果を基に、適切なセキュリティ対策や設定変更を行うことを目指します。
3.2 練習してみよう!
- (練習1)送信元IPアドレスごとに拒否されたリクエスト数を集計して、拒否された回数が多い順に上位20件を表示してください。
解答例(クリックして展開)
filter action="REJECT" | stats count(*) as numRequests by srcAddr | sort numRequests desc | limit 20
意図・目的:拒否トラフィックを大量に発生させている送信元IPアドレスを特定
- 拒否されたトラフィックの集計
- action="REJECT" をフィルタリングすることで、セキュリティグループやネットワークACLによって拒否されたトラフィックのみを対象とします。
- 送信元IPアドレスのランキング
- srcAddr(送信元アドレス)ごとに拒否されたリクエスト数をカウントし、多い順に上位20件を表示します。
- 潜在的な攻撃元の特定
- 特定の送信元IPアドレスから頻繁に拒否トラフィックが発生している場合、そのIPが不正アクセスや攻撃の試行を行っている可能性が高まります。
- (練習2)特定の送信元IPアドレスからの拒否されたリクエスト数を宛先IPアドレスごとに集計し、拒否された回数が多い順に上位20件を表示してください。
※ 送信元IPアドレスは「練習1」で判明した最も拒否トラフィックを送信している送信元IPアドレスを利用します。
解答例(クリックして展開)
#送信元IPアドレスは1つ前のクエリで分かった最も拒否トラフィックを送信している送信元IPアドレス filter action="REJECT" and srcAddr="送信元IPアドレス" | stats count(*) as numRejections by dstAddr | sort numRejections desc | limit 20
意図・目的:送信元IPアドレスがどの宛先IPアドレスに対して拒否を引き起こしているかを明らかにする
- 特定送信元IPの詳細分析
- 練習1のクエリで特定された送信元IPアドレスに絞り込み、さらに詳細な分析を行います。
- 宛先アドレスごとの拒否回数
- dstAddr(宛先アドレス)ごとに拒否されたリクエスト数をカウントし、多い順に上位20件を表示します。
- 攻撃対象の特定
- どの宛先アドレス(内部の特定サーバーやサービス)が頻繁に拒否されているかを把握することで、攻撃の対象となっているリソースを特定できます。
- (練習3)特定の送信元IPアドレスから特定の宛先IPアドレスへ送信されたリクエストのうち、拒否されたトラフィックのみを抽出し、それらを宛先ポートごとに集計して、拒否されたポート数が多い順に上位20件を表示してください。
※ 送信元IPアドレスは「練習1」で判明した最も拒否トラフィックを送信している送信元IPアドレスを利用します。
※ 送信先IPアドレスは「練習2」で判明した最も拒否トラフィックを受けている宛先IPアドレスを利用します。
解答例(クリックして展開)
#送信先IPアドレスは1つ前のクエリで分かった最も拒否トラフィックを受けているIPアドレス filter action="REJECT" and dstAddr="送信先IPアドレス" and srcAddr="送信元IPアドレス" | stats count(*) as numAttackingPort by dstPort | sort numAttackingPort desc | limit 20
意図・目的:特定の宛先IPアドレスに対してどのポートへのアクセスが拒否されているかを分析し、攻撃の種類や狙われているサービスを推測
- 特定の宛先IPへの詳細分析
- 練習2のクエリで特定された宛先IPアドレスと送信元IPアドレスの組み合わせに絞り込みます。
- ポート別拒否回数の集計
- dstPort(宛先ポート)ごとに拒否されたリクエスト数をカウントし、多い順に上位20件を表示します。
- 攻撃の種類や対象ポートの特定
- どのポートへのアクセスが頻繁に拒否されているかを把握することで、攻撃者がどのサービスやアプリケーションを狙っているのか、またはどの脆弱性を探しているのかの手がかりを得ることができます。
4. その他の便利機能
4.1 Query generator
Query generator は自然言語によるクエリ生成機能です(2024年12月時点で、英語のみ対応)
Write a query that counts the number of records by source IP and enumerates them in descending order.
送信元IPごとにレコード数をカウントし、降順に列挙するクエリを作成してください。
上記のように実行したいクエリを英語で表現した上でポチっとボタンを押すだけでクエリを生成してくれるようになります。
4.2 Saved Query
CloudWatch Logs Insightsではクエリを保存する機能があります。 先ほどご紹介した「Query generator」で生成したクエリや普段から頻繁に利用するクエリを保存しておくことでクエリ作成の手間を省くことができます
4.3 CloudWatch Logs Live Tail
CloudWatch Logs Live Tail とは、CloudWatch Logs のロググループおよびログストリームに配信されたログをリアルタイムで表示させる機能です。
端的に言うと、Linuxでtailコマンドを実行してコンソール上に表示させているような機能です。
Live Tail はリアルタイム表示を途中で停止させることができるので、デバック等で不審なログを発見した時に一時停止することで、すぐに特定のログを閲覧して調査することができます
詳細は以下のブログも合わせてご覧ください。
5. まとめ
Amazon CloudWatch Logs Insights を使いこなすことで、膨大なログの中から必要な情報を素早く見つけ出し、可視化することが可能になります。
本記事では基本的なクエリ構文の説明や、VPC Flow Logsを例にとった実践的な分析クエリを紹介し、さらにはクエリ生成機能(Query generator)やリアルタイム確認機能(Live Tail)といった周辺機能についても触れました。
CloudWatch Logs Insights は、システムの正常性やパフォーマンスを監視するだけでなく、潜在的なセキュリティリスクを洗い出すためにも非常に有効なツールです。ぜひ本記事の内容を参考に、日々の運用・トラブルシューティング・セキュリティ対策に役立ててみてください。