Course-এর সূচি

22.3

VPC Flow Log আর সমস্যা খোঁজা

একটা flow log record পড়া, ACCEPT/REJECT-এর ধরন দেখে বোঝা আটকাচ্ছে NACL না Security Group, আর log বিশ্লেষণের pipeline।

20 মিনিট পড়া + Animation

টিপস: ডটেড-আন্ডারলাইন করা যেকোনো শব্দে ট্যাপ বা Hover করলে তার অর্থ দেখবে।

এই লেসন শেষে তুমি পারবে

  • VPC Flow Logs কী ধরে রাখে (IP flow-এর metadata, payload কখনো না), কোন কোন level-এ চালু করা যায় (VPC, subnet, network interface, সাথে আলাদা Transit Gateway flow log), আর কোন traffic সে কখনোই দেখে না, বুঝিয়ে বলতে।
  • Default format-এর একটা record field ধরে ধরে পড়তে, inbound আর outbound আলাদা করতে, আর custom format-এর বাড়তি field-গুলো চিনতে (pkt-srcaddr, tcp-flags, flow-direction, traffic-path…)।
  • ACCEPT/REJECT-এর ধরন দেখে বলতে traffic আটকেছে security group না network ACL, বাইরে থেকে আসা connection আর instance-এর নিজের শুরু করা connection, দুই ক্ষেত্রেই।
  • গন্তব্য বাছতে: CloudWatch Logs (metric filter, alarm, Logs Insights, Contributor Insights), S3 আর Athena (মাসের পর মাসের হিসাব, সবচেয়ে সস্তা), বা Amazon Data Firehose (Splunk, OpenSearch), আর ঠিক permission দিতে: CloudWatch Logs-এর জন্য IAM role, S3-এর জন্য bucket policy।
  • “আমার instance internet-এ যেতে পারছে না” সমস্যা IPv4 checklist ধরে খুঁজতে, প্রমাণ হিসেবে flow log ব্যবহার করে, আর কখন Reachability Analyzer, Traffic Mirroring বা GuardDuty বেশি কাজের, তা জানতে।

#VPC-র call record

পুলিশ যখন কোনো phone নিয়ে তদন্ত করে, কথোপকথনটা তাদের খুব কমই লাগে। Operator-এর call detail record-ই যথেষ্ট: কোন নম্বর কোন নম্বরে call করেছিল, কখন, কতক্ষণ, আর call লেগেছিল কিনা। তোমার VPC-র জন্য VPC Flow Logs ঠিক সেই জিনিস। প্রতিটা network interface (ENI)-এর জন্য সে লিখে রাখে কোন address কোন address-এর সাথে কথা বলল, কোন port আর protocol-এ, কতগুলো packet আর byte, কখন, আর traffic-টা accept হলো নাকি reject। কী কথা হলো, সেটা সে কখনো লেখে না।

#শুধু metadata, payload কখনো না

একটা flow log record-এ থাকে source আর destination address, port, protocol নম্বর, packet আর byte-এর হিসাব, শুরু আর শেষের সময়, আর action: ACCEPT অথবা REJECT। Packet-এর ভেতরের HTTP request, SQL query, file বা password সে কখনো রাখে না। Notes-এর সবচেয়ে বড় exam trick এটাই: প্রশ্নে যদি payload লাগে, flow log ভুল উত্তর।

Action হলো ওই network interface-এর security group আর network ACL-এর সিদ্ধান্ত। Network-এর ওপরে application কেন ব্যর্থ হলো, flow log তা বলে না, আর route না থাকার কারণে packet হারালে সেটাকেও REJECT হিসেবে দেখায় না (নিচের checklist অংশে দেখবে route না থাকলে আসলে কেমন দেখায়)।

#তিনটা level, আর managed service-এর ENI

Flow log বানানো যায় তিন রকম resource-এর জন্য (slide p740):

Levelকী কী ধরেসাধারণ ব্যবহার
VPCVPC-র সব network interface, পরে বানানোগুলোওProduction VPC-র জন্য default পছন্দ
Subnetওই subnet-এর সব network interfaceসংবেদনশীল কোনো subnet, যেমন database-এর স্তর
Network interface (ENI)একটা interface, যেমন একটা EC2 instance-এরকম খরচে একটা server-এর সমস্যা খোঁজা

VPC বা subnet-এ flow log দিলে ভেতরের প্রতিটা ENI পাহারায় আসে, আর পরে চালু হওয়া কোনো ENI traffic পাঠানো মাত্রই নিজের log stream পায়। এর মধ্যে আছে AWS-এর service-গুলো তোমার subnet-এ যেসব interface বানায় সেগুলোও: Elastic Load Balancing, RDS, ElastiCache, Redshift, WorkSpaces, NAT gateway, Transit Gateway attachment আর interface VPC endpoint। ENI যে service-এরই হোক, flow log বানাতে হয় EC2/VPC-র দিক থেকেই।

বানানোর সময় আরও তিনটা পছন্দ:

  • Traffic type: ALL, শুধু ACCEPT, বা শুধু REJECT। আটকে যাওয়া traffic নজরে রাখার সস্তা উপায় শুধু REJECT; তদন্তের জন্য চাই ALL।
  • গন্তব্য: CloudWatch Logs, S3 বা Amazon Data Firehose (নিচের অংশে)।
  • Record format আর সর্বোচ্চ aggregation interval (পরের অংশে)।

Transit Gateway Flow Logs আলাদা একটা resource type, নিজস্ব field-সহ (tgw-id, tgw-attachment-id, packets-lost-no-route, packets-lost-blackhole…), বানানো হয় transit gateway-তে বা তার কোনো একটা attachment-এ (লেসন ২২.৬)। Peer করা VPC-তে flow log দিতে পারবে শুধু সেটা তোমার নিজের account-এ হলে।

Flow log-এর data নেওয়া হয় traffic-এর পথের বাইরে থেকে, তাই চালু বা বন্ধ করলে throughput বা latency-তে কোনো প্রভাব পড়ে না।

#একটা flow log record পড়া

#Default format

