1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

VPC Flow LogsのTCPフラグを真面目に調査してみた

Last updated at Posted at 2022-09-04

はじめに

社会人 20 年、AWS をお触りするようになり 10 年が経ちました。
これまで AWS の VPC Flow Logs のお世話になってきました。

しかし、通信の行きと戻りを意識したり、順次追加されてきた
カスタム形式のログフィールドについて、じっくりと観察したことがありませんでした。

ということで、今回はいくつかのシナリオでトラフィックを流してみて
特に TCPフラグがどのような値になっているか見てみました。

【参考】
VPC フローログを使用した IP トラフィックのログ記録

利用環境

・ Private subnet に EC2 インスタンスを2台用意し、VPC Flow Logs は CloudWatch Logs に出力する構成としています。
・ vm01 から vm02 に対して、PING や SSH (SFTP) で通信できるようにセキュリティグループを設定しています。
・ VPC Flow Logs は VPC に対して作成しています。

【構成図】
image.png

【EC2情報】

# 名前 OS Instance Type instance-id eni IPアドレス
01 vm01 Amazon Linux 2 t2.micro i-0360afced64ba1444 eni-0fb7dcfbbbb2f6573 10.0.129.221
02 vm02 Amazon Linux 2 t2.micro i-026cb4d7681325c92 eni-0652da0ac0ca00dee 10.0.130.11

【セキュリティグループ設定】

方向 タイプ プロトコル ポート範囲 ソース
インバウンドルール すべての ICMP - IPv4 ICMP すべて 10.0.128.0/20
インバウンドルール SSH TCP 22 10.0.128.0/20
アウトバウンドルール すべてのトラフィック すべて すべて 0.0.0.0/0

【VPC FLow Logsの設定】

項目 内容
フィルタ すべて
最大集約間隔 1 分間
送信先 CloudWatch Logs に送信
ログレコード形式 カスタム形式
ログ形式 すべて選択(詳細は「形式のプレビュー」参照)
形式のプレビュー
${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}

【参考】
VPCフローログの取得方法(CloudWatch Logsに保存)

実施内容

・vm01 から下記 3 つの通信を実施し、結果のログを CloudWatch Logs Insight でクエリしてみます。

  1. PING 疎通
  2. curl コマンドで Web アクセス
  3. SFTP でファイル転送

1. PING 疎通

  • まずはシンプルに vm01 から vm02 に対して、PING (毎秒 10,000 Bytes ) を実施しました。
ping コマンド
[root@ip-10-0-129-221 bin]# ping -s 10000 10.0.130.11 

【シーケンス図】
image.png

  • 次に CloudWatch Logs Insight で確認します。
  • [CloudWatch] > [ログ] > [ログのインサイト]を開きます。
  • 画面上部で VPC Flow Logs を出力している ロググループ を選択します。(今回は vpcflowlogs)
  • 下記のクエリ文で [クエリの実行] をおこないます。

【参考】
CloudWatch Logs Insights のクエリ構文

PING 実行結果確認用のクエリ文
fields @timestamp
| parse '* * * * * * * * * * * * * * * * * * * * * * * * * * * * *' as `account-id`, action, `az-id`, bytes, dstaddr, dstport, end, `flow-direction`, `instance-id`, `interface-id`, logstatus, packets, `pkt-dst-aws-service`, pktdstaddr, `pkt-src-aws-service`, pktsrcaddr, protocol, region, srcaddr, srcport, start, sublocationid, sublocationtype, `subnet-id`, tcpflags, `traffic-path`, type, version, `vpc-id`
| display @timestamp, start, end, action, logstatus, srcaddr, srcport, dstaddr, dstport, `interface-id`, `flow-direction`, packets, bytes, protocol, tcpflags
| filter `instance-id` in ['i-0360afced64ba1444','i-026cb4d7681325c92']
| filter dstaddr in ['10.0.129.221','10.0.130.11']
| filter srcaddr in ['10.0.129.221','10.0.130.11']
| filter protocol=1
| sort @timestamp desc

