এই পর্বে যা শিখবেন
- Stateful আর stateless firewall-এর আসল পার্থক্য, packet ধরে ধরে
- একটি অনলাইন দোকানের তিন স্তরের নিয়ম লেখা, group reference দিয়ে
- NACL-এর নিয়মের ক্রম মেলানো আর ephemeral port হিসাব করা
- ঝুঁকিপূর্ণ নিয়ম খুঁজে বের করা, পুরোনো নিয়ম পরিষ্কার করা, flow log দিয়ে যাচাই করা
- খোলা database নিয়ম downtime ছাড়া বন্ধ করার নিরাপদ ক্রম
১ · দুই পাহারাদার — রিসেপশন আর লঞ্চঘাট
পর্ব ২৫-এ আপনি VPC আর subnet দিয়ে জায়গা ভাগ করতে দেখেছেন। পর্ব ২৬-এ দেখেছেন packet কোন পথে যায়। কিন্তু পথ থাকা মানেই ঢোকার অনুমতি নয়। সেই অনুমতি ঠিক করে firewall. Firewall প্রতিটি packet-এর ঠিকানা, port আর protocol দেখে সিদ্ধান্ত নেয়: যেতে দেবে, না আটকাবে। তত্ত্বের দিকটি আছে Computer Networks কোর্সের firewall পর্বে; এখানে আমরা cloud-এ এটি চালানোর দিকটি দেখব।
Cloud-এ সাধারণত দুই স্তরের পাহারা থাকে। দুটির চরিত্র একেবারে আলাদা, আর এই পার্থক্যই পুরো পর্বের মূল কথা।
রিসেপশনিস্ট (security group): একটি অফিসের রিসেপশনে যিনি বসেন, তিনি খাতায় লিখে রাখেন কে ভেতরে গেছেন। সেই অতিথি বেরোনোর সময় তিনি নতুন করে অনুমতি খোঁজেন না। “ইনি তো আমার খাতায় আছেন” বলেই ছেড়ে দেন। লঞ্চঘাটের টিকিট চেকার (network ACL): ইনি কিছু মনে রাখেন না। যাওয়ার সময় একবার টিকিট দেখেছেন, ফেরার সময় আবার দেখবেন। ফিরতি টিকিট না থাকলে আটকে দেবেন, আপনি যতই বলুন “একটু আগেই তো গেলাম”।
এবার সংজ্ঞা। Security group বসে প্রতিটি VM-এর network interface-এ, আর Network ACL (সংক্ষেপে NACL) বসে পুরো subnet-এর সীমানায়। নিচের তুলনাটি AWS-এর নাম ধরে করা, কারণ এই দুই নাম সেখান থেকেই এসেছে। অন্য provider-এর কথা অংশ ৫-এ আসবে।
| বিষয় | Security group | Network ACL |
|---|---|---|
| কোথায় বসে | Network interface (VM-এর দরজা) | Subnet-এর সীমানা |
| স্মৃতি | Stateful: উত্তর নিজে থেকে ফেরে | Stateless: দুই দিকের নিয়ম আলাদা |
| নিয়মের ধরন | শুধু allow | Allow আর deny |
| মূল্যায়ন | সব নিয়ম একসাথে, ক্রম নেই | নম্বরের ক্রমে, প্রথম মিলেই থামে |
| কিছু না মিললে | আটকে যায় | শেষের * নিয়মে আটকে যায় |
| একই subnet-এর ভেতরের traffic | পাহারা দেয় | দেখে না, কারণ সীমানা পার হয় না |
| Source হিসেবে অন্য group | দেওয়া যায় | যায় না, শুধু CIDR |
একটি packet-কে firewall পাঁচটি জিনিস দিয়ে চেনে: source IP, source port, destination IP, destination port আর protocol. এই পাঁচটিকে একসাথে বলে five-tuple. Port আর সংযোগ তৈরির খুঁটিনাটি মনে করতে চাইলে TCP সংযোগের পর্ব দেখে নিন।
২ · Security group — যে দরজা মনে রাখে
একটি security group হলো কতগুলো allow নিয়মের তালিকা। প্রতিটি নিয়মে তিনটি জিনিস থাকে: protocol, port আর উৎস। যেমন “TCP, 443, যেকোনো জায়গা থেকে”। Outbound নিয়মে উৎসের জায়গায় থাকে গন্তব্য। আচরণের নিয়মগুলো এরকম:
- Inbound-এ শুরু থেকেই সব বন্ধ। একে বলে default deny. নতুন group-এ কোনো নিয়ম না লিখলে বাইরে থেকে কিছুই ঢুকবে না।
- Outbound-এ সাধারণত সব খোলা থাকে। AWS-এর নতুন group-এ ডিফল্টে একটি “সব outbound allow” নিয়ম থাকে। এটি মুছে কড়া করা যায়, আর ডেটা বাইরে যাওয়া ঠেকাতে সেটি ভালো অভ্যাস।
- Deny লেখা যায় না। তাই একটি নির্দিষ্ট IP-কে আটকাতে security group কাজে আসে না। সেই কাজ NACL বা WAF-এর।
- সব নিয়ম মিলে যোগফল। একটি VM-এ একাধিক group থাকলে নিয়মগুলোর union খাটে। কোনো একটি allow করলেই যথেষ্ট, তাই নিয়মের ক্রম নিয়ে ভাবতে হয় না।
- একই group-এর দুই VM আপনাআপনি কথা বলতে পারে না। তার জন্য self-referencing rule লাগে, অর্থাৎ group নিজেকেই উৎস হিসেবে দেখায়। ক্লাস্টারের VM-গুলোর পরস্পর যোগাযোগে এটি দরকার। (AWS-এর VPC-র সাথে আসা default group-এ এই নিয়মটি আগে থেকেই থাকে।)
“মনে রাখা” আসলে কী
স্মৃতির কাজটি করে connection tracking. একটি প্রবেশের অনুমতি পেলে firewall তার five-tuple একটি table-এ লিখে রাখে। পরে উল্টো দিক থেকে একই five-tuple-এর packet এলে table-এ মিলিয়েই ছেড়ে দেয়, নিয়মের তালিকা পড়ে না। নিচের সিমুলেটরে একই অনুরোধ, তার উত্তর আর একটি অচেনা packet তিনটি আলাদা firewall-এর ভেতর দিয়ে পাঠানো হয়েছে। চালিয়ে দেখুন, মান বদলে আবার চালান।
// One request and its reply through a stateful and a stateless filter.
const req = { src: '203.0.113.7', sport: 51514, dst: '10.0.1.20', dport: 443 };
const reply = { src: req.dst, sport: req.dport, dst: req.src, dport: req.sport };
const stray = { src: '203.0.113.99', sport: 443, dst: '10.0.1.20', dport: 51514 };
const flow = p => `${p.src}:${p.sport}>${p.dst}:${p.dport}`;
const back = p => `${p.dst}:${p.dport}>${p.src}:${p.sport}`;
const show = p => `${p.src}:${p.sport} -> ${p.dst}:${p.dport}`;
const allowed = (ranges, p) => ranges.some(([lo, hi]) => p.dport >= lo && p.dport <= hi);
function stateful(inRanges, outRanges) {
const table = new Set(); // connection tracking table
return (p, dir) => {
if (table.has(back(p))) return 'ALLOW (tracked, no rule read)';
if (!allowed(dir === 'in' ? inRanges : outRanges, p)) return 'DENY (no rule matched)';
table.add(flow(p));
return 'ALLOW (rule matched, flow recorded)';
};
}
function stateless(inRanges, outRanges) {
return (p, dir) => allowed(dir === 'in' ? inRanges : outRanges, p)
? 'ALLOW (rule matched)' : 'DENY (no rule matched)';
}
function run(name, fw) {
console.log('--- ' + name);
console.log('request', show(req), '=>', fw(req, 'in'));
console.log('reply ', show(reply), '=>', fw(reply, 'out'));
console.log('stray ', show(stray), '=>', fw(stray, 'in'));
}
run('stateful: in 443, out nothing', stateful([[443, 443]], []));
run('stateless: in 443, out 443', stateless([[443, 443]], [[443, 443]]));
run('stateless: in 443, out 1024-65535', stateless([[443, 443]], [[1024, 65535]]));প্রথম অংশ: outbound-এ একটিও নিয়ম নেই, তবু reply পেল ALLOW (tracked, no rule read). উত্তরটি নিয়ম দেখে নয়, table দেখে ছাড়া পেয়েছে।
দ্বিতীয় অংশ: stateless firewall-এ outbound 443 লেখা আছে, তবু উত্তর পেল DENY (no rule matched). উত্তরের গন্তব্য port 443 নয়, 51514. এই ভুলটিই অংশ ৪-এর বিষয়।
তৃতীয় অংশ: outbound 1024-65535 দিতেই উত্তর পেরিয়ে গেল। আর তিন অংশেই stray, অর্থাৎ আগে থেকে না-চাওয়া packet, পেল DENY (no rule matched). Stateful firewall “উত্তরের মতো দেখতে” packet ছাড়ে না, ছাড়ে শুধু table-এ থাকা সংযোগের উত্তর।
৩ · উৎস হিসেবে IP, নাকি অন্য group
নিয়মের উৎস দুইভাবে লেখা যায়। প্রথমটি CIDR, যেমন 10.0.2.0/24, যা একটি ঠিকানার পরিসর। CIDR-এর হিসাব একবার মনে করে নিন: /n মানে 232−nটি ঠিকানা। তাই /32 মানে ১টি, /24 মানে ২৫৬টি, /8 মানে ১,৬৭,৭৭,২১৬টি, আর 0.0.0.0/0 মানে ৪,২৯,৪৯,৬৭,২৯৬টি, অর্থাৎ পুরো IPv4 internet. (বিস্তারিত হিসাব Subnetting পর্বে আর পর্ব ২৫-এ।)
দ্বিতীয় উপায়টি হলো security group reference: উৎসের জায়গায় অন্য একটি group-এর নাম। এর মানে “ওই group যেসব network interface-এ লাগানো আছে, তাদের private ঠিকানা থেকে এলে packet যাবে”। ঠিকানা আপনাকে লিখতে হয় না, provider নিজেই সদস্য তালিকা মিলিয়ে নেয়।
একটি বিয়েবাড়ির ক্যাটারিং ভাবুন। গেটে যদি প্রতিটি পরিবেশকের নাম লিখে দেন, তাহলে কেউ বদলি এলেই তালিকা বদলাতে হবে। তার চেয়ে নিয়ম করুন “যাঁর গায়ে ক্যাটারিংয়ের ব্যাজ, তিনি ঢুকবেন”। লোক বদলায়, ব্যাজের নিয়ম বদলায় না। Security group reference সেই ব্যাজ।
হিসাব করে দেখি: reference কেন জেতে
ধরে নিই একটি app স্তরে ৪০টি instance চলে, আর প্রতিটির দুটি port-এ database-এর সাথে কথা বলা দরকার। IP-এর তালিকা লিখলে নিয়ম লাগবে ৪০ × ২ = ৮০টি। AWS-এ লেখার সময়ে এক group-এ ডিফল্ট সীমা প্রতি দিকে ৬০টি নিয়মের কাছাকাছি (quota বাড়ানো যায়, আর provider-ভেদে সংখ্যা আলাদা)। অর্থাৎ তালিকাটি বসানোই যাবে না। Reference দিলে লাগে ২টি নিয়ম, instance ৩টি হোক বা ৪০টি।
সংখ্যার চেয়েও বড় সুবিধা তিনটি:
- Autoscaling-এ কিছু বদলাতে হয় না। নতুন instance group নিয়ে জন্মায়, পুরোনোটি চলে গেলে সদস্যপদও যায়। (পর্ব ১৭)
- পুরোনো IP-র ঝুঁকি নেই। IP-এর তালিকায় মুছে যাওয়া instance-এর ঠিকানা থেকে যায়, আর সেই ঠিকানা পরে অন্য কেউ পেয়ে যেতে পারে।
- নিয়ম পড়ে অর্থ বোঝা যায়।
from sg-appএকটি উদ্দেশ্য বলে।10.0.2.37/32কিছুই বলে না।
Reference মেলে private ঠিকানায়। App যদি database-এর public ঠিকানা ধরে যোগাযোগ করে, তাহলে packet বাইরে ঘুরে অন্য ঠিকানা নিয়ে আসতে পারে, আর AWS-এর আচরণে নিয়মটি নাও মিলতে পারে। Private ঠিকানা বা private DNS নাম ব্যবহার করুন। VPC-র বাইরের group-কে reference করার ক্ষমতাও সীমিত: peering-এ অনেক সময় চলে, অন্য region-এ provider-ভেদে নাও চলতে পারে। সেখানে CIDR লাগে (পর্ব ২৮)।
Chaining: তিন স্তরের অনলাইন দোকান
একটি কাল্পনিক অনলাইন বাজার অ্যাপ ধরি: সামনে load balancer, মাঝে app server, পেছনে database. প্রতিটি স্তর শুধু তার আগের স্তরকে বিশ্বাস করে। একে বলে security group chaining. নিচের ছবিতে প্রতিটি তীর একটি নিয়ম, আর ছবিতে যে তীর নেই, সেই পথ বন্ধ।
তিন স্তর, প্রতিটি শুধু আগেরটিকে চেনে
Security group chaining in a three-tier shop
| Group | দিক | Port | উৎস বা গন্তব্য | কারণ |
|---|---|---|---|---|
sg-alb | in | 443 | 0.0.0.0/0 | Public দরজা, ক্রেতারা এখানেই আসেন |
sg-alb | out | 8080 | sg-app | শুধু app-এ পাঠানো আর health check |
sg-app | in | 8080 | sg-alb | শুধু load balancer থেকে |
sg-app | out | 5432 | sg-db | Database-এ যাওয়া |
sg-app | out | 443 | 0.0.0.0/0 | Payment API, NAT হয়ে (পর্ব ২৬) |
sg-db | in | 5432 | sg-app | শুধু app থেকে |
sg-db | out | কিছুই না | — | উত্তর এমনিতেই ফেরে, নতুন সংযোগ লাগে না |
খেয়াল করুন, sg-db-তে outbound নিয়ম নেই, তবু database উত্তর দিতে পারে। এটিই stateful হওয়ার সুবিধা। আর একটি কথা: reference নিয়ম অন্য group-এর নিয়ম কপি করে না, শুধু তার সদস্যদের চিনিয়ে দেয়। Chaining network-এর পথ সরু করে, কিন্তু app server হাতছাড়া হলে database-এ পথ থাকবেই। তাই database-এ আলাদা login, কম অনুমতি আর এনক্রিপশন লাগেই (পর্ব ২২)।
৪ · Network ACL — ক্রমে চলা, স্মৃতিহীন নিয়ম
NACL-এর প্রতিটি নিয়মের একটি নম্বর থাকে। Firewall সবচেয়ে ছোট নম্বর থেকে পড়তে শুরু করে। প্রথম যে নিয়ম মেলে, সেটির কথাই শেষ কথা; পরের নিয়ম আর পড়া হয় না। কিছুই না মিললে শেষের * নিয়মটি আটকে দেয়, যা মোছা যায় না।
রেলের সময়সূচির মতো ভাবুন: ওপর থেকে পড়তে পড়তে প্রথম যে ট্রেন মেলে, আপনি সেটিতেই ওঠেন। নিচে আরও ভালো ট্রেন থাকলেও লাভ নেই। সেজন্য একটি নির্দিষ্ট deny নিয়ম সব সময় সাধারণ allow-এর আগে, অর্থাৎ ছোট নম্বরে বসাতে হয়। না হলে সেটি কখনো কাজই করে না। একে বলে rule shadowing. নম্বর দেওয়ার সময় ১০০, ১১০, ১২০ এভাবে ফাঁক রাখুন, যাতে পরে মাঝখানে নতুন নিয়ম বসানো যায়।
// Network ACL: lowest rule number first, the first match decides, then stop.
const ip2n = s => s.split('.').reduce((a, b) => a * 256 + Number(b), 0);
function inCidr(ip, cidr) {
const [net, len] = cidr.split('/');
const size = 2 ** (32 - Number(len));
return Math.floor(ip2n(ip) / size) === Math.floor(ip2n(net) / size);
}
function evaluate(acl, p) {
const sorted = [...acl].sort((a, b) => a.no - b.no);
const trail = [];
for (const r of sorted) {
const hit = inCidr(p.src, r.cidr) && p.port >= r.lo && p.port <= r.hi;
trail.push(`${r.no}:${hit ? 'match' : 'skip'}`);
if (hit) return `${r.action} by ${r.no} [${trail.join(' ')}]`;
}
return `DENY by * [${trail.join(' ')} *:match]`;
}
const DENY_FIRST = [
{ no: 200, action: 'ALLOW', cidr: '0.0.0.0/0', lo: 443, hi: 443 },
{ no: 100, action: 'DENY', cidr: '198.51.100.0/24', lo: 0, hi: 65535 },
];
const ALLOW_FIRST = [
{ no: 100, action: 'ALLOW', cidr: '0.0.0.0/0', lo: 443, hi: 443 },
{ no: 200, action: 'DENY', cidr: '198.51.100.0/24', lo: 0, hi: 65535 },
];
const packets = [
{ src: '198.51.100.9', port: 443 },
{ src: '203.0.113.7', port: 443 },
{ src: '203.0.113.7', port: 22 },
];
for (const [name, acl] of [['deny first', DENY_FIRST], ['allow first', ALLOW_FIRST]]) {
console.log('--- ' + name);
for (const p of packets) console.log(`${p.src}:${p.port}`.padEnd(18), evaluate(acl, p));
}দুটি তালিকায় নিয়ম একই, শুধু নম্বর উল্টো। deny first-এ নিষিদ্ধ ঠিকানা পেল DENY by 100 [100:match]. allow first-এ সেই একই ঠিকানা পেল ALLOW by 100 [100:match], আর deny নিয়মটি পড়াই হলো না।
DENY_FIRST তালিকায় ২০০ নম্বর আগে লেখা হলেও কাজ ঠিক আছে, কারণ sort নম্বর ধরে সাজিয়ে নেয়। লেখার ক্রম নয়, নম্বরের ক্রমই আসল। তৃতীয় packet, port 22, দুই ক্ষেত্রেই পেল DENY by *, কারণ কোনো নিয়মই মেলেনি। মান বদলে নিজের নিয়ম পরীক্ষা করুন।
Ephemeral port: ফিরতি পথের ঠিকানা
আপনি browser-এ একটি সাইট খুললে সংযোগের গন্তব্য port হয় 443. কিন্তু browser নিজেও একটি port থেকে কথা বলে, আর সেই port অপারেটিং সিস্টেম সংযোগের জন্য সাময়িকভাবে বেছে দেয়। একে বলে ephemeral port. Server-এর উত্তরের গন্তব্য port হয় সেটিই। NACL যেহেতু কিছু মনে রাখে না, তাকে নিয়ম করে বলে দিতে হয়: এই পরিসরের port-এ উত্তর বেরোতে পারবে।
| কে ব্যবহার করে | পরিসর | মোট port |
|---|---|---|
| IANA-র সুপারিশ, আধুনিক Windows | 49152-65535 | ১৬,৩৮৪ |
| Linux kernel-এর সাধারণ ডিফল্ট | 32768-60999 | ২৮,২৩২ |
| NACL-এ প্রচলিত নিরাপদ পছন্দ (NAT gateway-সহ সবাইকে ঢেকে ফেলে) | 1024-65535 | ৬৪,৫১২ |
হিসাবটি সহজ: শেষ − শুরু + ১। যেমন ৬৫,৫৩৫ − ১,০২৪ + ১ = ৬৪,৫১২। ক্লায়েন্ট কে হবে, তা আপনি ঠিক করতে পারেন না, তাই public দিকের NACL-এ সবচেয়ে চওড়া পরিসরটিই সাধারণত লিখতে হয়। উল্টো দিকও ভুলবেন না: আপনার server নিজে বাইরে কোনো API-কে ডাকলে তার উত্তর inbound হয়ে ephemeral port-এ ঢোকে।
এবার একটি পুরো যাত্রা দেখি। ক্লায়েন্ট 203.0.113.7 একটি web server-এ HTTPS অনুরোধ পাঠাচ্ছে। সহজ রাখার জন্য ঠিকানা-অনুবাদের অংশ (NAT) বাদ দিয়ে server-এর private ঠিকানা 10.0.1.20 দেখানো হলো। NACL-এর নিয়ম এরকম: inbound ১০০ allow TCP 443; outbound ১০০ allow TCP 443 আর ১১০ allow TCP 1024-65535.
- ক্লায়েন্ট
:51514203.0.113.7 - NACL
subnetমনে রাখে না - Security group
interfaceমনে রাখে - Server
:44310.0.1.20
| Packet | |
| পাহারা | |
| সিদ্ধান্ত | |
| Tracking table |
- অনুরোধ রওনা দিল। ক্লায়েন্টের OS একটি ephemeral port
51514বেছে নিল। গন্তব্য port443. - আগে NACL. Subnet-এ ঢোকার সময় টিকিট চেকার সামনে পড়েন। নিয়ম ১০০ বলছে TCP
443চলবে, তাই packet পাস। - তারপর security group. Inbound নিয়মে
443আছে। পাস করানোর সাথে সাথে five-tuple-টি tracking table-এ লেখা হলো। - Server পেল। Packet প্রোগ্রামে পৌঁছাল, আর সে উত্তর তৈরি করল। আসলে এটি TCP handshake-এর প্রথম packet; পরের প্রতিটি packet-ও একই পাহারা পার হয়, কিন্তু আমরা একটি যাওয়া-আসা দেখছি।
- ফেরার পথে আগে security group. বেরোনোর সময় ক্রম উল্টো। উত্তরের five-tuple table-এ মিলে গেল, তাই outbound নিয়ম পড়াই হলো না।
- এবার NACL, এবং এখানেই আসল পরীক্ষা। উত্তরের গন্তব্য port
51514. নিয়ম ১০০ (443) মিলল না। নিয়ম ১১০ (1024-65535) মিলল, তাই পাস। NACL জানেই না এটি একটি উত্তর, সে শুধু নম্বর মিলিয়েছে। - উত্তর পৌঁছাল। চারবার পাহারা পার হলো: NACL, SG, SG, NACL. দুই NACL-কেই আলাদা করে নিয়ম লিখে রাজি করাতে হয়েছে, আর SG-কে একবার।
এবার সেই বিখ্যাত ভুলটি দেখি। একজন সহকর্মী নিরাপত্তা বাড়াতে নতুন NACL বসালেন, কিন্তু outbound-এ শুধু 443 রাখলেন। নতুনদের হাতে এই ঘটনা অনেকবার ঘটে, কারণ নিয়মটি দেখতে একদম যুক্তিসঙ্গত লাগে।
| Outbound নিয়ম | |
| Packet | |
| Flow log | |
| ব্যবহারকারী দেখছেন |
- নিয়ম বদল। নতুন NACL subnet-এ লাগানো হলো। পুরোনো সব outbound allow চলে গেল, রইল শুধু
443. - অনুরোধ ঢুকল। Inbound NACL আর security group, দুটিই পাস। এই পর্যন্ত কোনো সমস্যা নেই।
- উত্তর আটকাল। Security group ছাড়ল, কিন্তু NACL-এ গন্তব্য port
51514-এর কোনো নিয়ম নেই।*নিয়ম packet ফেলে দিল। - নীরবে ঝুলে থাকা। Firewall কোনো খবর পাঠায় না, packet শুধু হারিয়ে যায়। TCP ভাবে হয়তো পথে হারিয়েছে, তাই আবার চেষ্টা করে। Handshake শেষ না হওয়ায় অনেক সময় nginx-এর log-এ অনুরোধটি থাকেই না।
- Flow log সূত্র দিল। একই সংযোগে inbound ACCEPT আর outbound REJECT. Security group হলে উত্তর আটকাত না, কারণ সে মনে রাখে। তাই সন্দেহের তীর stateless স্তরের দিকে, অর্থাৎ NACL.
- সমাধান। Outbound ১১০ allow TCP
1024-65535যোগ হলো। এবার উত্তর বেরোল। নিয়মটি security group-এ নয়, NACL-এ লাগে, এটি মনে রাখুন।
এজন্য অনেক দলের ব্যবহারিক পরামর্শ হলো: মূল নিয়ন্ত্রণ security group-এ রাখুন, NACL-কে খোলা রেখে শুধু বিশেষ কাজে ব্যবহার করুন। যেমন একটি পুরো ঠিকানা-পরিসর দ্রুত আটকানো, বা সংবেদনশীল subnet-এর চারপাশে মোটা দাগের একটি সীমা টানা। AWS-এর default NACL সব allow করে, কিন্তু আপনার বানানো নতুন NACL শুরুতে সব deny করে। তাই নতুন NACL লাগানো মানেই subnet-এর সব traffic বন্ধ হওয়ার ঝুঁকি।
৫ · অন্য provider-এ একই ধারণা, ভিন্ন নিয়ম
ধারণা একই, কিন্তু আচরণ হুবহু এক নয়। এক provider-এর অভ্যাস অন্যটিতে নিয়ে গেলে ভুল হয়, তাই নিচের তুলনাটি মানচিত্র হিসেবে নিন, সমীকরণ হিসেবে নয়। খুঁটিনাটি লেখার সময়ের, তাই আসল সিদ্ধান্তের আগে provider-এর নথি দেখে নিন।
| বিষয় | AWS | Azure NSG | Google VPC firewall rules |
|---|---|---|---|
| কোথায় লাগে | SG: interface; NACL: subnet | Subnet বা NIC, দুটিতেই | পুরো VPC network-এর ওপর, target দিয়ে সীমিত |
| Stateful? | SG হ্যাঁ, NACL না | হ্যাঁ | হ্যাঁ |
| Deny লেখা যায়? | SG না, NACL হ্যাঁ | হ্যাঁ | হ্যাঁ |
| ক্রম | SG ক্রমহীন, NACL ছোট নম্বর আগে | ছোট priority নম্বর আগে | ছোট priority নম্বর আগে |
| Group-এর মতো উৎস | Security group reference | Application security group | Network tag বা service account |
| ডিফল্ট | Inbound বন্ধ, outbound খোলা | Inbound বন্ধ, VNet-এর ভেতরে খোলা, outbound খোলা | Ingress বন্ধ, egress খোলা |
একটি ব্যবহারিক ফাঁদ: AWS-এর group-এ ক্রম নিয়ে ভাবতে হয় না, কিন্তু Azure আর Google-এ priority ভুল হলে একটি deny আপনার allow-কে ঢেকে ফেলতে পারে। নিচে একই নিয়ম, “app থেকে database-এ 5432”, তিন CLI-তে। এগুলো উদাহরণ মাত্র, আইডি ও নাম কাল্পনিক। Cloud ব্যবহারে টাকা লাগতে পারে, আর পরীক্ষার পর resource মুছে ফেলবেন।
# Allow PostgreSQL into the db group, only from members of the app group
aws ec2 authorize-security-group-ingress \
--group-id sg-0db0000000example \
--protocol tcp --port 5432 \
--source-group sg-0a00000000example# Lower priority number is read first; the source is an application security group
az network nsg rule create \
--resource-group shop-rg --nsg-name db-nsg \
--name allow-app-to-db --priority 200 \
--direction Inbound --access Allow --protocol Tcp \
--source-asgs app-asg --destination-port-ranges 5432# Target and source are network tags on the VMs
gcloud compute firewall-rules create allow-app-to-db \
--network shop-net --direction INGRESS --action ALLOW \
--rules tcp:5432 --source-tags app --target-tags db৬ · 0.0.0.0/0 — কোন দরজায় চলে, কোন দরজায় নয়
Public website-এর 443-এ 0.0.0.0/0 স্বাভাবিক, কারণ সেটিই দোকানের সদর দরজা। সমস্যা হয় যখন একই মান বসে পেছনের দরজায়:
- SSH (
22): Internet-এ চালু থাকা যেকোনো server-এ স্বয়ংক্রিয় স্ক্যান আসতেই থাকে। Key ছাড়া login বন্ধ থাকলেও sshd-এর নিজের দুর্বলতার ঝুঁকি থাকে। - RDP (
3389): Windows server-এর দূর-নিয়ন্ত্রণ। অতীতে login ছাড়াই আক্রমণযোগ্য ত্রুটি পাওয়া গেছে (যেমন ২০১৯-এর BlueKeep, CVE-2019-0708), তাই internet-এ খোলা রাখা বড় ঝুঁকি। - Database (
3306,5432,6379,27017): এগুলো internet-এর জন্য তৈরিই হয়নি। ভুল সেটিংয়ে কিছু database login ছাড়াই খোলা থাকে।
IPv6 ভুলবেন না: ::/0 মানে একই জিনিস, পুরো IPv6 internet. 0.0.0.0/0 মুছে ::/0 রেখে দিলে দরজা খোলাই থাকে। আর port-এর পরিসর দেখেও সতর্ক হোন, 3000-3400 লিখলে তার ভেতরে 3306 আর 3389 দুটিই ঢুকে যায়।
ভালো থেকে সাধারণ ক্রমে: (১) Session manager ধরনের সেবা, যেখানে inbound port একটিও খুলতে হয় না। (২) VPN বা bastion, আর server-এ নিয়ম 22 from sg-bastion. (৩) অস্থায়ীভাবে নিজের একটি IP-র /32, মেয়াদসহ। বিস্তারিত পর্ব ১২-তে আছে।
এবার একটি অডিটর। ধরা যাক প্রতিটি নিয়মের সাথে আপনি flow log থেকে জেনেছেন কত দিন কোনো traffic আসেনি (idle মান)। নিচের সিমুলেটর ঝুঁকি খুঁজে গুরুত্ব অনুযায়ী সাজায়। গুরুত্বের নামগুলো এই উদাহরণের নিজস্ব, কোনো মান (standard) নয়।
// Flag risky security-group rules. Sample data; the severity scheme is ours, not a standard.
const ADMIN = { 22: 'SSH', 3389: 'RDP' };
const DB = { 3306: 'MySQL', 5432: 'PostgreSQL', 6379: 'Redis', 27017: 'MongoDB' };
const RANK = { CRITICAL: 0, HIGH: 1, MEDIUM: 2, LOW: 3 };
const rules = [
{ id: 'r1', group: 'sg-alb', lo: 443, hi: 443, src: '0.0.0.0/0', note: 'public https', idle: 0 },
{ id: 'r2', group: 'sg-app', lo: 22, hi: 22, src: '0.0.0.0/0', note: '', idle: 12 },
{ id: 'r3', group: 'sg-db', lo: 5432, hi: 5432, src: '::/0', note: 'temp debug', idle: 200 },
{ id: 'r4', group: 'sg-db', lo: 5432, hi: 5432, src: 'sg-app', note: 'app to db', idle: 0 },
{ id: 'r5', group: 'sg-old', lo: 0, hi: 65535, src: '10.0.0.0/8', note: 'vendor test', idle: 400 },
{ id: 'r6', group: 'sg-app', lo: 3000, hi: 3400, src: '0.0.0.0/0', note: 'dev tool', idle: 30 },
{ id: 'r7', group: 'sg-app', lo: 8080, hi: 8080, src: '10.0.1.25/32', note: 'old lb node', idle: 120 },
];
const isOpen = s => s === '0.0.0.0/0' || s === '::/0';
const covered = (map, r) => Object.keys(map).map(Number)
.filter(p => p >= r.lo && p <= r.hi).map(p => map[p]);
function audit(r) {
const found = [], admin = covered(ADMIN, r), db = covered(DB, r);
if (isOpen(r.src) && admin.length) found.push(['CRITICAL', `internet to admin port ${admin}`]);
if (isOpen(r.src) && db.length) found.push(['CRITICAL', `internet to database port ${db}`]);
if (r.hi - r.lo >= 1000) found.push(['HIGH', `wide port range ${r.lo}-${r.hi}`]);
if (r.src.endsWith('/32')) found.push(['MEDIUM', 'fixed IP, prefer a group reference']);
if (r.idle >= 90) found.push(['MEDIUM', `no traffic for ${r.idle} days`]);
if (!r.note) found.push(['LOW', 'no description']);
return found.map(([sev, msg]) => ({ sev, msg, id: r.id, group: r.group }));
}
const report = rules.flatMap(audit).sort((a, b) => RANK[a.sev] - RANK[b.sev]);
for (const f of report) console.log(f.sev.padEnd(9), f.id, f.group.padEnd(7), f.msg);
const clean = rules.filter(r => audit(r).length === 0).map(r => r.id);
console.log(`\n${report.length} findings, clean rules: ${clean.join(', ')}`);শেষ লাইনটি পড়ুন: 10 findings, clean rules: r1, r4. r1 হলো 443-এ public দরজা, আর r4 হলো group reference, দুটিই পরিষ্কার। অর্থাৎ 0.0.0.0/0 নিজে অপরাধী নয়, কোন port-এ বসেছে সেটিই আসল।
r6 দুটি CRITICAL পেল: internet to admin port RDP আর internet to database port MySQL. পরিসরের ভেতরে port লুকিয়ে ছিল, সরাসরি চোখে পড়ার কথা নয়। r3 ধরা পড়ল ::/0-এর জন্য, আর r7 পেল fixed IP, prefer a group reference.
একই কাজ pipeline-এ করা যায় ছোট একটি shell script দিয়ে। Provider-এর CLI থেকে নিয়মগুলো বের করে CSV বানানো গেলে নিচের awk অংশ ঝুঁকিপূর্ণ নিয়ম ধরবে। এখানে CSV block-এর ভেতরেই বানানো হয়েছে, তাই কোনো account লাগে না।
set -euo pipefail
export LC_ALL=C
cd "$(mktemp -d)"
cat > rules.csv <<'CSV'
group,direction,proto,from_port,to_port,source,description
sg-alb,in,tcp,443,443,0.0.0.0/0,public https
sg-bastion,in,tcp,22,22,0.0.0.0/0,temp admin access
sg-app,in,tcp,8080,8080,sg-alb,from load balancer
sg-app,in,tcp,22,22,sg-bastion,admin through bastion
sg-win,in,tcp,3389,3389,::/0,windows admin
sg-db,in,tcp,5432,5432,0.0.0.0/0,temp debug
sg-db,in,tcp,5432,5432,sg-app,from app
sg-old,in,tcp,0,65535,0.0.0.0/0,vendor test
sg-app,out,tcp,443,443,0.0.0.0/0,payment api
CSV
awk -F, '
BEGIN { split("22 3389 3306 5432 6379 27017", ports, " ") }
NR == 1 || $2 != "in" { next }
$6 != "0.0.0.0/0" && $6 != "::/0" { next }
{
found = ""
for (i = 1; i in ports; i++)
if (ports[i] + 0 >= $4 + 0 && ports[i] + 0 <= $5 + 0) found = found " " ports[i]
if (found != "") { print $1 ":" found " open to " $6 " (" $7 ")"; n++ }
}
END { print "risky rules: " n + 0 }
' rules.csv > report.txt
cat report.txt
echo "--- rules per group"
grep -v '^risky' report.txt | cut -d: -f1 | sort | uniq -c | sort -rnআউটপুটের শেষ সারাংশ risky rules: 4. ধরা পড়েছে sg-bastion: 22 open to 0.0.0.0/0 (temp admin access), sg-win: 3389 open to ::/0 (windows admin), sg-db: 5432 open to 0.0.0.0/0 (temp debug), আর sg-old-এর পুরো পরিসর, যেখানে ছয়টি port-ই ধরা পড়েছে: 22 3389 3306 5432 6379 27017.
বাদ গেছে sg-alb (443 তালিকায় নেই), sg-app-এর 22 (উৎস group, তাই পরিষ্কার) আর শেষের outbound নিয়ম ($2 != "in"). খেয়াল করুন, “temp” শব্দটি দুটি নিয়মে আছে। অস্থায়ী নিয়মই স্থায়ী ঝুঁকিতে পরিণত হয় সবচেয়ে বেশি।
৭ · নিয়মের সীমা, পরিষ্কার করা আর flow log দিয়ে যাচাই
নিয়মের সীমা
নিয়ম অসীম নয়, কারণ প্রতিটি packet-এ এগুলো মেলাতে হয়। AWS-এ লেখার সময়ে ডিফল্ট হিসাব মোটামুটি এরকম: এক group-এ প্রতি দিকে ৬০টি নিয়ম, এক interface-এ ৫টি group, এক NACL-এ প্রতি দিকে ২০টি নিয়ম। অর্থাৎ এক interface-এ সর্বোচ্চ ৫ × ৬০ = ৩০০টি নিয়ম। কিছু quota বাড়ানো যায়, আর সংখ্যা বদলাতে পারে। অন্য provider-এর হিসাব আলাদা, সেখানকার quota পাতা দেখুন। সীমায় ঠেকলে প্রায়ই সেটি নকশার গন্ধ: reference, prefix list বা নিয়ম একত্র করার সময় এসেছে।
পুরোনো নিয়ম পরিষ্কার করা
Firewall-এর নিয়ম সহজে বাড়ে, কমে না। কেউ “দুই দিনের জন্য” একটি নিয়ম খোলেন, তারপর ভুলে যান। মুছতে সবাই ভয় পান, কারণ জানেন না কে ব্যবহার করছে। প্রতিকার হলো অভ্যাস:
- প্রতিটি নিয়মে description আর owner tag রাখুন; অস্থায়ী নিয়মে মেয়াদের তারিখ।
- সব নিয়ম IaC-তে লিখুন, যাতে পরিবর্তন review হয় আর হাতে করা বদল drift হিসেবে ধরা পড়ে (পর্ব ৫১)।
- নিয়মিত সময়ে, ধরুন প্রতি ত্রৈমাসিকে, অডিট চালান। ৯০ দিন traffic না থাকলে owner-কে জিজ্ঞেস করুন।
- “Traffic নেই” প্রমাণ নয়। মাসে একবার চলা job বা disaster recovery-র পথ ৯০ দিন চুপ থাকতে পারে। তাই মোছার আগে যাচাই করুন, আর ফেরত আনার পথ তৈরি রাখুন।
Flow log: কী ঘটল তার হিসাব
Flow log হলো network interface দিয়ে কোন সংযোগ গেল আর কোনটি আটকাল, তার সারাংশ রেকর্ড। এতে ঠিকানা, port, packet সংখ্যা আর ফল থাকে, কিন্তু ডেটার ভেতরের লেখা থাকে না। নিচে AWS-এর ডিফল্ট format-এর দুটি নমুনা লাইন, হাতে লেখা, কোনো আসল account-এর নয়। শেষ দিকের ACCEPT বা REJECT খেয়াল করুন।
2 123456789012 eni-0abc1234example 203.0.113.7 10.0.1.20 51514 443 6 8 1120 1761800000 1761800060 ACCEPT OK
2 123456789012 eni-0abc1234example 10.0.1.20 203.0.113.7 443 51514 6 6 3400 1761800000 1761800060 REJECT OK
ক্রমটি হলো version, account, interface, source IP, destination IP, source port, destination port, protocol (6 মানে TCP), packet, byte, শুরু, শেষ, ফল আর log-এর অবস্থা। এই জোড়াটি পড়ে বলা যায়, অনুরোধ ঢুকেছে, উত্তর আটকেছে, অর্থাৎ অংশ ৪-এর সেই NACL ভুল। উল্টোটিও সত্য: inbound-এই REJECT মানে NACL বা security group, দুটির যেকোনো একটি হতে পারে। Log সাধারণত কয়েক মিনিট দেরিতে আসে, আর রাখতে storage-এর খরচ আছে। Azure আর Google-এ নাম ও format আলাদা, ধারণা এক। সরাসরি পথ যাচাইয়ে পর্ব ১৩-এর ss আর curl কাজে আসবে। আর কিছু traffic, যেমন provider-এর নিজস্ব DNS বা metadata ঠিকানায় যাওয়া, অনেক সময় log বা নিয়মের আওতার বাইরে থাকে।
খোলা database, চলমান দোকান: নিরাপদে কড়া করা
এখন আসল পরীক্ষা। আপনি দেখলেন sg-db-তে 5432 সবার জন্য খোলা, আর দোকান চলছে। সরাসরি মুছলে কোনো অজানা সার্ভিস বন্ধ হতে পারে। Allow নিয়ম যোগফলে কাজ করে, তাই ক্রমটি হলো: আগে নতুন সরু নিয়ম যোগ, যাচাই, তারপর পুরোনোটি বাদ।
| নিয়ম | |
| নতুন সংযোগ পারে | |
| দেখা গেছে | |
| দোকান |
- ঝুঁকি চিহ্নিত। অডিটরে
CRITICALএলো। এখনই কিছু মোছা হয়নি। আগে জানা দরকার কে এই পথ ব্যবহার করে। - Flow log পড়া।
5432-এ ACCEPT হওয়া উৎস:10.0.2.11আর10.0.2.12(app),10.0.5.9(report server), আর203.0.113.50, যাকে কেউ চেনেন না। এই শেষটিকে সম্ভাব্য incident হিসেবে আলাদা করে তদন্তে তুলুন। - আগে যোগ।
from sg-appআরfrom sg-reportযোগ হলো। Allow নিয়ম যোগফলে খাটে, তাই এতে কারও পথ বন্ধ হয় না। পুরোনো নিয়ম এখনো আছে, তাই এই ধাপে ঝুঁকি বাড়ে না, কমেও না। - যাচাই। App আর report server সত্যিই ওই group-এর সদস্য কি না মিলিয়ে নিন। সম্ভব হলে একটি instance বদলে নতুন সংযোগ পরীক্ষা করুন। Staging-এ মহড়া দেওয়া আরও ভালো।
- তারপর বাদ।
0.0.0.0/0আর::/0নিয়ম মুছলেন। AWS-এর নথি অনুযায়ী চলমান tracked সংযোগ সাধারণত সাথে সাথে কাটে না, তাই app-এর connection pool নির্বিঘ্নে চলে। এই আচরণ provider-ভেদে যাচাই করে নিন। ফেরত আনার কমান্ড হাতের কাছে রাখুন। - শেষ যাচাই আর দীর্ঘমেয়াদি কাজ। দোকান চলছে, public উৎস এখন REJECT. বাকি কাজ: database-এর public access বন্ধ, IaC-তে নিয়ম লেখা, আর অচেনা উৎসের জন্য database-এর log তদন্ত ও password বদল।
একই ধাপগুলো CLI-তে দেখতে এরকম (উদাহরণ, আইডি কাল্পনিক)। লক্ষ করুন, দ্বিতীয় লাইন প্রথমটির পরে এবং যাচাইয়ের পরেই চলবে।
# Step 3: add the narrow rule first
aws ec2 authorize-security-group-ingress --group-id sg-0db0000000example \
--protocol tcp --port 5432 --source-group sg-0a00000000example
# Step 5: only after checking, remove the wide rule
aws ec2 revoke-security-group-ingress --group-id sg-0db0000000example \
--protocol tcp --port 5432 --cidr 0.0.0.0/0৮ · Firewall একা নয় — স্তরে স্তরে নিরাপত্তা
Firewall ঠিক করে কে দরজা পর্যন্ত পৌঁছাবে। কে ভেতরে কী করবে, সেটি সে জানে না। একটি allow করা 443 সংযোগের ভেতর দিয়ে আসা খারাপ অনুরোধ security group দেখতে পায় না। তাই firewall প্রথম ও একমাত্র ভরসা নয়, এটি নিরাপত্তার একটি স্তর। একে বলে defense in depth: এক স্তর ব্যর্থ হলে পরেরটি ধরবে, যেমন গুদামঘরে গেটের তালা, ভেতরের ঘরের তালা আর সিন্দুকের তালা আলাদা। পূর্ণ ছবি পাবেন পর্ব ৩৪-এ, আর নকশার দিক System Design কোর্সে।
| স্তর | উদাহরণ | যা ধরে |
|---|---|---|
| Edge | CDN, WAF, DDoS সুরক্ষা (পর্ব ৩০) | খারাপ HTTP অনুরোধ, বন্যার মতো traffic |
| Subnet | NACL, route table (পর্ব ২৬) | মোটা দাগের সীমানা, ঠিকানা-পরিসর আটকানো |
| Interface | Security group | কে কোন port-এ আসতে পারে |
| Host | nftables, ufw, হালনাগাদ OS | Cloud নিয়ম ভুল হলেও দ্বিতীয় বাধা |
| পরিচয় | IAM, database login (পর্ব ৩১) | পৌঁছানো ব্যক্তি আসলে কে, কী করতে পারেন |
| ডেটা | TLS, এনক্রিপশন, backup | বাকি সব ভাঙলেও ক্ষতি সীমিত রাখা |
Managed network firewall
Security group five-tuple দেখে, domain name দেখে না। “App শুধু payments.example.com-এ যেতে পারবে” এমন নিয়ম এতে লেখা যায় না। এর জন্য আছে managed network firewall: AWS Network Firewall, Azure Firewall, Google Cloud-এর Cloud NGFW. এগুলো traffic-এর পথের মাঝে বসে domain-ভিত্তিক outbound নিয়ম, অনুপ্রবেশ শনাক্তকরণ আর কেন্দ্রীয় নীতি দেয়। দাম হলো route বদল (পর্ব ২৬), আলাদা খরচ আর বাড়তি latency. দাম ঘণ্টা ও ডেটার হিসাবে আসে, provider-এর দামের পাতা দেখে তবেই সিদ্ধান্ত নিন। ছোট দোকানে সাধারণত দরকার নেই, নিয়ন্ত্রিত শিল্পে বা অনেক VPC-তে কাজে লাগে। Kubernetes-এর ভেতরে এই কাজের সমতুল্য NetworkPolicy (পর্ব ৪৯), আর container network-এর ভিত্তি আছে এই পর্বে।
আরও গভীরে: Tracking table সীমাহীন নয়। AWS instance type অনুযায়ী tracked সংযোগের সীমা আছে, আর সীমা পার হলে packet পড়ে যায়, যা খুব ব্যস্ত load-এ রহস্যময় লাগে। আবার কিছু খুব খোলা নিয়মে (দুই দিকেই সব উৎস ও সব port) AWS-এ সংযোগ track না-ও হতে পারে। NACL-এর আরেকটি লুকানো ফাঁদ হলো Path MTU Discovery: বড় packet-এর জন্য দরকারি ICMP “fragmentation needed” বার্তা আটকে দিলে ছোট অনুরোধ চলে, বড় উত্তর ঝুলে থাকে। RFC 6056 (২০১১) ephemeral port বেছে নেওয়ার কৌশল আলোচনা করে, আর RFC 6335 (২০১১) 49152-65535 পরিসর নির্ধারণ করে।
পরীক্ষা ও ইন্টারভিউতে:
- Security group আর NACL-এর পার্থক্য? Group stateful, interface-স্তরে, শুধু allow; NACL stateless, subnet-স্তরে, ক্রমে allow ও deny.
- একটি IP আটকাবেন কীভাবে? AWS-এ security group-এ deny নেই, তাই NACL-এ ছোট নম্বরের deny বা WAF.
- Inbound
443খোলা, তবু সাইট timeout? NACL-এ ephemeral port-এর outbound নিয়ম আছে কি না দেখুন; route আর host firewall-ও। - Autoscaling-এ DB-র নিয়ম কী হবে? উৎস হবে app-এর security group, IP নয়।
- Connection timeout বনাম connection refused? Timeout মানে পথে packet হারাচ্ছে, প্রায়ই firewall. Refused মানে server পৌঁছানো গেছে, কিন্তু port-এ কেউ শুনছে না।
৯ · AI-এর যুগে firewall-এর নিয়ম
“সংযোগ হচ্ছে না” বললে AI-এর সবচেয়ে সহজ উত্তর হলো 0.0.0.0/0, কারণ তাতে সমস্যাটি সাথে সাথে চলে যায়। সমস্যা যায়, ঝুঁকি থেকে যায়। AI আপনার নেটওয়ার্ক দেখতে পায় না, তাই নিয়ম পড়ে যাচাই করার দায়িত্ব আপনার।
| AI-এর ভুল | ফল | যাচাই |
|---|---|---|
Debug করতে সব port 0.0.0.0/0 | Database internet-এ খোলা | Plan-এ প্রতিটি উৎস পড়ুন, অডিটর চালান |
| Security group-এ ephemeral port-এর নিয়ম | অকারণে হাজার port খোলা | Stateful-এ উত্তরের নিয়ম লাগে না |
| NACL-এ ফিরতি নিয়ম বাদ | চুপচাপ timeout | দুই দিকের নিয়ম আলাদা মিলিয়ে দেখুন |
0.0.0.0/0 মুছে ::/0 রেখে দেওয়া | IPv6-এ দরজা খোলা | দুই address family-ই খুঁজুন |
| Reference-এর বদলে স্থির IP | Autoscaling-এ নিয়ম পুরোনো | IP দেখলেই কারণ জিজ্ঞেস করুন |
| নেই এমন flag বা argument | কমান্ড ব্যর্থ বা ভিন্ন আচরণ | Official docs, terraform plan, --dry-run |
| পুরোনো নিয়ম আগে মুছে দেওয়া | Downtime | আগে যোগ, পরে বাদ |
AI-কে সমস্যার সাথে সীমাও বলে দিন। শেষ দুটি লাইন সবচেয়ে কাজের। মনে রাখবেন, আসল আইডি, account নম্বর বা secret কখনো প্রম্পটে দেবেন না।
AI-এর দেওয়া নিয়ম হাতে পেলে — চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন — তারপর “→ উত্তর” চাপুন।
প্র ০১Stateful firewall তো স্পষ্টতই সুবিধাজনক। তাহলে cloud-এ stateless NACL এখনো টিকে আছে কেন?
ইতিহাসটি আগে দেখি। ১৯৮০-র দশকের শেষে আসা প্রথম firewall ছিল সরল packet filter. Jeffrey Mogul-এর DEC-এর কাজ (১৯৮৯) এই ধারার পরিচিত উদাহরণ। প্রতিটি packet আলাদা বিচার হতো, ঠিক আজকের NACL-এর মতো। সমস্যা ছিল ফিরতি পথ: ক্লায়েন্টের port-এর জন্য বিশাল পরিসর খুলে রাখতে হতো। ১৯৯০-এর দশকের শুরুতে Check Point-এর FireWall-1 “stateful inspection” ধারণাটি জনপ্রিয় করে, যেখানে সংযোগের অবস্থা মনে রাখা হয়। ফলে পরিসর খোলার দরকার কমে যায়।
তাহলে পুরোনো নকশা টিকল কেন? কারণ স্মৃতির দাম আছে। প্রতিটি সংযোগের জন্য table-এ জায়গা লাগে, মিলিয়ে দেখতে সময় লাগে, আর table ভরে গেলে packet পড়ে যায়। Stateless পরীক্ষায় কোনো table নেই, তাই খরচ স্থির। প্রবল traffic-এর সময় এই গুণটি কাজে লাগে, আর কোনো খারাপ ঠিকানা-পরিসর আটকাতে স্মৃতির দরকারই নেই।
দ্বিতীয় কারণ দায়িত্বের বিভাজন। Security group থাকে VM-এর সাথে, অনেক সময় অ্যাপ দল সেটি সামলায়। NACL থাকে subnet-এর সাথে, তাই নেটওয়ার্ক বা নিরাপত্তা দল একটি মোটা সীমা টানতে পারে, যা অ্যাপ দলের ভুলে ভাঙে না। তৃতীয়ত, deny দরকার হলে AWS-এ NACL-ই সহজ পথ।
তবে Azure আর Google এই দুই স্তর আলাদা করে দেয়নি, দুটিই একটি stateful মডেলে এনেছে। অর্থাৎ NACL কোনো প্রাকৃতিক নিয়ম নয়, একটি নকশার সিদ্ধান্ত। নতুন cloud-এ এলে তাই আগে জেনে নিন, সেখানে কোন স্তর স্মৃতি রাখে আর কোনটি রাখে না।
মূল উপলব্ধি: স্মৃতি সুবিধা দেয়, কিন্তু খরচ আর ব্যর্থতার নতুন পথও আনে। প্রতিটি “পুরোনো” প্রযুক্তি টিকে থাকলে ধরে নিন, সে কোনো একটি দামে এখনো সস্তা।
প্র ০২Security group-এ deny নেই — এটি কি দুর্বলতা, নাকি ইচ্ছাকৃত নকশা?
প্রথম দেখায় দুর্বলতা মনে হয়। একটি খারাপ IP আটকাতে পারি না কেন? কিন্তু উল্টো দিক থেকে ভাবুন। শুধু allow থাকলে নিয়মের ফল হলো সব allow-এর যোগফল। নতুন নিয়ম কেবল পথ বাড়ায়, কোনো পুরোনো পথ বন্ধ করে না। ক্রম নিয়ে ভাবতে হয় না, আর দুটি নিয়মের মধ্যে সংঘর্ষ হয় না। একটি প্রশ্নের উত্তর সহজে বলা যায়: এই packet কি যাবে? যেকোনো একটি allow মিললেই যাবে।
যেখানে deny আর ক্রম আছে, সেখানে জটিলতা বাড়ে। একটি নিয়মের অর্থ নির্ভর করে তার আগের সব নিয়মের ওপর। বড় firewall-এ এটি বাস্তব সমস্যা: Avishai Wool-এর ২০০৪ সালের একটি পরিচিত গবেষণা (IEEE Computer) দেখিয়েছিল, প্রতিষ্ঠানের firewall-এ configuration ভুল খুবই সাধারণ, আর নিয়ম যত বেশি, ভুল তত বেশি। Shadowing সেই ভুলগুলোর একটি।
একই সাথে, allow-only মডেলের সীমাও আসল। “সবাই পাবে, শুধু এরা ছাড়া” এটি প্রকাশ করা যায় না। আর একটি দল ভুল করে খোলা নিয়ম দিলে কেন্দ্রীয় নিরাপত্তা দল সেখানে “এর ওপরে কিছু চলবে না” বলতে পারে না। এজন্য বড় প্রতিষ্ঠানে আলাদা স্তর লাগে: Azure-এর deny নিয়ম ও Google-এর hierarchical firewall policy এই কাজটি করে, AWS-এ NACL বা Firewall Manager-এর মতো ব্যবস্থা নেওয়া হয়।
আরেকটি বড় কথা: deny-list নিরাপত্তার দুর্বল ভিত্তি। আপনি কেবল জানা খারাপ ঠিকানা আটকাতে পারেন, আর আক্রমণকারীর ঠিকানা বদলায়। Default deny আর ছোট allow-list উল্টো দিক থেকে ভাবে: অজানা সবকিছুই বন্ধ।
মূল উপলব্ধি: ভালো নিরাপত্তা নকশা শুধু শক্তিশালী নয়, সহজে যাচাইযোগ্যও। যে নিয়ম মানুষ পড়ে বুঝতে পারে না, সেটি কাগজে শক্তিশালী হলেও বাস্তবে দুর্বল।
প্র ০৩আমার database-এর password খুব শক্ত। তাহলে 5432 internet-এ খোলা রাখলে সমস্যা কী?
Password শুধু একটি ঝুঁকি ঠেকায়, ভুল login. কিন্তু খোলা port আরও অনেক কিছু উন্মুক্ত করে। Login-এর আগের কোডও চলে, সেখানে কোনো ত্রুটি থাকলে password কাজে আসে না। ইতিহাস এটি বারবার দেখিয়েছে।
জানুয়ারি ২০০৩-এ Slammer worm Microsoft SQL Server-এর একটি buffer overflow কাজে লাগিয়ে ছড়ায়, UDP port 1434-এ একটি মাত্র packet-এ। Moore ও সহলেখকদের বিশ্লেষণ অনুযায়ী, প্রায় ১০ মিনিটের মধ্যে ঝুঁকিতে থাকা host-এর বড় অংশ আক্রান্ত হয়। সেখানে password-এর কোনো ভূমিকাই ছিল না। আর ২০১৯-এর BlueKeep দেখিয়েছে, RDP-তেও login ছাড়াই ঝুঁকি থাকতে পারে।
দ্বিতীয় বিষয় হলো খুঁজে পাওয়ার গতি। Internet-কে “বিশাল, কেউ আমাকে খুঁজে পাবে না” ভাবা ভুল। ২০১৩ সালে প্রকাশিত ZMap গবেষণা (Durumeric ও সহলেখক, USENIX Security) দেখিয়েছিল, একটি সাধারণ যন্ত্র দিয়েই পুরো IPv4-এর একটি port ৪৫ মিনিটের কম সময়ে স্ক্যান করা যায়। Shodan-এর মতো সার্চ ইঞ্জিন এমন তথ্য নিয়মিত সূচিবদ্ধ করে। তাই খোলা port প্রকাশের ঘণ্টা বা মিনিটের মধ্যেই চোখে পড়ে ধরে নিতে হয়।
তৃতীয়ত, ভুল আসলে আসে সেটিংয়ে। ২০১৭-র শুরুতে নিরাপত্তা গবেষকরা জানান, internet-এ খোলা, login-বিহীন বহু হাজার MongoDB server-এর ডেটা মুছে মুক্তিপণ চাওয়া হচ্ছে। Default সেটিং, ভুলে যাওয়া test server আর পুরোনো সংস্করণ, সবই বাস্তব।
তাই firewall শুধু পথ আটকায় না, আক্রমণের উপরিতল (attack surface) ছোট করে। পৌঁছাতেই না পারলে অজানা ত্রুটিও কাজে লাগানো কঠিন হয়। আর database login-ও থাকবে, কারণ স্তর একটির বদলে আরেকটি নয়।
মূল উপলব্ধি: “কেউ login করতে পারবে না” আর “কেউ পৌঁছাতে পারবে না” দুটি আলাদা নিশ্চয়তা। ভালো নকশা দুটিই চায়, কারণ প্রতিটির ব্যর্থতার ধরন আলাদা।
প্র ০৪Zero trust বলে network-কে বিশ্বাস করা যাবে না। তাহলে security group নিয়ে এত পরিশ্রম কেন?
পুরোনো পৃথিবীতে নিরাপত্তা ছিল দুর্গের মতো: বাইরে দেয়াল, ভেতরে সবাই বিশ্বস্ত। সমস্যা হলো, একজন দেয়াল পেরোলেই ভেতরে অবাধে ঘুরতে পারে। Forrester-এর John Kindervag ২০১০ সালের দিকে “zero trust” শব্দটি জনপ্রিয় করেন। Google ২০১৪ সালে BeyondCorp নকশা প্রকাশ করে, যেখানে অফিসের network-এ থাকা কোনো বিশেষ অধিকার দেয় না। NIST SP 800-207 (২০২০) এই ধারণাকে একটি মান দেয়: প্রতিটি অনুরোধ পরিচয় দিয়ে যাচাই হবে, অবস্থান দিয়ে নয়।
এর মানে কি firewall অপ্রয়োজনীয়? না। Zero trust বলে, network-এর অবস্থানকে পরিচয়ের প্রমাণ হিসেবে নেবেন না। সে বলে না, সবাইকে সব port-এ পৌঁছাতে দিন। Security group তিনটি কাজ করে, যা পরিচয় যাচাই করতে পারে না।
- আক্রমণের উপরিতল ছোট করা: Login কোডের আগেই packet থামে।
- ক্ষতির ব্যাসার্ধ সীমিত করা: একটি app হাতছাড়া হলে সে শুধু তার অনুমোদিত পথেই যেতে পারে। একে অনেক সময় micro-segmentation বলা হয়।
- ভুলের বিরুদ্ধে দ্বিতীয় স্তর: কেউ ভুলে কোনো admin panel চালু রাখলেও firewall সেটি বাইরে থেকে আড়াল রাখে।
একই সাথে, উল্টো ভুলটিও বিপজ্জনক। from sg-app মানে “ওই group-এর ঠিকানা থেকে এসেছে”, “বিশ্বস্ত ব্যক্তি” নয়। তাই service-এর মধ্যে mutual TLS, স্বল্পমেয়াদি credential আর IAM লাগে (পর্ব ৩১)। দুটি মিলেই পূর্ণ ছবি।
বাংলাদেশের প্রেক্ষাপটে ছোট দলের জন্য পুরো zero trust বড় প্রকল্প মনে হতে পারে। সেখানে ভালো শুরু হলো default deny, group reference আর admin port বন্ধ করা। এগুলো সস্তা, আর ঝুঁকির বড় অংশ কমায়।
মূল উপলব্ধি: Zero trust firewall বাদ দিতে বলে না, firewall-কে একমাত্র ভরসা বানাতে নিষেধ করে। পথ সরু করা আর পরিচয় যাচাই একে অন্যের বিকল্প নয়।
প্র ০৫একটি নিয়মে ৯০ দিন কোনো traffic নেই। এটি কি নিরাপদে মুছে ফেলা যায়?
লোভনীয় উত্তর “হ্যাঁ”, কিন্তু সঠিক উত্তর “আগে খোঁজ নিন”। ধরুন একটি কাল্পনিক অনলাইন বাজার অ্যাপের একটি নিয়ম বছরে একবার চলে: হিসাব বন্ধের রাতে একটি report server database-এ যায়। আরেকটি নিয়ম শুধু disaster recovery-র সময় লাগে। ৯০ দিনের নীরবতা দেখে মুছলে সমস্যা ধরা পড়বে ঠিক সবচেয়ে খারাপ দিনটিতে। আবার না মুছলে অপ্রয়োজনীয় খোলা পথ জমতে থাকে। দুটিই খরচ, তাই পদ্ধতি লাগে।
প্রথমত, তথ্যের সীমা বুঝুন। Flow log ঠিকানা বলে, উদ্দেশ্য বলে না। AWS-এ log সাধারণত বলে না কোন নিয়মটি মিলেছে, তাই একই port-এর দুটি নিয়মের কোনটি ব্যবহার হচ্ছে তা অনুমান করতে হয়। Log না রাখা সময়ের কথা তো জানাই যায় না।
দ্বিতীয়ত, ঝুঁকি অনুযায়ী ভাগ করুন। 0.0.0.0/0-এ admin port হলে অপেক্ষা নয়, সাথে সাথে সরু করুন, যাচাইসহ। ভেতরের একটি group reference হলে তাড়া কম, owner-কে জিজ্ঞেস করার সময় আছে।
তৃতীয়ত, প্রক্রিয়া বানান। প্রতিটি নিয়মে owner আর কারণ রাখুন। Owner না পাওয়া গেলে নিয়মটি পরিষ্কারের তালিকায় যায়। মুছুন IaC-র মাধ্যমে, যাতে একটি commit revert করলেই নিয়ম ফেরে। অস্থায়ী নিয়ম মেয়াদসহ তৈরি করুন। আর নতুন পথ যাচাই করতে provider-এর পথ-বিশ্লেষণ সেবা ব্যবহার করতে পারেন, যেমন AWS Reachability Analyzer, Azure Network Watcher বা Google Connectivity Tests. এগুলো packet না পাঠিয়েই configuration পড়ে বলতে পারে পথ খোলা কি না।
চতুর্থত, মহড়া দিন। DR মহড়া নিয়মিত চালালে সেই পথের traffic-ও log-এ আসে, আর নিয়মের প্রয়োজন প্রমাণিত থাকে।
মূল উপলব্ধি: নিরাপত্তা পরিষ্কার মানে শুধু মোছা নয়, প্রতিটি নিয়মের মালিক ও কারণ জানা। যে নিয়মের কারণ কেউ বলতে পারেন না, সেটি নিজেই একটি ঝুঁকি।
অনুশীলন
কোনো cloud account লাগবে না। কাগজ, কলম আর পাতার সিমুলেটরই যথেষ্ট।
-
হিসাব: (ক)
10.0.0.0/16-এ কয়টি ঠিকানা? (খ) ২৫টি app instance, প্রতিটির তিনটি port; IP-এর তালিকায় কয়টি নিয়ম লাগবে, আর reference-এ কয়টি? সীমা ৬০ ধরলে কী হবে? (গ) একজন NACL-এ outbound32768-60999দিলেন। Windows ক্লায়েন্টের port49152-65535পরিসরে সমানভাবে ছড়ানো ধরলে কত শতাংশ সংযোগ ব্যর্থ হবে?(ক) ২১৬ = ৬৫,৫৩৬টি ঠিকানা।
(খ) ২৫ × ৩ = ৭৫টি নিয়ম, যা ৬০-এর সীমা ছাড়িয়ে যায়। Reference-এ লাগে ৩টি।
(গ) নিয়মের বাইরে পড়া port হলো
61000-65535, মোট ৬৫,৫৩৫ − ৬১,০০০ + ১ = ৪,৫৩৬টি। ক্লায়েন্টের মোট port ১৬,৩৮৪টি। ৪,৫৩৬ ÷ ১৬,৩৮৪ ≈ ০.২৭৭, অর্থাৎ প্রায় ২৮%. এটি সবচেয়ে খারাপ ধরনের সমস্যা, কারণ চারবারে একবারের বেশি ব্যর্থ, বাকিগুলো ঠিক চলে। তাই “মাঝে মাঝে সংযোগ হয় না” শুনলে NACL-এর পরিসরও সন্দেহের তালিকায় রাখুন। -
ফল অনুমান করুন: একটি NACL-এর inbound নিয়ম: ৮০ allow
203.0.113.5/32TCP443; ৯০ deny203.0.113.0/24সব port; ১০০ allow0.0.0.0/0TCP443;*deny. এই চারটি packet-এর ফল কী হবে: (১)203.0.113.5:443(২)203.0.113.6:443(৩)198.51.100.1:443(৪)198.51.100.1:22? প্রতিটি ঠিকানা উৎস, port গন্তব্যের। উত্তর মিলিয়ে দেখতেnacl_order.js-এ নিয়মগুলো বসিয়ে চালাতে পারেন।(১) ৮০-তে মিলল: ALLOW. (২) ৮০ মিলল না, ৯০-এ মিলল: DENY. (৩) ৮০ ও ৯০ মিলল না, ১০০-তে মিলল: ALLOW. (৪) কিছুই মিলল না,
*: DENY. লক্ষ করুন, একটি পরিসর আটকে তার ভেতরের একটি ঠিকানা ছাড় দিতে ছাড়ের নিয়মটি ছোট নম্বরে বসাতে হয়েছে। -
সমালোচনা ও নকশা: AI একটি দোকানের জন্য এই নিয়ম দিল:
sg-appinbound সব TCP0.0.0.0/0;sg-dbinbound54320.0.0.0/0; SSH220.0.0.0/0; সব নিয়মে description ফাঁকা। কারণ দেখিয়েছে “সংযোগ সমস্যা হবে না”। কী কী ভুল? আপনার সংশোধিত নকশা কী?ভুল: App সরাসরি internet-এ খোলা, load balancer এড়িয়ে যাওয়া যায়। Database পুরো internet-এ খোলা। SSH খোলা। সব port খোলা থাকায় ভুলে চালু থাকা যেকোনো service দৃশ্যমান। Description নেই, তাই পরে কেউ বুঝবেন না কেন আছে।
সংশোধন:
sg-alb: in443from0.0.0.0/0.sg-app: in8080fromsg-alb.sg-db: in5432fromsg-app. Admin প্রবেশ session manager বা22 from sg-bastion. Database আর app private subnet-এ। প্রতিটি নিয়মে description আর owner. আর “সংযোগ সমস্যা” দেখা দিলে flow log দিয়ে আসল কারণ খুঁজুন, নিয়ম চওড়া করে নয়। -
কমান্ডের কাজ:
audit_rules.sh-এ SQL Server-এর port1433যোগ করুন। আউটপুটে কী বদলাবে? আর ঝুঁকিপূর্ণ নিয়ম পেলে CI job ব্যর্থ করতে script-এর শেষে কী যোগ করবেন?split-এর তালিকায়1433যোগ করলে শুধুsg-old-এর লাইন বদলাবে:sg-old: 22 3389 3306 5432 6379 27017 1433 open to 0.0.0.0/0 (vendor test). কারণ0-65535পরিসরে1433পড়ে, আর অন্য কোনো নিয়মে পড়ে না।risky rules: 4একই থাকবে, কারণ গোনা হয় নিয়ম, port নয়।CI-এর জন্য শেষে একটি লাইন যথেষ্ট (উদাহরণ):
grep -qx 'risky rules: 0' report.txt || exit 1এতে ঝুঁকিপূর্ণ নিয়ম থাকলে script অশূন্য exit status দেবে, আর pipeline থেমে যাবে।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমAWS-এ একটি subnet-এর VM-এ আসা HTTPS অনুরোধ আর তার উত্তরের পথ সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- Network ACL-এর inbound নিয়ম
- Security group-এর inbound নিয়ম, connection tracking-এ লেখা
- VM-এর প্রোগ্রাম অনুরোধ পেয়ে উত্তর তৈরি করে
- Security group-এ tracking table মিলিয়ে উত্তর ছাড়া
- Network ACL-এর outbound নিয়মে ephemeral port মেলানো
একটি AWS security group-এ inbound TCP 443 allow আছে, আর outbound-এ কোনো নিয়ম নেই। একজন ক্লায়েন্ট 443-এ অনুরোধ পাঠালে server-এর উত্তরের কী হবে?
- আটকে যাবে, কারণ outbound নিয়ম নেই
- ফিরে যাবে, কারণ connection tracking সংযোগটি মনে রেখেছে
- ফিরবে শুধু ephemeral port-এর outbound নিয়ম থাকলে
- ফিরবে শুধু outbound 443 থাকলে
একটি NACL-এর inbound নিয়ম: ১০০ allow 0.0.0.0/0 TCP 443; ২০০ deny 198.51.100.0/24 সব port; * deny. 198.51.100.9 থেকে 443-এ packet এলে কী হবে?
- Allow হবে, কারণ ১০০ নম্বর আগে মিলেছে
- Deny হবে, কারণ deny সব সময় allow-এর চেয়ে শক্তিশালী
- Deny হবে, কারণ বড় নম্বর আগে পড়া হয়
- Deny হবে শেষের * নিয়মে
একটি web server-এ সাইট লোড হচ্ছে না, ব্রাউজারে timeout. Flow log-এ একই সংযোগে inbound ACCEPT আর outbound REJECT দেখা গেল। সবচেয়ে সম্ভাব্য কারণ কোনটি?
- Server-এ nginx চলছে না
- Security group-এ outbound নিয়ম নেই
- NACL-এ ephemeral port-এর outbound নিয়ম নেই
- TLS certificate-এর মেয়াদ শেষ
App স্তরে autoscaling-এ ৩ থেকে ২০টি instance চলে। Database-এর security group-এ inbound নিয়মের উৎস কী হওয়া উচিত?
0.0.0.0/0- App স্তরের security group
- প্রতিটি instance-এর IP আলাদা নিয়মে
10.0.0.0/8
একটি চলমান সিস্টেমে database-এর 5432 নিয়ম 0.0.0.0/0 থেকে সরিয়ে শুধু app-এর group করতে হবে। Downtime ছাড়া সঠিক ক্রম কোনটি?
- আগে পুরোনো নিয়ম মুছে তারপর নতুন নিয়ম যোগ
- পুরোনো নিয়ম মুছে flow log দেখা, সমস্যা হলে ফেরানো
- Database বন্ধ করে নিয়ম বদলে আবার চালু
- Flow log দেখে নতুন নিয়ম যোগ, যাচাই, তারপর পুরোনো নিয়ম বাদ
AWS security group থেকে Azure NSG-তে এলে কোন পার্থক্যটি সবচেয়ে গুরুত্বপূর্ণ?
- NSG stateless, তাই ফিরতি নিয়ম লিখতে হয়
- NSG-তে deny আছে, আর নিয়ম priority-র ক্রমে পড়া হয়
- NSG শুধু subnet-এ লাগানো যায়
- NSG-তে port দিয়ে নিয়ম লেখা যায় না
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন — অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- Security group interface-এ বসে, stateful, শুধু allow, ক্রম নেই। NACL subnet-এ বসে, stateless, ছোট নম্বর আগে, প্রথম মিলই শেষ কথা।
- Inbound-এ পথ NACL → SG, outbound-এ SG → NACL. NACL-এ উত্তরের জন্য
1024-65535লাগে। - উৎসে IP নয়, group reference. প্রতিটি স্তর শুধু আগের স্তরকে চেনে।
0.0.0.0/0আর::/0শুধু public দরজায়। SSH, RDP, database-এ নয়, পরিসরের ভেতরেও নয়।- নিয়ম কড়া করতে আগে যোগ, পরে বাদ; যাচাই করুন flow log দিয়ে। Firewall একটি স্তর, পরিচয় ও এনক্রিপশনের বিকল্প নয়।
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ২৮ · VPC জোড়া — peering, transit, VPN, dedicated link আর private endpointপরবর্তী পর্বএকাধিক network-কে নিরাপদে যুক্ত করা।
- ক্লাউড কম্পিউটিং ও DevOps · কোর্স হোম৮১টি পর্বপুরো কোর্সের রোডম্যাপ।
- পর্ব ১২ · SSH আর দূরের serverসম্পর্কিতBastion আর session manager দিয়ে admin প্রবেশ।
- Computer Networks · Firewall ও VPNগভীরে যানFirewall-এর তত্ত্ব আর নেটওয়ার্কের ভিত্তি।
- System Design · নিরাপত্তার নকশাপাশের ট্র্যাকপুরো সিস্টেমের স্তরে নিরাপত্তা ভাবা।