Default format হলো version 2: space দিয়ে আলাদা করা চোদ্দটা field, সবসময় এই ক্রমে (slide p742):

#Fieldমানে
1versionFormat-এর version: default format-এ 2
2account-idNetwork interface-টা যে account-এর
3interface-idযে ENI traffic দেখেছে
4srcaddrSource address (বাইরে যাওয়া traffic-এ ENI-র private IPv4 বা IPv6 address)
5dstaddrDestination address (ভেতরে আসা traffic-এ ENI-র private address)
6srcportSource port
7dstportDestination port
8protocolIANA-র protocol নম্বর: 6 = TCP, 17 = UDP, 1 = ICMP
9packetsএই interval-এ এই flow-এর packet
10bytesএই interval-এ এই flow-এর byte
11startInterval-এর প্রথম packet-এর Unix সময়
12endInterval-এর শেষ packet-এর Unix সময়
13actionACCEPT বা REJECT
14log-statusOK; NODATA (interval-এ কোনো traffic নেই); SKIPDATA (ভেতরের capacity-র সীমা বা কোনো ভুলে কিছু record বাদ পড়েছে)

যে field খাটে না সেখানে থাকে -। একটা NODATA record-এ address আর হিসাবের জায়গায় শুধু dash।

#একটা record পড়ে দেখি

2 111122223333 eni-0a1b2c3d4e5f67890 203.0.113.50 10.0.1.25 51544 443 6 12 4310 1730448000 1730448060 ACCEPT OK

বাঁ থেকে ডানে পড়ো: version 2; account 111122223333; দেখেছে ENI eni-0a1b2c3d4e5f67890; 203.0.113.50-এর port 51544 (একটা browser-এর ephemeral port) থেকে 10.0.1.25-এর port 443-এ; protocol 6, মানে TCP; ১২টা packet, ৪,৩১০ byte; ১ নভেম্বর ২০২৪, UTC সকাল ৮:০০:০০ থেকে ৮:০১:০০-র মধ্যে; accept হয়েছে; log স্বাভাবিকভাবে লেখা।

দিক default format-এর কোনো field না। ENI-র নিজের private address কোথায় বসেছে তা দেখে দিক বোঝো: 10.0.1.25 আছে dstaddr-এ, তাই এটা ENI-র দিকে inbound। Reply আসে দ্বিতীয় একটা record হয়ে, address আর port উল্টে। একটা TCP connection, দুটো record, দুটোই একই interface-এর চোখ দিয়ে দেখা।

Slide p742 ব্যবহারগুলো বলে দেয়: srcaddr/dstaddr দিয়ে সমস্যার address, srcport/dstport দিয়ে সমস্যার port খোঁজা, action বলে security group বা network ACL-এর কারণে সফল নাকি ব্যর্থ, আর পুরোটা দিয়ে ব্যবহারের ধরন বা ক্ষতিকর আচরণের বিশ্লেষণ, S3-এ Athena বা CloudWatch Logs Insights দিয়ে।

#Aggregation interval আর পৌঁছানোর দেরি

Flow log real time না। একই flow-এর packet (একই ENI-তে একই five-tuple) একটা capture window জুড়ে যোগ হতে থাকে:

  • সর্বোচ্চ aggregation interval default-এ ১০ মিনিট; আরও সূক্ষ্ম record চাইলে ১ মিনিট বাছতে পারো (record বেশি, তাই খরচও বেশি)।
  • Nitro-ভিত্তিক instance-এ interval সবসময় ১ মিনিট বা কম, তুমি যা-ই বাছো।
  • Window বন্ধ হওয়ার পর পৌঁছাতে সাধারণত লাগে CloudWatch Logs-এ মোটামুটি ৫ মিনিট আর S3-এ মোটামুটি ১০ মিনিট, best effort।

মানে সমস্যা ঘটার কয়েক মিনিট পরে তার record দেখা যায়। সেকেন্ডের হিসাব চাইলে CloudWatch metric বা Traffic Mirroring, flow log না।

#Custom format: বাড়তি field

Custom format-এ তুমি ঠিক করো কোন field থাকবে আর কোন ক্রমে। Record-এর version হয় তোমার বাছা field-গুলোর মধ্যে সবচেয়ে বড় version। যেগুলো জানা কাজের:

Field (version)কী যোগ করে
vpc-id, subnet-id, instance-id (3)ENI কোথায় আছে, আলাদা inventory মিলিয়ে দেখা ছাড়াই
tcp-flags (3)FIN 1, SYN 2, RST 4, SYN-ACK 18-এর bitmask (interval-এর ভেতরে OR হয়: 19 = SYN-ACK + FIN)। SYN-ACK ছাড়া শুধু SYN-ওয়ালা অনেক flow মানে সম্ভবত port scan
type (3)IPv4, IPv6 বা EFA
pkt-srcaddr, pkt-dstaddr (3)Packet-এর আসল source আর destination। NAT gateway-এর ENI-তে srcaddr/dstaddr দেখায় NAT-এর নিজের address; এরা দেখায় instance আর আসল destination। EKS pod-এর address-ও
region, az-id, sublocation-type, sublocation-id (4)Region, AZ ID, Local Zone, Wavelength বা Outpost
pkt-src-aws-service, pkt-dst-aws-service (5)কোনো address কোন AWS service-এর (S3, DYNAMODB, EC2, ROUTE53…)
flow-direction (5)ingress বা egress, দিক আর আন্দাজ করতে হয় না
traffic-path (5)Egress-এর জন্য: 1 VPC-র ভেতরে, 2 internet gateway বা gateway endpoint, 3 virtual private gateway, 4 একই Region-এ peering, 5 অন্য Region-এ peering, 6 Local বা Wavelength Zone, 7 gateway endpoint, 8 internet gateway
ecs-… field (7)awsvpc mode-এ চলা ECS task-এর cluster, service, task আর container
reject-reason (8)VPC Block Public Access reject করলে BPA, encryption control-এর জন্য EC