【補足説明】
・ カスタム形式のログに合わせて、parse句でログを解析してフィールド抽出しています。
・ ログ分析に必要なフィールドだけに絞るため、display句で表示するフィールドを指定しています。
・ vm01 と vm02 間の通信に絞るため、filter句で インスタンス ID、宛先 IP、送信元 IPを使って絞っています。
・ ICMP 通信に絞るため、filter句でプロトコル番号を 1 に絞っています。
・ イベント発生時刻の新しい順にsort句で並び替えています。

【クエリ結果】
image.png

【考察】
・ フローログの最大集約間隔が 1 分間 のため、1 分以内の間隔に集約されています。
・ IP アドレスから #2 がエコー要求、 #1 がエコー応答のはずですが、情報がないため行きと帰りの判断ができませんでした。
・ ICMP 通信は TCP ではないため、当然tcpflag0です。

2. curl コマンドで Web アクセス

  • 事前に nslookup コマンドでwww.google.comの名前解決を実施し、IP アドレスを確認しました。
  • IP アドレスを確認した上で curl コマンドでwww.google.comに Web アクセスを実施しました。
curl コマンド
[root@ip-10-0-129-221 bin]# nslookup www.google.com
Server:         10.0.0.2
Address:        10.0.0.2#53

Non-authoritative answer:
Name:   www.google.com
Address: 172.217.175.36
Name:   www.google.com
Address: 2404:6800:4004:822::2004

[root@ip-10-0-129-221 bin]# curl www.google.com

【シーケンス図】
・ まずは、TCP スリーウェイハンドシェークによるコネクション接続開始フェーズです。
image.png

・ 次に GET でデータを受信します。
image.png

※ 公式ドキュメントの抜粋ですが、ACK のみの場合はtcpflag0になります。

フローログエントリが ACK パケットのみで構成されている場合、フラグ値は 16 ではなく 0 になります。

・ 最後に TCP コネクションを切断します。(腑に落ちない点がありますが、クエリ結果で後述します)
image.png

  • CloudWatch Logs Insight において、下記内容で [クエリの実行] をおこないます。
Web アクセス結果確認用のクエリ文
fields @timestamp
| parse '* * * * * * * * * * * * * * * * * * * * * * * * * * * * *' as `account-id`, action, `az-id`, bytes, dstaddr, dstport, end, `flow-direction`, `instance-id`, `interface-id`, logstatus, packets, `pkt-dst-aws-service`, pktdstaddr, `pkt-src-aws-service`, pktsrcaddr, protocol, region, srcaddr, srcport, start, sublocationid, sublocationtype, `subnet-id`, tcpflags, `traffic-path`, type, version, `vpc-id`
| display @timestamp, start, end, action, logstatus, srcaddr, srcport, dstaddr, dstport, `interface-id`, `flow-direction`, packets, bytes, protocol, tcpflags
| filter dstaddr in ['10.0.129.221','172.217.175.36']
| filter srcaddr in ['10.0.129.221','172.217.175.36']
| filter protocol=6
| sort @timestamp desc

【補足説明】
・ カスタム形式のログに合わせて、 parse句でログを解析してフィールド抽出しています。
・ ログ分析に必要なフィールドだけに絞るため、 display句で表示するフィールドを指定しています。
・ vm01 と www.google.com 間の通信に絞るため、filter句で 宛先 IP、送信元 IPを使って絞っています。
・ google の IP は、nslookup コマンドで名前解決した172.217.175.36としています。
・ TCP 通信に絞るため、filter句でプロトコル番号を 6 に絞っています。
・ イベント発生時刻の新しい順に sort句で並び替えています。

【クエリ結果】
image.png

【考察】
・ フローログの最大集約間隔が 1分間 のため、1分以内の間隔に集約されています。
・ #2 の宛先ポートが80、TCP フラグが ❶SYN(2)+❺FIN(1)で合計3となっているため、行きの通信だと判断できます。
・ #1 の送信元ポートが80、TCP フラグが ❷SYN(2)+ACK(16)+❼FIN(1)で合計19となっているため、戻りの通信だと判断できます。
・ どうも❺と❼のTCP切断要求時のACK(16)は、計算に入らないようです。理由までは解明できませんでした。

