はじめに
あまりセキュリティを強固に保っていない社内環境でVPC Flow Logsを確認して怪しいアクセスがあったかどうかを確認してほしいと依頼があった際にすぐに確認できるawkコマンドについてまとめてみます。
最初にやること
ログファイルのダウンロード
Flow Logが出力されているS3からログをダウンロードする必要があります。
Flow Logは大量にあるため、手作業でやっていたらキリがありません。
そこで以下CloudShellを使用してS3に出力されているログをCloudShel環境に一度出力します。
たとえば5月10日~13日の分のログを出力したい場合
aws s3 sync \
s3://{S3名称}/AWSLogs/{AccountId}/vpcflowlogs/{region}/yyyy/mm/ \
./vpcflowlogs \
--exclude "*" \
--include "10/*" \
--include "11/*" \
--include "12/*" \
--include "13/*"
オプションの意味
--exlude "*" -> 一旦すべてを除外する
--include "dd/*" -> 対象の日付配下にあるすべてのファイルおよびプレフィックスにあるもの
--exludeで一度すべてを除外するのはaws s3 syncコマンドが全部コピーする動きになるからです。
イメージ
2026/05/
├─10/
│ └─log
├─11/
│ └─log
└─12/
└─log
つまり、日付配下にある全てのログファイルをvpcflowlogsディレクトリにコピーする動きとなる。
ファイルの解凍
ダウンロードしたら、ファイルを解凍します。
# vpcflowlogs/配下にあるgzipファイルを解凍
gunzip ./vpcflowlogs/**/*.gz
ログの中身を調査
ここまでで事前準備は完了です。
以下でログのカラム名を出力します。
awk '{print $0}' $(find ./vpcflowlogs/10 -type f) | head -1
# 出力結果
version account-id interface-id srcaddr dstaddr srcport dstport protocol packets bytes start end action log-stattus
print $0はファイルの中身をそのまま全部表示する
しかしhead -1を指定しているので1行目のみを表示している。
また$0以降は以下
| 記号 | 意味 |
|---|---|
| $0 | 行全体 |
| $1 | 1列目 |
| $2 | 2列目 |
| $NF | 最後の列 |
出力されたカラム名は以下の意味となる
version VPC Flow Logsのフォーマットバージョン番号
account-id AWSのアカウントID
interface-id 通信が発生したENI
srcaddr 通信元IP
dstaddr 宛先IP
srcport 送信元ポート
dstport 宛先ポート
protocol プロトコル
packets パケット数
bytes バイト数
start 通信開始時間
end 通信終了時間
action 判定 (ACCEPT or REJECT)
log-stattus ログの状態 (OK or NODATA(通信なし) or SKIPDATA)
| 記号 | 意味 |
|---|---|
| $0 | 行全体 |
| $1 | 1列目 |
| $2 | 2列目 |
| $NF | 最後の列 |
上記表から当てはめると以下になる
$1 version VPC Flow Logsのフォーマットバージョン番号
$2 account-id AWSのアカウントID
$3 interface-id 通信が発生したENI
$4 srcaddr 通信元IP
$5 dstaddr 宛先IP
$6 srcport 送信元ポート
$7 dstport 宛先ポート
$8 protocol プロトコル
$9 packets パケット数
$10 bytes バイト数
$11 start 通信開始時間
$12 end 通信終了時間
$13 action 判定 (ACCEPT or REJECT)
$14 log-stattus ログの状態 (OK or NODATA(通信なし) or SKIPDATA)
この内容を念頭に置いておくと以降のawsコマンドの意味が理解できると思います。
怪しいIPを抽出
awk '{print $4}' $(find ./vpcflowlogs -type f) | sort | uniq -c | sort -nr | head -20
コマンドの意味
-
find ./vpcflowlogs -type fでvpcflowlogsディレクトリ配下にあるすべてのファイルのパス一覧を取得 -
{print $4}でそれらのファイル全て読み込んで4列目を抽出する -
sort: 値をソートする -
uniq -c: 同じ値の件数をカウント -
sort -nr件数の多い順に並べる head -20
# 出力結果例
# 左がアクセス回数、右がアクセス元IP
900 100.xxx.xxx.xx
400 200.xxx.xxx.xx
インターネット向けの通信の抽出
# 送信元が10.0.x.xでかつ、プライベートIPではない通信を抽出し、送信元IP・宛先IP・宛先ポートを表示する
awk '$4 ~ /^10.\.0\./ && $5 !~ /^(10\.|172\.16\.|172\.17\.|172\.18\.|192\.168\.)/ {print $4, $5, $7}'
コマンドの意味
-
find ./vpcflowlogs -type fでvpcflowlogsディレクトリ配下にあるすべてのファイルのパス一覧を取得 -
$4 ~ /^10\.10\.で「10.0で始まる」 -> つまり送信元が10.0.x.xの通信 -
$4 ~ /^10.\.0\./ && $5 !~ /^(10\.|172\.16\.|172\.17\.|172\.18\.|192\.168\.)で送信元IPが10.0.x.x かつ 宛先IPが!~で一致しないことを示している -> つまり、「172.16.x.x」「172.17.x.x」「172.18.x.x」「192.178.x.x」に一致しないを指定しているためプライベートIPアドレス帯を除外している -
print $4, $5, $7で送信元IP、宛先IP、ポートを指定して出力
送信元IP 宛先IP ポートを出力
上記を使用してVPC Flow Logsのログチェックは最短でできそうですね。