নতুন version-গুলো (৯ থেকে ১১, ২০২৫–২০২৬) যোগ করেছে regional NAT gateway-এর ID, flow-টা encrypted কিনা, EC2 আর Auto Scaling group-এর tag-এর মান, আর next-hop-এর field। Production-এ এগুলো কাজের; পরীক্ষা জানে default field, pkt-srcaddr/pkt-dstaddr আর custom format-এর ধারণাটা।

#Flow log যা কখনো দেখে না

কিছু traffic একদমই log হয় না:

  • Amazon DNS server-এর traffic (Amazon-এর দেওয়া resolver, VPC-র base address + 2, 169.254.169.253-তেও পাওয়া যায়)। নিজের DNS server চালালে তার traffic সাধারণ traffic, সেটা log হয়।
  • 169.254.169.254-এ, মানে instance metadata service-এ আসা-যাওয়া।
  • 169.254.169.123-এ, মানে Amazon Time Sync Service-এ আসা-যাওয়া।
  • DHCP আর ARP traffic।
  • Amazon-এর activation server-এ Windows license activation-এর traffic।
  • Default VPC router-এর reserved address-এ যাওয়া traffic।
  • Mirror করা traffic-এর source দিকটা (mirror target-এ পৌঁছানো কপিগুলোই শুধু দেখবে)।
  • Endpoint network interface আর Network Load Balancer-এর network interface-এর মধ্যের traffic।

Address-এর দুটো খুঁটিনাটি ছবিটা পুরো করে: secondary private IPv4 address-এ পাঠানো traffic-এ dstaddr-এ দেখায় primary address (আসলটা পেতে pkt-dstaddr), আর NAT gateway বা EKS pod-এর বেলায় packet-এর আসল address থাকে শুধু pkt-srcaddr/pkt-dstaddr-এ।

যা দেখা যায় না, NAT আর একটা miner

একটা private instance কথা বলে Amazon DNS server, metadata service আর NAT gateway হয়ে internet-এর সাথে। এর কিছু traffic flow log-এ কখনোই আসে না; কিছু আসে দুবার।

পরিস্থিতি

Amazon resolver-এ DNS আর metadata call কোনো record-ই রাখে না।

Instance10.0.2.40
Amazon DNS10.0.0.2record নেই
A? api.example.com

Flow log record

ENIsrcaddrdstaddrpkt-srcaddrpkt-dstaddraction
—————কিছু নেই
ধাপ 1 / 3
1

Instance Amazon-এর দেওয়া DNS server দিয়ে একটা নাম resolve করে (VPC-র base address যোগ দুই, এখানে 10.0.0.2)। Query আর উত্তর দুটোই হয়, তবুও flow log কিছুই লেখে না: Amazon DNS server-এর traffic log হয় না।

#Security group না network ACL?

এটাই notes-এর “ultimate trick”, আর flow log নিয়ে পরীক্ষার সবচেয়ে প্রিয় প্রশ্ন। সবকিছু দাঁড়িয়ে আছে লেসন ৩.৫-এর একটা পার্থক্যের ওপর: security group stateful (allow করা traffic-এর reply নিজে থেকেই allow, যেকোনো দিকে), network ACL stateless (reply-এর জন্য আলাদা rule লাগে, সাধারণত ephemeral port 1024–65535-এর জন্য)।

Request আর তার reply, দুটোর action field দেখো (slide p743):

Connection-টা…Request-এর recordReply-এর recordদোষী
ভেতরে আসে (কোনো client instance-কে call করে)inbound REJECTনেইSecurity group অথবা network ACL: দুটোই দেখো
ভেতরে আসেinbound ACCEPToutbound REJECTNetwork ACL-এর outbound rule
বাইরে যায় (instance নিজেই client)outbound REJECTনেইSecurity group অথবা network ACL (outbound rule)
বাইরে যায়outbound ACCEPTinbound REJECTNetwork ACL-এর inbound rule

“আগে ACCEPT, পরে REJECT”-এর সারিগুলো কেন শুধু network ACL হতে পারে: যে security group request accept করেছে, সে connection-টা আগেই মনে রেখেছে, reply আটকানোর ক্ষমতাই তার নেই। Network ACL কিছুই মনে রাখে না; সে reply-কে port 51544-এ যাওয়া একদম নতুন একটা packet হিসেবে বিচার করে, আর 1024–65535 allow করার কোনো rule না থাকলে তার শেষ * rule সেটা deny করে।

Request-টাই যখন reject হয়, তখন ধরন দেখে দুটোকে আলাদা করা যায় না। অন্য স্তরটা দেখো: default network ACL সব allow করে, তাই দোষ security group-এর; আর যে security group পরিষ্কারভাবে source-টা allow করে, সেখানে সন্দেহ network ACL-এর কোনো deny rule-এর ওপর। Reachability Analyzer (নিচে) ঠিক কোন rule তা বলে দেয়।

ACCEPT আর REJECT পড়া

Public subnet-এ একটা e-commerce web server, তার network interface-এ flow log চালু। Network ACL আর security group পার হওয়া প্রতিটা packet নিচের table-এ একটা করে লাইন রেখে যায়।

পরিস্থিতি

একটা HTTPS connection ENI-তে দুটো record বানায়: ভেতরে আসা request, বাইরে যাওয়া reply।

VPC10.0.0.0/16
Public subnet10.0.1.0/24
ক্রেতা203.0.113.50
Network ACLstatelessin: 443 allowed
Web server10.0.1.25
Flow logENI-তে
:51544 → :443
ধাপ 1 / 5
1

একজন ক্রেতা shop খুলছেন। তাঁর browser একটা অস্থায়ী (ephemeral) port বেছে নেয়, 51544, আর port 443-এ connect করে। Subnet-এর কিনারায় প্রথমে network ACL যাচাই হয়: তার inbound rule TCP 443 allow করে।

আসল তদন্তে মাঝে মাঝে দুটো জিনিস গুলিয়ে দেয়:

  • Connection বন্ধ হয়ে যাওয়ার পরে আসা packet-এর (দেরিতে আসা retransmission) জন্যও REJECT লেখা হয়, তাই নইলে সুস্থ একটা server-এ কয়েকটা REJECT লাইন থাকা স্বাভাবিক।
  • Record লেখা হয় ENI-তে, network ACL আর security group বিচার করে দেওয়ার পরে। ঢোকার পথে network ACL যে packet ফেলে দেয়, সেটাও destination ENI-তে REJECT হিসেবে log হয়; “NACL-এর ওপর” আলাদা flow log লাগে না।