※ 公式ドキュメントの抜粋ですが、集約間隔内だと各パケットの TCPフラグ は合計されます。

TCP フラグは、集約間隔内に OR 処理することができます。短い接続の場合、フラグがフローログレコードの同じ行に設定されることがあります (例えば、SYN-ACK と FIN の場合は 19、SYN と FIN の場合は 3 など)。例については、「TCP フラグシーケンス」を参照してください。

【参考】
TCPフラグ値 早見表
TCP three-way handshaking

3. SFTP でファイル転送

  • 最後に SFTP 接続を行い、410 Bytes の適用なテキストファイルを転送してみます。
  • また、SFTP の切断はデータ転送後、6 分の間をおいてみました。
sftp コマンド
[root@ip-10-0-129-221 tmp]# sftp hibino@10.0.130.11
hibino@10.0.130.11's password:
Connected to 10.0.130.11.
sftp> put test.txt
Uploading test.txt to /home/hibino/test.txt
test.txt                                                                                                       
100%  410   777.3KB/s   00:00

< 約 6 分放置 >

sftp> quit

【シーケンス図】
・ まずは、TCP スリーウェイハンドシェークによるコネクション接続開始フェーズです。
image.png

・ 次にtest.txtのテキストデータを転送します。
image.png

・ 約 6 分の間をおいて、 SFTP を切断します。
image.png

  • CloudWatch Logs Insight において、下記内容で [クエリの実行] をおこないます。
SFTP データ転送結果確認用のクエリ文
fields @timestamp
| parse '* * * * * * * * * * * * * * * * * * * * * * * * * * * * *' as `account-id`, action, `az-id`, bytes, dstaddr, dstport, end, `flow-direction`, `instance-id`, `interface-id`, logstatus, packets, `pkt-dst-aws-service`, pktdstaddr, `pkt-src-aws-service`, pktsrcaddr, protocol, region, srcaddr, srcport, start, sublocationid, sublocationtype, `subnet-id`, tcpflags, `traffic-path`, type, version, `vpc-id`
| display @timestamp, start, end, action, logstatus, srcaddr, srcport, dstaddr, dstport, `interface-id`, `flow-direction`, packets, bytes, protocol, tcpflags
| filter `instance-id` in ['i-0360afced64ba1444','i-026cb4d7681325c92']
| filter dstaddr in ['10.0.129.221','10.0.130.11']
| filter srcaddr in ['10.0.129.221','10.0.130.11']
| filter protocol=6
| sort @timestamp desc

【補足説明】
・ カスタム形式のログに合わせて、 parse句でログを解析してフィールド抽出しています。
・ ログ分析に必要なフィールドだけに絞るため、 display句で表示するフィールドを指定しています。
・ vm01 と vm02 間の通信に絞るため、filter句で インスタンス ID、宛先 IP、送信元 IPを使って絞っています。
・ TCP 通信に絞るため、filter句でプロトコル番号を 6 に絞っています。
・ イベント発生時刻の新しい順に sort句で並び替えています。

【クエリ結果】
image.png

【考察】
・ データ転送時の #7 と 8 では、ACK のみのため、やはりtcpflag0でした。
・ SFTP 切断時の #1 〜 4 では、ENI ごとに ingress と egress で計 4 つありましたが、いずれもtcpflagは FYN(1)でした。

まとめ

さて、いかがでしたでしょうか?

通信の方向は、ポート番号と TCP フラグを組み合わせてみることで判断できることが分かりました。
戻り通信の場合、TCP フラグ値は SNY/ACK(2+16=18)以上になっていることでも判断材料になります。
しかし、コネクション切断時の TCP フラグ値が FYN(1) のみであることは腑に落ちませんでした。

検証が終わった後に、確認した内容が全く同じように公式ドキュメントに書かれていて落ち込みました。

あとは最大集約間隔 1 分間でフローをまとめられてしまうため、正確な通信を把握したい場合は
やはり VPC Traffic Mirroring を使って、フルパケットキャプチャするしかないですね。

1
1
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
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?