কাঁচা লাইন দিয়ে অনুশীলন করো। একটা case বাছো, field চিনতে কোনো লাইনে click করো, তারপর দোষীর নাম বলো:

Flow log গোয়েন্দা

একটা case বাছো, কাঁচা flow log লাইনগুলো পড়ো (default format), কোনো লাইনে click করে তার field-গুলো চিনে নাও, তারপর দোষীর নাম বলো।

Public subnet-এ web server 10.0.1.25। ক্রেতারা বলছেন shop “লোড হতেই থাকে”, তারপর time out। Security group যেকোনো জায়গা থেকে 443 allow করে।

কাঁচা record (parse করতে যেকোনোটায় click করো)

Field দেখতে ওপরের কোনো লাইনে click করো।

দোষী কে?

#Flow log কোথায় যায়

Slide p744 architecture-গুলো দেখায়। একটা flow log একটাই গন্তব্যে পাঠায়; দুটো গন্তব্য লাগলে একই resource-এ দুটো flow log বানাও (প্রতি resource-এ ২৫০টা পর্যন্ত)।

#CloudWatch Logs: নজর রাখা আর সতর্ক করা

Flow log লেখে একটা log group-এ, প্রতিটা ENI-র জন্য একটা log stream (লেসন ১৯.২)। সেখান থেকে:

  • Metric filter মিলে যাওয়া লাইনগুলোকে একটা metric বানায়, যেমন reject হওয়া SSH (dstport 22, action REJECT) বা যেকোনো RDP চেষ্টা; সেই metric-এর ওপর একটা CloudWatch alarm SNS-কে জানায় (লেসন ১৯.৩)।
  • Logs Insights জমা record-এর ওপর query চালায়; flow log-এর field-গুলো সে নিজেই নাম ধরে চিনে নেয় (srcAddr, dstPort, action, bytes…)।
  • Contributor Insights একটা চলমান top-N রাখে: slide p744-এর “top 10 IP address”, সবচেয়ে ব্যস্ত source–destination জোড়া, সবচেয়ে বেশি reject হওয়া source (লেসন ১৯.৪)।
  • Subscription filter দিয়ে group-টা Lambda, Kinesis বা Firehose-এ আরও এগিয়ে পাঠানো যায়।

Record পৌঁছায় কয়েক মিনিটে, flow log-এর পক্ষে “live”-এর সবচেয়ে কাছাকাছি এটাই। তবে অনেক মাস CloudWatch Logs-এ রাখার খরচ S3-এর চেয়ে বেশি।

#S3: অনেকদিন রাখো, Athena দিয়ে query করো

Flow log একটা bucket-এ compress করা log file লেখে, AWSLogs/<account-id>/vpcflowlogs/<region>/<year>/<month>/<day>/-এর নিচে। বানানোর সময় যা বাছতে পারো:

  • File format: plain text (default) অথবা Apache Parquet, columnar, ছোট, আর query করতে অনেক সস্তা।
  • Hive-compatible prefix (year=2026/month=10/…), যাতে Athena আর Glue partition বোঝে।
  • দিনের বদলে ঘণ্টা ধরে partition, যাতে এক বিকেলের query শুধু ওই ঘণ্টাগুলোই পড়ে।

তারপর Athena সরাসরি file-এর ওপর standard SQL চালায়, scan করা data ধরে দাম নেয় (লেসন ১৭.১); ফলাফলের chart বানাতে পারে QuickSight। VPC console তোমার জন্য Athena-র table আর saved query-ও বানিয়ে দেয়। মাস বা বছরের record রাখার সবচেয়ে সস্তা জায়গা S3, আর lifecycle rule পুরনো file-কে আরও ঠান্ডা class-এ সরিয়ে দিতে পারে।

#Amazon Data Firehose: অন্য tool-এ পাঠাও

Flow log পাঠায় একটা Firehose stream-এ (একই বা অন্য account-এ), যেটা buffer করে, দরকারে রূপ বদলায়, আর পৌঁছে দেয় Splunk, OpenSearch, কোনো HTTP endpoint বা S3-এ, ব্যর্থ হলে একটা backup bucket-এ (লেসন ১৩.৬)। কোনো third-party বা কেন্দ্রীয় security tool-কে record একটানা পেতে হলে এটা বাছো। Amazon Data Firehose-এর নাম ফেব্রুয়ারি ২০২৪ পর্যন্ত ছিল Kinesis Data Firehose; notes আর slide পুরনো নামটাই লেখে, আর পরীক্ষার প্রশ্নে যেকোনোটা আসতে পারে।

তোমার দরকারগন্তব্য
Reject হওয়া traffic-এ alarm, top talker, গত কয়েক দিনের দ্রুত খোঁজCloudWatch Logs (metric filter, alarm, Logs Insights, Contributor Insights)
মাসের পর মাসের হিসাব, SQL, সবচেয়ে কম খরচS3 + Athena
Splunk, OpenSearch, partner-এর SIEM, অন্য account-এর pipelineAmazon Data Firehose

#Permission: CloudWatch-এর জন্য role, S3-এর জন্য bucket policy

Permission ছাড়া flow log কোথাও লিখতে পারে না (slide p745):

  • CloudWatch Logs-এর জন্য লাগে একটা IAM role, যেটা তুমি flow log-এর হাতে দাও। তার trust policy-তে service principal vpc-flow-logs.amazonaws.com-কে assume করতে দিতে হবে, আর permission policy-তে allow করতে হবে logs:CreateLogGroup, logs:CreateLogStream, logs:PutLogEvents, logs:DescribeLogGroups আর logs:DescribeLogStreams। যিনি flow log বানাচ্ছেন, তাঁর ওই role-এর জন্য iam:PassRole লাগে। Trust policy-তে aws:SourceAccount আর aws:SourceArn condition দিলে confused deputy সমস্যা থেকে বাঁচা যায়।
  • S3-এর জন্য কোনো IAM role লাগে না। Bucket policy-কে log delivery service delivery.logs.amazonaws.com-কে s3:PutObject (আর s3:GetBucketAcl) করতে দিতে হয়। Bucket তোমার হলে আর তার policy বদলানোর অধিকার থাকলে, flow log বানানোর সময় AWS নিজেই এই policy বসিয়ে দেয়; অন্য account-এর bucket হলে তার মালিক এটা যোগ করেন।
  • Firehose-এ পাঠাতে তোমার account-এর একটা service-linked role ব্যবহার হয় (আর অন্য account-এ পাঠালে এমন একটা role, যাকে গন্তব্য account বিশ্বাস করে)।

তিনটা গন্তব্য, permission-এর দুই নিয়ম

একটা VPC-র flow log পাঠাতে পারে CloudWatch Logs-এ, S3-এ অথবা Amazon Data Firehose-এ। প্রতিটা গন্তব্য আলাদা প্রশ্নের উত্তর দেয়, আর IAM role লাগে শুধু CloudWatch Logs-এর বেলায়।

পরিস্থিতি

Record কয়েক মিনিটে পৌঁছায়; metric filter আর Insights সেগুলোকে alarm আর top-10 তালিকা বানায়।

Flow logVPC levelIAM role ✓
CloudWatch Logslog group
Alarmmetric filter
SNSon-call phone
S3 bucketParquet, ঘণ্টা ধরে
AthenaSQL
QuickSightdashboard
record
ধাপ 1 / 3
1

Flow log তার IAM role assume করে, যে role vpc-flow-logs.amazonaws.com-কে বিশ্বাস করে আর logs:CreateLogGroup, CreateLogStream, PutLogEvents আর Describe call-গুলো allow করে। তারপর log group-এ লেখে, প্রতিটা network interface-এর জন্য একটা করে log stream।

#VPC-র সমস্যা খোঁজা: checklist আর প্রমাণ

লেসন ৩.৩-এ “আমার instance internet-এ যেতে পারছে না”-র checklist দেওয়া হয়েছে। এখানে একই তালিকা, সাথে প্রতিটা দোষের জন্য flow log কী প্রমাণ দেয়, কারণ প্রমাণটাই বলে দেয় কোন জিনিসটা ঠিক করতে হবে।

Public subnet:

  1. Instance-এ public IPv4 address বা Elastic IP।
  2. VPC-তে internet gateway লাগানো।
  3. Subnet-এর route table 0.0.0.0/0 পাঠায় IGW-তে।
  4. Security group traffic allow করে (service-এর port-এর জন্য inbound; outbound default-এ খোলা)।
  5. Network ACL traffic দুই দিকেই allow করে, বিশেষ করে ephemeral port।

Private subnet:

  1. একটা public subnet-এ NAT gateway আছে, আর সেই public subnet-এর route table 0.0.0.0/0 পাঠায় IGW-তে।
  2. Private subnet-এর route table 0.0.0.0/0 পাঠায় NAT gateway-তে।
  3. তারপর একই security group আর network ACL-এর যাচাই।
দোষFlow log কী দেখায়সমাধান
Public IP নেই (public subnet)কয়েকটা packet-ওয়ালা outbound ACCEPT (SYN-এর আবার চেষ্টা), inbound লাইন নেই, REJECT নেইElastic IP, বা auto-assign public IPv4
0.0.0.0/0 → igw-… route নেইশুধু ACCEPT লাইন, কিছুই ফেরে না; route তো firewall নাSubnet-এর নিজের route table-এ route যোগ করো
IGW লাগানো নেইওপরের মতোইIGW লাগাও, তারপর route যোগ করো
Security group port আটকায়Inbound REJECT, reply-এর লাইন নেইInbound rule যোগ করো
Ephemeral port ছাড়া network ACLInbound ACCEPT, outbound REJECT (instance নিজে call করলে outbound ACCEPT, inbound REJECT)ঠিক দিকে 1024–65535 allow করো
NAT-এর দিকে private route নেইInstance-এ outbound ACCEPT, NAT gateway-এর ENI-তে কিছুই নেইPrivate route table-এ 0.0.0.0/0 → nat-…
NAT gateway-এর subnet-এ IGW route নেইNAT ENI-তে বাইরে যাওয়ার record আছে, ফেরার নেইNAT gateway-কে সত্যিকারের public subnet-এ বসাও

মনে রাখার ধরন: REJECT মানে কোনো firewall; ACCEPT আর তারপর চুপচাপ মানে route বা address।

VPC-র সমস্যা খোঁজো

Public subnet-এ একটা web server, private subnet-এ NAT gateway-এর পেছনে একটা app server। প্রতিটা scenario checklist-এর একটা জিনিস ভাঙে, আর দেখায় সেটা নিয়ে flow log কী বলে।

পরিস্থিতি

Public IP, IGW লাগানো, IGW-এর দিকে route, security group, দুই দিকেই network ACL।

VPC10.0.0.0/16
Public10.0.1.0/24
Private10.0.2.0/24
Internet
IGWattached ✓
Web server10.0.1.25public IP ✓
NAT gateway
App server10.0.2.40
:443
ধাপ 1 / 3
1

১ আর ২ নম্বর যাচাই: web server-এর একটা public IPv4 address (বা Elastic IP) আছে, আর VPC-তে একটা internet gateway লাগানো। দুটোই না থাকলে internet-এর কোনো traffic তার কাছে পৌঁছাতে পারে না।

#একই প্রশ্নের জন্য আরও tool

Flow log লেখে যা ঘটেছে। পাশের তিনটা tool আলাদা প্রশ্নের উত্তর দেয়:

  • VPC Reachability Analyzer একটা source আর destination (instance, ENI, IGW, VPN gateway, peering connection, transit gateway…)-এর মধ্যের configuration বিশ্লেষণ করে, আর জানায় হয় পথ খোলা, নয়তো ঠিক কোন জিনিস আটকাচ্ছে: “security group sg-…-এ TCP 8080-এর rule নেই”। সে কোনো packet পাঠায় না, তাই কোনো traffic থাকার আগেও কাজ করে, এমনকি যখন flow log-এ কিছুই আসত না তখনও। এটা ওপরের checklist-টাই, স্বয়ংক্রিয়, প্রতি বিশ্লেষণে মোটামুটি ০.১০ USD।
  • Network Access Analyzer পুরো network জুড়ে উদ্দেশ্য যাচাই করে: “internet থেকে database subnet-এ যাওয়ার সব পথ দেখাও” বা “production থেকে development-এ কিছুই যেতে পারবে না”, আর যে পথগুলো সেটা ভাঙে তা জানায়। এটা audit-এর জন্য, একটা ভাঙা connection-এর জন্য না।
  • Traffic Mirroring পুরো packet, payload-সহ, কপি করে কোনো IDS বা packet analyser-এ পাঠায় (লেসন ২২.৭)। Metadata-তে না কুলালে এটা ব্যবহার করো।

GuardDuty-ও VPC flow log-এর data বিশ্লেষণ করে, তবে নিজের আলাদা feed থেকে: এর জন্য তোমাকে flow log চালু করতে হয় না, আর চালু করলেও GuardDuty-র কিছু বদলায় না (লেসন ২১.৭)। তোমার নিজের flow log তোমার নিজের তদন্ত আর audit-এর জন্য।

#কী কী ভুল হয়

  • CloudWatch Logs-এ data নেই: IAM role-এ logs:PutLogEvents/CreateLogStream নেই, বা তার trust policy-তে vpc-flow-logs.amazonaws.com নেই। describe-flow-logs দেখায় DeliverLogsStatus: FAILED, সাথে “Access error”।
  • দুই মিনিট পরে “flow log বানালাম কিন্তু খালি”: এখনো কিছুই ভুল না। প্রথম record আসে traffic, একটা aggregation interval আর পৌঁছানোর দেরির পরে: ১০ থেকে ২০ মিনিট স্বাভাবিক।
  • S3-তে বানাতে গিয়ে ব্যর্থ: bucket অন্য account-এর আর তার মালিক delivery.logs.amazonaws.com-এর bucket policy যোগ করেননি, অথবা নিজের bucket-এ তোমার PutBucketPolicy নেই। মনে রেখো, স্বয়ংক্রিয় policy আগের bucket policy-কে বদলে দেয়।
  • যে field রাখোনি সেটা দরকার: flow log বদলানো যায় না। Custom format দিয়ে মুছে আবার বানাও; অতীত ওই field ছাড়াই থাকবে।
  • NAT gateway-এর log-এ শুধু NAT-এর নিজের address: instance আর আসল destination দেখতে pkt-srcaddr আর pkt-dstaddr যোগ করো।
  • লাইন নেই মানে traffic নেই ধরে নেওয়া: Amazon resolver-এ DNS, metadata, Time Sync, DHCP আর ARP কখনো log হয় না।
  • ফেলে দেওয়া reply-এর দোষ security group-এর ঘাড়ে চাপানো: অসম্ভব; ACCEPT-এর পরে reply পড়ে গেলে সেটা network ACL।
  • Route-এর দোষ REJECT লাইনে খোঁজা: route, public IP না থাকা বা খুলে রাখা gateway রেখে যায় ACCEPT আর চুপচাপ, REJECT না। Reachability Analyzer ব্যবহার করো।
  • ১ মিনিট interval-এ পুরো VPC-র ALL flow log CloudWatch Logs-এ পাঠিয়ে বিশাল bill: বড় হিসাব S3-এ Parquet-এ পাঠাও, CloudWatch Logs রাখো শুধু যে কয়টা জিনিসে alarm দরকার তার জন্য, বা নজরদারির জন্য শুধু REJECT log করো।
  • সুস্থ server-এ অনেক REJECT লাইন: connection বন্ধ হওয়ার পরে আসা দেরির packet reject হয়ে log হয়। একক লাইন না, ধরন খোঁজো।
  • Payload, URL বা SQL আশা করা: flow log-এ এগুলো কখনো থাকে না। থাকে WAF log, application log বা Traffic Mirroring-এ।

#System design-এ flow log

মনে রাখার মতো ধরন:

  • প্রতিটা production VPC-তে একটা flow log, account-এর baseline থেকেই বানানো (CloudFormation stack set বা Control Tower customisation), আর AWS Config-এর managed rule vpc-flow-logs-enabled flow log ছাড়া যেকোনো VPC ধরিয়ে দেয় (লেসন ১৯.৭)।
  • কেন্দ্রীয় log archive: প্রতিটা account-এর flow log যায় একটা log-archive account-এর একটা S3 bucket-এ (Parquet, ঘণ্টা ধরে partition), security দল Athena দিয়ে query করে। Bucket policy শুধু member account-গুলো থেকে log delivery service-কে allow করে, আর S3 Object Lock বা delete নিষেধ করা policy প্রমাণ নিরাপদ রাখে।
  • দুটো flow log, দুটো কাজ: metric filter আর alarm-এর জন্য শুধু REJECT-এর একটা flow log CloudWatch Logs-এ, আর ইতিহাসের জন্য ALL-এর একটা flow log S3-এ।
  • SIEM feed: flow log Firehose হয়ে Splunk বা OpenSearch-এ, WAF log আর CloudTrail-এর পাশে (লেসন ১৩.৬)।
  • সমস্যা খোঁজার toolkit: traffic থাকার আগে Reachability Analyzer, পরে flow log, payload দরকার হলে Traffic Mirroring, হুমকির জন্য GuardDuty।
  • যা পেলে তা আটকানো: flow log-এ ধরা পড়া top talker আটকানো হয় network ACL-এর deny rule, WAF rule বা Network Firewall দিয়ে, traffic কোথা দিয়ে ঢুকছে তার ওপর নির্ভর করে (লেসন ২৪.৩ এগুলো তুলনা করে)।
  • খরচের হিসাব: flow log নিজে vended log হিসেবে বিল হয় (us-east-1-এ CloudWatch Logs-এ GB প্রতি মোটামুটি ০.৫০ USD, S3 বা Firehose-এ কম, বড় পরিমাণে ধাপে ধাপে ছাড়; CloudWatch-এর pricing page দেখে নিও, দাম যাচাই নভেম্বর ২০২৬), সাথে storage আর Athena-র scan। তবে flow log যে traffic দেখিয়ে দেয়, সেখান থেকেই প্রায়ই বড় সাশ্রয় আসে: দলগুলো flow log দেখেই আবিষ্কার করে যে bill-এর বড় অংশ NAT gateway বা cross-AZ traffic (লেসন ২২.৮)।

#নিজে করে দেখো

এই command-গুলো AWS CLI v2-এর, ap-southeast-1-এ, বানানো ID দিয়ে। Flow log-এ GB প্রতি সামান্য খরচ আছে; যা বানাবে তা মুছে ফেলো।

# 1. CloudWatch Logs-এ পাঠানোর IAM role: flow logs service-কে বিশ্বাস করো, logs-এর action allow করো
cat > trust.json <<'EOF'
{ "Version": "2012-10-17",
  "Statement": [ { "Effect": "Allow",
    "Principal": { "Service": "vpc-flow-logs.amazonaws.com" },
    "Action": "sts:AssumeRole",
    "Condition": { "StringEquals": { "aws:SourceAccount": "111122223333" } } } ] }
EOF
cat > perms.json <<'EOF'
{ "Version": "2012-10-17",
  "Statement": [ { "Effect": "Allow",
    "Action": [ "logs:CreateLogGroup", "logs:CreateLogStream", "logs:PutLogEvents",
                "logs:DescribeLogGroups", "logs:DescribeLogStreams" ],
    "Resource": "*" } ] }
EOF
aws iam create-role --role-name flow-logs-to-cwl --assume-role-policy-document file://trust.json
aws iam put-role-policy --role-name flow-logs-to-cwl --policy-name publish --policy-document file://perms.json

# 2. VPC-তে শুধু REJECT-এর flow log, CloudWatch Logs-এ, 1 মিনিট interval
aws ec2 create-flow-logs --resource-type VPC --resource-ids vpc-0a1b2c3d4e5f67890 \
  --traffic-type REJECT --log-destination-type cloud-watch-logs \
  --log-group-name /vpc/shop-rejects \
  --deliver-logs-permission-arn arn:aws:iam::111122223333:role/flow-logs-to-cwl \
  --max-aggregation-interval 60
# { "ClientToken": "...", "FlowLogIds": [ "fl-0123456789abcdef0" ], "Unsuccessful": [] }

# 3. পৌঁছাচ্ছে তো?
aws ec2 describe-flow-logs --flow-log-ids fl-0123456789abcdef0 \
  --query 'FlowLogs[].[FlowLogStatus,DeliverLogsStatus,DeliverLogsErrorMessage]'
# [ [ "ACTIVE", "SUCCESS", null ] ]
# PutLogEvents ছাড়া role হলে:  [ [ "ACTIVE", "FAILED", "Access error" ] ]

# 4. সব traffic S3-এ: custom format, Parquet, Hive-compatible ঘণ্টাভিত্তিক partition (role লাগে না)
aws ec2 create-flow-logs --resource-type VPC --resource-ids vpc-0a1b2c3d4e5f67890 \
  --traffic-type ALL --log-destination-type s3 \
  --log-destination arn:aws:s3:::shop-flow-logs-example/vpc/ \
  --log-format '${version} ${vpc-id} ${subnet-id} ${instance-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${tcp-flags} ${packets} ${bytes} ${start} ${end} ${action} ${log-status} ${pkt-srcaddr} ${pkt-dstaddr} ${flow-direction} ${traffic-path}' \
  --destination-options FileFormat=parquet,HiveCompatiblePartitions=true,PerHourPartition=true
aws s3api get-bucket-policy --bucket shop-flow-logs-example --query Policy --output text
# ... "Principal":{"Service":"delivery.logs.amazonaws.com"},"Action":"s3:PutObject" ...  (নিজে থেকেই বসানো)

CloudWatch-এর কপিতে একটা metric filter আর একটা Insights query কাজ করতে দেখো:

# 5. Reject হওয়া SSH চেষ্টা গোনো (default-এর ১৪টা field-এর ওপর space দিয়ে ভাগ করা pattern), আর তাতে alarm দাও
aws logs put-metric-filter --log-group-name /vpc/shop-rejects --filter-name ssh-rejects \
  --filter-pattern '[version, account, eni, src, dst, srcport, dstport="22", protocol="6", packets, bytes, start, end, action="REJECT", status]' \
  --metric-transformations metricName=SshRejects,metricNamespace=Shop/Network,metricValue=1
aws cloudwatch put-metric-alarm --alarm-name ssh-scan --namespace Shop/Network --metric-name SshRejects \
  --statistic Sum --period 300 --evaluation-periods 1 --threshold 100 \
  --comparison-operator GreaterThanThreshold \
  --alarm-actions arn:aws:sns:ap-southeast-1:111122223333:netops-oncall

# 6. গত এক ঘণ্টায় সবচেয়ে বেশি reject হওয়া source, Logs Insights দিয়ে
aws logs start-query --log-group-name /vpc/shop-rejects \
  --start-time $(date -d '-1 hour' +%s) --end-time $(date +%s) \
  --query-string 'filter action = "REJECT" | stats count(*) as rejects by srcAddr, dstPort | sort rejects desc | limit 10'
# { "queryId": "a1b2c3d4-5678-90ab-cdef-EXAMPLE33333" }
aws logs get-query-results --query-id a1b2c3d4-5678-90ab-cdef-EXAMPLE33333
# srcAddr 203.0.113.66   dstPort 22    rejects 4812
# srcAddr 198.51.100.9   dstPort 3389  rejects 1290

S3-এ মাসের পর মাসের ইতিহাস Athena দিয়ে query করো (Athena console-এ, বা aws athena start-query-execution দিয়ে):

-- 7. Parquet file-এর ওপর একটা table (Parquet-এ field-এর নামে hyphen-এর বদলে underscore)
CREATE EXTERNAL TABLE vpc_flow_logs (
  version int, vpc_id string, subnet_id string, instance_id string, interface_id string,
  srcaddr string, dstaddr string, srcport int, dstport int, protocol bigint, tcp_flags int,
  packets bigint, bytes bigint, start bigint, `end` bigint, action string, log_status string,
  pkt_srcaddr string, pkt_dstaddr string, flow_direction string, traffic_path int)
PARTITIONED BY (`aws-account-id` string, `aws-service` string, `aws-region` string,
  `year` string, `month` string, `day` string, `hour` string)
STORED AS PARQUET
LOCATION 's3://shop-flow-logs-example/vpc/AWSLogs/';
MSCK REPAIR TABLE vpc_flow_logs;

-- 8. Auditor-এর প্রশ্ন: গত quarter-এ MySQL-এ কে পৌঁছেছিল, আর কত data সরেছিল?
SELECT srcaddr, dstaddr, count(*) AS records, sum(bytes) AS total_bytes
FROM vpc_flow_logs
WHERE year = '2026' AND month IN ('07', '08', '09')
  AND dstport = 3306 AND action = 'ACCEPT'
GROUP BY srcaddr, dstaddr
ORDER BY total_bytes DESC;
-- srcaddr      dstaddr     records  total_bytes
-- 10.0.2.40    10.0.3.15   12960    88412339201
-- 10.0.2.41    10.0.3.15   12941    87990211554
-- 10.0.9.7     10.0.3.15   3        1840          <- analytics subnet? কেন, জিজ্ঞেস করো

“দুই subnet কথা বলতে পারছে না”-র ঘটনায় কোন rule আটকাচ্ছে তা Reachability Analyzer-কে দিয়ে বলাও:

# 9. একটাও packet না পাঠিয়ে web → app, TCP 8080 পথটা বিশ্লেষণ করো
aws ec2 create-network-insights-path --source i-0aaa1111bbbb22223 --destination i-0ccc3333dddd44445 \
  --protocol tcp --destination-port 8080
# { "NetworkInsightsPath": { "NetworkInsightsPathId": "nip-0a1b2c3d4e5f67890", ... } }
aws ec2 start-network-insights-analysis --network-insights-path-id nip-0a1b2c3d4e5f67890
aws ec2 describe-network-insights-analyses --network-insights-path-id nip-0a1b2c3d4e5f67890 \
  --query 'NetworkInsightsAnalyses[0].[NetworkPathFound,Explanations[0].ExplanationCode,Explanations[0].SecurityGroup.Id]'
# [ false, "ENI_SG_RULES_MISMATCH", "sg-0app1234567890abc" ]

# 10. পরিষ্কার করো
aws ec2 delete-flow-logs --flow-log-ids fl-0123456789abcdef0 fl-0fedcba9876543210

কোনো instance থেকে curl -m 5 https://example.com চালাও, time out হোক, তারপর কয়েক মিনিট পরে Logs Insights-এ মিলে যাওয়া record খোঁজো: ঘটনা আর তার flow log-এর মধ্যের দেরিটা হাতেকলমে টের পাওয়ার সবচেয়ে সহজ উপায় এটাই।

#সারসংক্ষেপ

মূল কথা

  • VPC Flow Logs প্রতিটা ENI-তে IP flow-এর metadata লেখে (address, port, protocol, packet, byte, সময়, ACCEPT/REJECT), payload কখনো না। Level: VPC, subnet, ENI; managed service-এর ENI (ELB, RDS, ElastiCache, Redshift, WorkSpaces, NAT gateway, Transit Gateway)-ও ধরা পড়ে; Transit Gateway Flow Logs আলাদা type। Performance-এ কোনো প্রভাব নেই।
  • Default format v2: version, account-id, interface-id, srcaddr, dstaddr, srcport, dstport, protocol, packets, bytes, start, end, action, log-status। দিক = ENI-র নিজের address কোথায় বসেছে। Custom format যোগ করে vpc-id, subnet-id, instance-id, tcp-flags, pkt-srcaddr/pkt-dstaddr (NAT gateway), flow-direction, traffic-path…।
  • Real time না: aggregation default ১০ মিনিট বা ১ মিনিট (Nitro-তে সবসময় ≤ ১ মিনিট), তারপর CloudWatch Logs-এ ~৫ মিনিট, S3-এ ~১০। Flow log বদলানো যায় না: মুছে আবার বানাও। পেছনের কিছু ভরাট হয় না।
  • Log হয় না: Amazon DNS server, 169.254.169.254 metadata, Time Sync, DHCP, ARP, Windows activation, default router-এর reserved IP, mirror করা source traffic।
  • SG না NACL: inbound REJECT → SG অথবা NACL; inbound ACCEPT + outbound REJECT → NACL; outbound ACCEPT + inbound REJECT → NACL। Security group কখনো reply ফেলে না। ACCEPT আর চুপচাপ → route বা address।
  • গন্তব্য: CloudWatch Logs (metric filter, alarm, Logs Insights, Contributor Insights top-10; লাগে vpc-flow-logs.amazonaws.com-এর বিশ্বাস করা একটা IAM role, logs:CreateLogGroup/CreateLogStream/PutLogEvents-সহ); S3 (role নেই, delivery.logs.amazonaws.com-এর জন্য bucket policy, Parquet + ঘণ্টাভিত্তিক partition, Athena = মাসের পর মাসের SQL, সবচেয়ে সস্তা); Amazon Data Firehose (আগের নাম Kinesis Data Firehose) → Splunk, OpenSearch।
  • Checklist: public IP, IGW, IGW-এর দিকে route, SG, দুই দিকে NACL; private: public subnet-এ NAT, যে subnet IGW-তে route করে, আর NAT-এর দিকে route। Reachability Analyzer packet ছাড়াই আটকানো configuration-এর নাম বলে; payload-এর জন্য Traffic Mirroring; GuardDuty flow data পড়ে নিজের feed থেকে।