এই পর্বে যা শিখবেন
- Server-এ Linux কেন, কোন distribution কখন, আর LTS মানে কী
- Filesystem-এর মানচিত্র দেখে বলতে পারা, কোন ফাইল কোথায় থাকবে আর কোনটির backup লাগবে
- User, group, root, sudo আর service account দিয়ে ক্ষমতা ভাগ করা
chmod,chown,umaskহাতে হিসাব করা, আর kernel-এর সিদ্ধান্ত অনুসরণ করাaptওdnf-এর ভেতরের পথ, disk-এর প্রাথমিক সমস্যা ধরা, আর নতুন server শক্ত করার চেকলিস্ট
১ · Server-এ কেন Linux, আর কোন Linux
আগের পর্ব DevOps আর SRE-তে দেখেছেন, যে দল software বানায়, চালানোর দায়ও তার। চালাতে হলে যন্ত্রটি চিনতে হবে। Cloud-এ যে virtual machine ভাড়া নেবেন, container চালাবেন, Kubernetes-এর যে node দেখবেন, তার বেশিরভাগের ভেতরে Linux. তাই মডিউল ২ শুরু হচ্ছে এখান থেকে।
Linux কেন? কারণগুলো ব্যবহারিক:
- প্রতি server-এ লাইসেন্স ফি নেই। একশো VM চালালেও OS-এর জন্য আলাদা ফি দিতে হয় না (RHEL-এর মতো সাবস্ক্রিপশন distribution বাদে)।
- সবকিছু লেখায়। Config সাধারণ text ফাইল, কাজ কমান্ডে। Text ফাইল git-এ রাখা যায়, কমান্ড script-এ বসানো যায়। Automation-এর জন্য এর চেয়ে ভালো ভিত্তি কমই আছে।
- স্ক্রিন লাগে না। দূর থেকে SSH দিয়ে চালানো হয়। Graphical desktop না থাকায় মেমরি আর CPU বাঁচে।
- Container-এর ভিত্তি। Container চলে Linux kernel-এর namespace আর cgroup সুবিধার ওপর। পর্ব ৩৬-এ এর ব্যবহার দেখবেন।
এর মানে এই নয় যে অন্য OS খারাপ। Windows Server সব বড় cloud-এ পাওয়া যায়, আর .NET Framework বা Active Directory-নির্ভর কাজে সেটিই ঠিক পছন্দ। তবে এই কোর্সের বেশিরভাগ tool Linux-কেন্দ্রিক।
১৯৯১ সালে Linus Torvalds একটি kernel প্রকাশ করেন। GNU প্রকল্পের tool-গুলোর সাথে মিলে সেটি একটি পূর্ণ OS হয়ে ওঠে। ১৯৯৩ সালে Ian Murdock শুরু করেন Debian, প্রায় একই সময়ে আসে Red Hat, আর ২০০৪ সালে Debian-এর ভিত্তিতে আসে Ubuntu. আজকের প্রায় সব server distribution এই ধারাগুলোরই কোনো একটির বংশধর।
Distribution — একই kernel, আলাদা সংসার
“Linux” শব্দটি কঠোর অর্থে শুধু kernel. আপনি যা install করেন, সেটি distribution বা distro: kernel, মৌলিক tool, package manager, আর একদল মানুষের নেওয়া সিদ্ধান্ত। অনেকটা একই চালের ভাত, কিন্তু আলাদা হোটেলের আলাদা রান্না আর আলাদা মেনু।
| পরিবার | Package | কোথায় বেশি দেখবেন | যা মনে রাখবেন |
|---|---|---|---|
| Debian | apt, .deb | সাধারণ server, container base image | সম্প্রদায়-চালিত, রক্ষণশীল ও স্থিতিশীল |
| Ubuntu LTS | apt, .deb | Cloud VM, শেখার পরিবেশ | Debian থেকে এসেছে; দুই বছর পরপর নতুন LTS |
| RHEL পরিবার (RHEL, Rocky, AlmaLinux) | dnf, .rpm | Enterprise, ব্যাংকের মতো নিয়ন্ত্রিত পরিবেশ | খুব দীর্ঘ support; RHEL-এ সাবস্ক্রিপশন লাগে |
| Alpine | apk | Container image | খুব ছোট; musl libc ব্যবহার করে, তাই কিছু software-এ আলাদা আচরণ |
| Provider-এর নিজস্ব (Amazon Linux, Azure Linux ইত্যাদি) | লেখার সময়ে Amazon Linux-এ dnf, .rpm | নিজ নিজ cloud-এ | সেই cloud-এর জন্য সাজানো; অন্য জায়গায় নেওয়া কঠিন হতে পারে |
এখানকার প্রতিটি সময়সীমা বদলাতে পারে, তাই সিদ্ধান্তের আগে distribution-এর নিজের lifecycle পাতা দেখে নিন।
LTS — আসল পণ্য হলো সময়
LTS (Long Term Support) মানে নির্মাতা একটি নির্দিষ্ট release-এ বহু বছর নিরাপত্তা-সংশোধন দেওয়ার প্রতিশ্রুতি দেন। Ubuntu LTS-এ লেখার সময়ে সাধারণ support প্রায় পাঁচ বছর, আর RHEL পরিবারে প্রায় দশ বছর। এই সময়ে software-এর বড় version বদলায় না, কেবল ত্রুটি সংশোধন আসে। ফলে আপনার app হঠাৎ ভেঙে পড়ে না।
উল্টো পথটির নাম rolling release: সবসময় নতুন version, কিন্তু প্রায়ই বদল। Server-এ সাধারণত LTS-ই পছন্দ, কারণ এখানে নতুনত্বের চেয়ে পূর্বানুমেয়তা দামি।
একটি ফাঁদ: LTS-এ সংশোধনগুলো পুরোনো version-এই বসানো হয়, একে বলে backport. তাই 1.24.0-2ubuntu7.1-এর মতো version নম্বর দেখতে পুরোনো হলেও ভেতরের ত্রুটি হয়তো সংশোধিত। শুধু version নম্বর দেখে “এই server অনিরাপদ” বলা যায় না। মূল version-এর পরের অংশটি (যেখানে distribution-এর সংশোধনের হিসাব থাকে) আর distribution-এর নিরাপত্তা বিজ্ঞপ্তি দেখতে হয়। উল্টোটিও সত্য: support-এর মেয়াদ (end of life) শেষ হলে আর কোনো সংশোধন আসে না।
২ · Filesystem-এর মানচিত্র — কোন জিনিস কোথায়
একটি বড় গুদামঘরের কথা ভাবুন। প্রতিটি মালের নির্দিষ্ট তাক আছে, তাই নতুন কর্মী এসেও জিনিস খুঁজে পান। Linux-এও একই ব্যবস্থা। Windows-এর মতো C: D: নেই। সবকিছু একটি গাছের ভেতরে, যার গোড়া /. কোন ধরনের ফাইল কোথায় থাকবে, তার মান হলো Filesystem Hierarchy Standard (FHS). Distribution-গুলো এটি মোটামুটি মেনে চলে, সামান্য পার্থক্যও আছে।
Server-এর filesystem — কী কোথায়, আর backup লাগবে কি না
Filesystem tree with what lives where
/var/log আর /var/lib দুটিই /var-এর ভেতরে।এই মানচিত্র মুখস্থের বিষয় নয়, কাজের বিষয়। Server-এ সমস্যা হলে প্রশ্নগুলো এই ক্রমেই আসে:
- Config কোথায়?
/etc/nginx/বা/etc/ssh/. এখানকার ফাইল বদলালে আচরণ বদলায়, তাই এগুলো Git বা IaC-তে রাখা ভালো। - Log কোথায়?
/var/log/আর systemd-এর journal. পর্ব ১১-তেjournalctlদেখবেন। - Disk কে ভরাল? প্রায়ই
/var/logবা/var/lib, যেমন database বা Docker-এর ডেটা। - এই প্রোগ্রাম কোথা থেকে এলো? Package manager যা বসায় তা
/usr-এ যায়। নিজে হাতে বসানো থাকে/usr/localবা/opt-এ, যাতে package manager-এর হিসাবের সাথে না মেশে।
/proc কেন আলাদা: এখানে ডিস্কে কিছু নেই। ফাইল পড়লে kernel তখনই উত্তর বানিয়ে দেয়, যেমন প্রতিটি প্রসেসের তথ্য বা মেমরির হিসাব। ps-এর মতো tool এখান থেকেই পড়ে। /tmp-ও স্থায়ী নয়: অনেক distribution-এ এটি reboot-এ মোছে, কোনোটিতে এটি মেমরিতে থাকে (tmpfs). তাই দরকারি কিছু এখানে রাখবেন না।
ফাইল, inode আর directory-র তত্ত্ব এখানে আবার গড়ছি না। Operating Systems কোর্সের File concept আর access method আর Directory আর link পর্বে সেগুলো আছে। Terminal একেবারে নতুন হলে Linux terminal পর্ব আগে দেখে নিন।
৩ · User, group, root আর sudo — ক্ষমতা ভাগ করা
একটি মেসের কথা ভাবুন। প্রত্যেক বোর্ডারের নিজের ঘরের চাবি আছে। রান্নাঘরের চাবি আছে বাজার কমিটির (group). আর বাড়িওয়ালার কাছে আছে মাস্টার চাবি, যেটি সব তালা খোলে। Linux-এ user মানে বোর্ডার, group মানে কমিটি, আর root মানে বাড়িওয়ালা।
Kernel নাম চেনে না, সংখ্যা চেনে। প্রতিটি user-এর একটি UID, প্রতিটি group-এর একটি GID. UID 0 হলো root. নিচের আউটপুট একটি নমুনা, আপনার server-এ সংখ্যা ও নাম আলাদা হবে।
# উদাহরণ: নমুনা আউটপুট, version-ভেদে আলাদা হতে পারে
$ id
uid=1001(rahim) gid=1001(rahim) groups=1001(rahim),27(sudo)
Root দিয়ে সরাসরি login কেন নয়
“আমি তো একাই, root দিয়ে ঢুকলে সমস্যা কী?” কারণ চারটি:
- ভুলের মাপ। Root-এর কোনো বাধা নেই। একটি ভুল
rmপুরো server মুছতে পারে। সাধারণ user-এর ভুল সাধারণত নিজের ফাইলেই থামে, অর্থাৎ blast radius ছোট থাকে। - জবাবদিহি। তিনজন একই root দিয়ে ঢুকলে log বলতে পারে না কে কী করেছে। নিজের নামে ঢুকলে audit log-এ নাম থাকে।
- জানা নাম। Internet-এর স্বয়ংক্রিয় scanner প্রায় সবসময় “root” নামে চেষ্টা করে। নামটি বন্ধ থাকলে এক ধাপ বাধা বাড়ে।
- চুরির ক্ষতি। আপনার প্রোগ্রাম root হিসেবে চললে সেটির একটি ত্রুটিই পুরো যন্ত্র খুলে দিতে পারে।
পর্ব ০৬-এ cloud account-এর root account নিয়ে একই কথা পড়েছেন। স্তর আলাদা, নীতি এক: least privilege. Cloud image-এ সাধারণত ubuntu বা ec2-user-এর মতো একটি শুরুর user থাকে, আর root login বন্ধ বা সীমিত থাকে। Image-ভেদে এটি আলাদা, তাই ধরে না নিয়ে যাচাই করুন।
sudo — খাতায় সই করে চাবি নেওয়া
sudo একটি নির্দিষ্ট কমান্ড অন্য user হিসেবে, সাধারণত root হিসেবে, চালায়। কে কী চালাতে পারবে, তা লেখা থাকে /etc/sudoers আর /etc/sudoers.d/-তে। প্রতিটি ব্যবহার log-এ যায়। Debian পরিবারে admin group-এর নাম সাধারণত sudo, RHEL পরিবারে wheel. ঠিক যেন বাড়িওয়ালার ম্যানেজারের খাতায় সই করে এক কাজের জন্য চাবি নেওয়া।
# Edit only with: sudo visudo -f /etc/sudoers.d/deploy
# The deploy user may restart one service, and nothing else.
deploy ALL=(root) NOPASSWD: /usr/bin/systemctl restart webappvisudo ব্যবহার করুন, কারণ এটি সংরক্ষণের আগে syntax যাচাই করে। ভাঙা sudoers আপনাকে নিজের server থেকেই আটকে দিতে পারে। আর ALL=(ALL) NOPASSWD: ALL লিখলে কার্যত root-ই দিচ্ছেন। সাবধান থাকুন: vim বা tee-এর মতো প্রোগ্রামকে sudo দিলে সেটি দিয়ে যেকোনো ফাইল বদলানো যায়।
Service account — মানুষ নয়, app-এর পরিচয়
আপনার web app কার পরিচয়ে চলবে? আপনার নামে নয়, root-এ তো নয়ই। প্রতিটি app-এর জন্য আলাদা service account বানান, যার login নেই, home ফোল্ডার নেই, আর ক্ষমতা শুধু নিজের কাজটুকু। App-এ কোনো ত্রুটি থাকলেও ক্ষতি সেই account-এর সীমায় আটকে থাকে। nologin shell থাকায় এই account দিয়ে কেউ ঢুকতে পারে না।
# A system account with no login and no home directory
sudo useradd --system --no-create-home --shell /usr/sbin/nologin webapp
# A state folder only webapp can use
sudo install -d -o webapp -g webapp -m 750 /var/lib/webapp
# Config: root writes it, webapp may only read it
sudo install -d -o root -g webapp -m 750 /etc/webapp
sudo install -o root -g webapp -m 640 app.env /etc/webapp/app.envএই পরিচয় দিয়ে service চালানো দেখবেন পর্ব ১১-তে। একই ভাবনা ফিরে আসবে পর্ব ৩১-এ cloud IAM-এর role হয়ে, আর পর্ব ৩৮-এ non-root container হয়ে।
৪ · rwx, octal, chmod, chown আর umask
পুরো তত্ত্ব আছে Operating Systems কোর্সের Linux permission পর্বে। এখানে শুধু server চালাতে যেটুকু হাতে লাগে।
প্রতিটি ফাইলের একটি owner, একটি group, আর একটি mode থাকে। Mode-এ তিন শ্রেণির (owner, group, other) জন্য তিনটি করে বিট: r = ৪, w = ২, x = ১. যোগ করলেই octal সংখ্যা। যেমন rw-r----- মানে owner ৪+২ = ৬, group ৪, other ০, অর্থাৎ 640.
| Mode | rwx | সাধারণ ব্যবহার |
|---|---|---|
644 | rw-r--r-- | সাধারণ config বা HTML ফাইল, গোপন কিছু নয় |
640 | rw-r----- | Service-এর config, যা তার group পড়বে |
600 | rw------- | গোপন ফাইল, যেমন SSH private key |
750 | rwxr-x--- | App-এর directory বা script |
2775 | rwxrwsr-x | দলের shared ফোল্ডার; নতুন ফাইল ফোল্ডারের group পায় |
1777 | rwxrwxrwt | /tmp: সবাই লিখতে পারে, কিন্তু অন্যের ফাইল মুছতে পারে না (sticky bit) |
chmod mode বদলায়, আর chown মালিক বদলায়। ফাইলের owner বা root mode বদলাতে পারেন, কিন্তু মালিকানা বদলাতে সাধারণত root লাগে। chown webapp:webapp data.db মানে owner আর group দুটোই webapp. -R দিলে পুরো গাছ বদলায়, তাই আগে দেখে নিন কোন path-এ চালাচ্ছেন।
নিচের converter-এ সংখ্যা বদলে নিজে পরীক্ষা করুন। শেষ অংশে আছে umask-এর হিসাব, যা একটু পরেই দেখবেন।
// Octal <-> rwx, special bits and umask. Change the lists, press Run again.
const SPECIAL = [0o4000, 0o2000, 0o1000]; // setuid, setgid, sticky
function toRwx(mode) {
let out = "";
for (let i = 0; i < 3; i++) {
const b = (mode >> (6 - 3 * i)) & 7;
const on = mode & SPECIAL[i];
const low = i === 2 ? "t" : "s";
const x = on ? (b & 1 ? low : low.toUpperCase()) : (b & 1 ? "x" : "-");
out += (b & 4 ? "r" : "-") + (b & 2 ? "w" : "-") + x;
}
return out;
}
function toOctal(text) {
let mode = 0;
for (let i = 0; i < 3; i++) {
const [r, w, x] = text.slice(i * 3, i * 3 + 3);
const b = (r === "r" ? 4 : 0) + (w === "w" ? 2 : 0) + ("xst".includes(x) ? 1 : 0);
mode |= b << (6 - 3 * i);
if ("sStT".includes(x)) mode |= SPECIAL[i];
}
return mode;
}
const oct = (m) => m.toString(8).padStart(4, "0");
console.log("octal -> rwx");
for (const m of [0o644, 0o640, 0o600, 0o750, 0o777, 0o2775, 0o1777, 0o4755, 0o4644])
console.log(" ", oct(m), toRwx(m));
console.log("rwx -> octal");
for (const t of ["rw-r-----", "rwxr-x---", "rwsr-xr-x", "rwxrwxrwt"])
console.log(" ", t, oct(toOctal(t)));
console.log("umask: real rule is AND NOT, not subtraction");
for (const u of [0o022, 0o002, 0o027, 0o077, 0o033])
console.log(" ", oct(u), "file", oct(0o666 & ~u), "dir", oct(0o777 & ~u));আউটপুটের 4755 rwsr-xr-x-এ owner-এর x-এর জায়গায় ছোট s: setuid আছে, x-ও আছে। আর 4644 rwSr--r---এ বড় S: setuid আছে কিন্তু x নেই, অর্থাৎ বিটটি কোনো কাজে লাগছে না। Server-এ বড় S দেখলে বুঝবেন কোনো ভুল হয়েছে। শেষ লাইন 0033 file 0644 dir 0744 দেখায়, umask বিয়োগ নয়। বিয়োগ করলে ফাইল হতো 633, অথচ আসল ফল 644.
umask — নতুন তালার ডিফল্ট
নতুন ফাইল বানালে mode কে ঠিক করে? প্রোগ্রাম চায় সাধারণত 666 (ফাইল) বা 777 (directory), আর umask তা থেকে কিছু বিট বন্ধ করে। নিয়মটি হলো mode = চাওয়া & ~umask. অনেক server-এ ডিফল্ট 022, ফলে ফাইল 644, যা সবাই পড়তে পারে। গোপন ফাইল লেখে এমন app-এর জন্য 027 বা 077 ভালো।
set -euo pipefail
lab=$(mktemp -d) # a private folder, removed at the end
trap 'rm -rf "$lab"' EXIT
cd "$lab"
umask 022
echo "port=8080" > app.conf
echo "DB_PASS=example" > app.env
printf 'echo deployed\n' > deploy.sh
mkdir shared
echo "== 1. as created (umask 022) =="
stat -c '%a %A %n' app.conf app.env deploy.sh shared
chmod 640 app.conf # owner rw, group r, other nothing
chmod 600 app.env # a secret: owner only
chmod u+x,g+x deploy.sh # symbolic: add x, keep the rest
chmod 2775 shared # setgid on a folder
echo "== 2. after chmod =="
stat -c '%a %A %n' app.conf app.env deploy.sh shared
echo "== 3. umask sets the starting mode =="
for m in 022 027 077 033; do
( umask "$m"
touch "file$m"; mkdir "dir$m"
stat -c "umask $m: %a %A %n" "file$m" "dir$m" )
doneপ্রথম অংশে 644 -rw-r--r-- app.env: umask 022-এ বানানো গোপন ফাইলটি প্রথমে সবাই পড়তে পারে। chmod 600-এর পর সেটি 600 -rw------- app.env. তাই গোপন ফাইল আগে বানিয়ে পরে chmod করার চেয়ে আগে umask ঠিক করা বা install -m 600 ব্যবহার করা নিরাপদ। chmod u+x,g+x বাকি বিট রেখেই 644-কে করল 754. আর 2775 drwxrwsr-x shared-এ group-এর জায়গায় s. শেষে umask 033: 644 আর 744 মিলিয়ে দেখুন, converter-এর হিসাবের সাথে মিলে গেছে।
Setuid — ধার করা পরিচয়
Setuid বিট থাকা প্রোগ্রাম চলে ফাইলের মালিকের পরিচয়ে, যে চালাল তার পরিচয়ে নয়। passwd এর পরিচিত উদাহরণ: সাধারণ user নিজের password বদলায়, কিন্তু password-এর ফাইলে লেখার অধিকার তো শুধু root-এর। তাই passwd root-এর পরিচয় ধার করে চলে। ধারণাটি কাজের, কিন্তু এমন প্রোগ্রামে একটি ত্রুটি মানেই root-এর ঝুঁকি। Server-এ এদের তালিকা রাখুন, আর অচেনা কিছু দেখলে খোঁজ নিন। Linux kernel script-এর ওপর setuid মানে না; এটি শুধু compiled প্রোগ্রামে কাজ করে।
৫ · Kernel কীভাবে সিদ্ধান্ত নেয়
সবচেয়ে বেশি ভুল বোঝা হয় এখানে। অনেকে ভাবেন, owner-এ না মিললে group, group-এ না মিললে other, এভাবে অনুমতি খোঁজা হয়। আসলে তা নয়। Kernel প্রথমে ঠিক করে আপনি কোন একটি শ্রেণিতে পড়েন, তারপর শুধু সেই শ্রেণির বিট দেখে। অন্য শ্রেণিতে অনুমতি থাকলেও লাভ নেই।
একটি বাস্তব অনুরোধ অনুসরণ করি। প্রসেসটি চলছে webapp user হিসেবে, যার group webapp আর appcfg. ফাইলটি হলো -rw-r----- root appcfg /etc/app.conf. দুটি directory-র mode 755, মালিক root. “পরে” চাপুন, ডান পাশের মান খেয়াল করুন।
1open("/etc/app.conf", read)2walk "/" : x on dir?3walk "/etc" : x on dir?4uid == file owner?5file group in my groups?6class bits have r?7return fd or EACCES
| জায়গা | |
| শ্রেণি | |
| বিট | |
| ফল |
- অনুরোধ এলো। প্রসেস
open()system call দিয়ে ফাইলটি পড়তে চাইল। Kernel-এর কাছে আছে প্রসেসের UID আর group-এর তালিকা। - আগে পথ, পরে ফাইল। ফাইলে পৌঁছাতে প্রতিটি directory পার হতে হয়, আর directory-তে x মানে “ভেতর দিয়ে যাওয়া”।
/-এর মালিক root,webappকোনো মিল পায় না, তাই শ্রেণি other. বিটr-x-এ x আছে, পার হলো। - দ্বিতীয় directory.
/etc-তেও একই হিসাব: শ্রেণি other, বিটr-x, x আছে। কোনো parent directory-তে x না থাকলে ফাইলের নিজের mode যা-ই হোক, পড়া যেত না। - Owner কি? ফাইলের মালিক root, প্রসেসের UID
webapp-এর। মিলল না, তাই owner-বিটrw-এখানে প্রযোজ্যই নয়। - Group কি? ফাইলের group
appcfg, আর প্রসেসের তালিকায়appcfgআছে। শ্রেণি ঠিক হয়ে গেল: group. এখন থেকে other-বিট আর দেখা হবে না। - বিট মেলানো। Group-বিট
r--, আর দরকার read. r আছে, তাই অনুমতি মিলল। - ফল। Kernel একটি file descriptor ফেরত দিল, যেমন 3. প্রসেস ফাইলের লেখা
port=8080পড়তে পারল। যাচাই হয়open()-এর সময়; পরের প্রতিটি read-এ আবার হয় না। - অন্য ফল। এবার ধরুন
appcfggroup তালিকায় নেই। তখন শ্রেণি হতো other, বিট---. Kernel ফেরত দিতEACCES, যা আপনি দেখেন “Permission denied” হিসেবে। সমাধানchmod 644নয়, প্রসেসকে group-এ যোগ করা।
এবার নিজে পরীক্ষা করুন। নিচের simulator একই নিয়মে চলে, আর root-এর বিশেষ নিয়মও আছে: read আর write-এ বিট লাগে না, কিন্তু চালানোর জন্য অন্তত একটি x বিট থাকতে হয়। শেষের তালিকায় নতুন অনুরোধ যোগ করে দেখুন।
// Unix permission check. Exactly ONE class applies: owner, else group, else other.
const users = { root: ["root"], webapp: ["webapp", "appcfg"],
backup: ["backup"], rahim: ["rahim", "sudo"] };
const files = {
"/": { owner: "root", group: "root", mode: 0o755 },
"/etc": { owner: "root", group: "root", mode: 0o755 },
"/etc/app.conf": { owner: "root", group: "appcfg", mode: 0o640 },
"/home": { owner: "root", group: "root", mode: 0o755 },
"/home/rahim": { owner: "rahim", group: "rahim", mode: 0o700 },
"/home/rahim/a": { owner: "rahim", group: "rahim", mode: 0o644 },
"/home/rahim/b": { owner: "rahim", group: "rahim", mode: 0o044 },
};
const WANT = { read: 4, write: 2, exec: 1 };
function classOf(user, node) {
if (node.owner === user) return ["owner", 6];
return users[user].includes(node.group) ? ["group", 3] : ["other", 0];
}
function allowed(user, node, bit) {
if (user === "root") return bit !== 1 || (node.mode & 0o111) !== 0;
return ((node.mode >> classOf(user, node)[1]) & bit) !== 0;
}
function check(user, want, path) {
const parts = path.split("/").slice(1);
for (let i = 0; i < parts.length; i++) { // walk the parent folders first
const dir = "/" + parts.slice(0, i).join("/");
if (!allowed(user, files[dir], 1)) return `DENY no x on ${dir}`;
}
const ok = allowed(user, files[path], WANT[want]) ? "ALLOW" : "DENY ";
return `${ok} ${user === "root" ? "root rule" : classOf(user, files[path])[0]}`;
}
for (const [u, w, p] of [["webapp", "read", "/etc/app.conf"], ["webapp", "write", "/etc/app.conf"],
["backup", "read", "/etc/app.conf"], ["root", "write", "/etc/app.conf"],
["root", "exec", "/etc/app.conf"], ["rahim", "read", "/home/rahim/a"],
["webapp", "read", "/home/rahim/a"], ["rahim", "read", "/home/rahim/b"]])
console.log(u.padEnd(7) + w.padEnd(6) + p.padEnd(15) + check(u, w, p));দুটি লাইন চমকে দেওয়ার মতো। rahim read /home/rahim/b DENY owner: ফাইলের mode 044, group আর other পড়তে পারে, কিন্তু মালিক নিজে পারে না, কারণ তার শ্রেণি owner, আর owner-বিট শূন্য। আর webapp read /home/rahim/a DENY no x on /home/rahim: ফাইল 644 হলেও পথের directory 700, তাই ফাইল পর্যন্ত পৌঁছানোই গেল না। root exec /etc/app.conf DENY root rule দেখায়, root-ও x-হীন ফাইল চালাতে পারে না।
আরও গভীরে: এই পুরো মডেলের নাম discretionary access control (DAC): মালিক নিজেই অনুমতি ঠিক করেন। এর ওপরে আরও স্তর বসতে পারে। POSIX ACL একটি ফাইলে আলাদা আলাদা user-কে অনুমতি দিতে দেয়। Capability root-এর ক্ষমতাকে ছোট টুকরোয় ভাগ করে। আর SELinux বা AppArmor-এর মতো LSM DAC পার হওয়ার পরও, এমনকি root-কেও, আটকাতে পারে। তাই বিট ঠিক থাকলেও “Permission denied” এলে RHEL পরিবারে SELinux-এর log দেখা উচিত।
৬ · Permission অডিট — ঝুঁকি খুঁজে বের করা
সিদ্ধান্ত বুঝলেন, এবার পুরো server-এ ভুল খোঁজার পালা। সবচেয়ে বিপজ্জনক ভুল হলো world-writable ফাইল, অর্থাৎ other-এর w বিট চালু। এমন script যে কেউ বদলে দিতে পারে, আর পরে root সেটি চালালে পুরো যন্ত্র ঝুঁকিতে পড়ে।
find-এর -perm তিন রকম: -perm 644 মানে হুবহু 644; -perm -o+w মানে বলা বিটগুলোর সবই আছে; -perm /022 মানে বলা বিটগুলোর অন্তত একটি আছে। নিচের script নিজের বানানো একটি ছোট ফোল্ডারে কাজ করে, আর সেখানে ইচ্ছা করে কিছু ভুল রাখা হয়েছে।
set -euo pipefail
lab=$(mktemp -d); trap 'rm -rf "$lab"' EXIT; cd "$lab"
# A tiny fictional app tree, with some mistakes on purpose
mkdir -p srv/app srv/uploads srv/spool etc
touch srv/app/main.py srv/app/notes.txt srv/app/.env srv/app/run.sh etc/tool
chmod 644 srv/app/main.py
chmod 664 srv/app/notes.txt # the group may edit it, others may not
chmod 666 srv/app/.env # mistake: anyone can edit a secret
chmod 777 srv/app/run.sh # mistake: anyone can edit a script
chmod 777 srv/uploads # mistake: no sticky bit
chmod 1777 srv/spool # shared folder, sticky bit is set
chmod 4755 etc/tool # setuid: must be on an approved list
echo "== exact mode 644 =="
find . -type f -perm 644 | sort
echo "== all of these bits: o+w =="
find . -type f -perm -o+w | sort
echo "== any of these bits: g+w, o+w =="
find . -type f -perm /022 | sort
n=0
flag() { # level, message, then find tests
local level=$1 msg=$2 p; shift 2
while IFS= read -r p; do
printf '%s %s %s %s\n' "$level" "$(stat -c %a "$p")" "$p" "$msg"
n=$((n + 1))
done < <(find . "$@" | sort)
}
echo "== audit =="
flag HIGH "world-writable file" -type f -perm -o+w
flag HIGH "world-writable dir, no sticky" -type d -perm -o+w ! -perm -1000
flag WARN "setuid, check the allow-list" -type f -perm -4000
echo "findings: $n"== any of these bits: g+w, o+w == অংশে ./srv/app/notes.txt বাড়তি এসেছে, কারণ এর শুধু g+w আছে; -o+w-এর তালিকায় এটি নেই। অডিটের ফল findings: 4. খেয়াল করুন, srv/spool তালিকায় নেই, যদিও সেটিও সবাই লিখতে পারে: sticky bit থাকায় ! -perm -1000 শর্তে বাদ পড়েছে। আর n=$((n + 1)) লেখা হয়েছে কারণ set -e-এর সাথে ((n++)) শূন্য থেকে শুরু হলে script থামিয়ে দেয়। set -euo pipefail-এর পূর্ণ ব্যাখ্যা পাবেন পর্ব ১০-এ।
আসল server-এ এই খোঁজ একটু সাবধানে চালাতে হয়: -xdev দিয়ে একটি filesystem-এ থাকুন, যাতে /proc আর network disk-এ না ঢোকে। ফলাফল ঠিক করার আগে পড়ুন; অনেক package-এর setuid বিট ইচ্ছাকৃত। এটি শুধু খোঁজে, কিছু বদলায় না।
# Read-only checks. They list files and change nothing.
sudo find / -xdev -type f -perm -o+w
sudo find / -xdev -type d -perm -o+w ! -perm -1000
sudo find / -xdev -type f -perm -4000৭ · Package manager — apt, dnf আর স্বাক্ষর করা package
আগের দিনে software বসাতে হলে source code নামিয়ে compile করতে হতো, আর প্রতিটি নির্ভরতা নিজে খুঁজতে হতো। Package manager এই কাজ করে দেয়। ধরুন ওষুধ কিনছেন: রাস্তার ফেরিওয়ালার বদলে অনুমোদিত দোকান, সিল করা প্যাকেট, আর গায়ে মেয়াদ লেখা। Repository সেই দোকান, signature সেই সিল।
| কাজ | Debian, Ubuntu (apt) | RHEL পরিবার (dnf) |
|---|---|---|
| তালিকা হালনাগাদ | apt update | dnf check-update |
| install | apt install nginx | dnf install nginx |
| সব upgrade | apt upgrade | dnf upgrade |
| ফাইলের তালিকা | dpkg -L nginx | rpm -ql nginx |
| এই ফাইল কার? | dpkg -S /usr/sbin/nginx | rpm -qf /usr/sbin/nginx |
| কী হবে দেখা, করা নয় | apt-get -s install nginx | dnf install --assumeno nginx |
Script-এ apt-এর বদলে apt-get লিখুন, কারণ apt-এর আউটপুট মানুষের জন্য, আর সেটি স্থির থাকার নিশ্চয়তা নেই। এবার দেখি apt install-এর ভেতরে কী হয়।
- Repository
sourcesকোন দোকান - তালিকা
InReleaseসিল যাচাই - পরিকল্পনা
dependsকী কী লাগবে - Download
.debhash মেলানো - Disk
dpkgফাইল বসানো - Service
postinstশেষের কাজ
Types: deb
URIs: https://deb.example.org/debian
Suites: stable
Components: main
Signed-By: /usr/share/keyrings/example-archive-keyring.gpg
Get:1 https://deb.example.org/debian stable InRelease
Get:2 https://deb.example.org/debian stable/main amd64 Packages
Reading package lists... Done
# saved in /var/lib/apt/lists/
The following NEW packages will be installed:
nginx nginx-common
0 upgraded, 2 newly installed, 0 to remove and 0 not upgraded.
Do you want to continue? [Y/n]
nginx_1.24.0-2_amd64.deb nginx-common_1.24.0-2_all.deb # SHA256 of the file == SHA256 in the signed list a1b2c3... == a1b2c3... OK
/usr/sbin/nginx /etc/nginx/nginx.conf /usr/lib/systemd/system/nginx.service /var/log/nginx # the record: /var/lib/dpkg/status
active # RHEL family: installed but not started. # There you run: systemctl enable --now nginx
- কোন দোকান। Server-এ লেখা থাকে কোন repository থেকে package আসবে, আর কোন public key দিয়ে তার সিল যাচাই হবে।
Signed-Byএই repository-কে একটি নির্দিষ্ট key-এর সাথে বাঁধে। - দামের তালিকা আনা।
apt updateকোনো software বসায় না, শুধু তালিকা আনে।InReleaseফাইলটি repository-র private key দিয়ে স্বাক্ষর করা, আর এর ভেতরেPackagesতালিকার hash থাকে। স্বাক্ষর না মিললে apt থেমে যায়। - পরিকল্পনা।
apt install nginxতালিকা দেখে হিসাব করে কোন dependency লাগবে। এখানেnginxচায়nginx-common-কে। “0 to remove” লাইনটি পড়ুন; কিছু মুছে ফেলার পরিকল্পনা থাকলে থামুন। - Download আর hash.
.debফাইল আসে/var/cache/apt/archives/-এ। এর SHA256 মেলানো হয় স্বাক্ষরিত তালিকার সাথে। তাই mirror ফাইল বদলালে মিলবে না, এমনকি HTTP দিয়ে নামালেও। - Disk-এ বসানো।
dpkgফাইলগুলো filesystem-এর মানচিত্র মেনে ছড়িয়ে দেয়: প্রোগ্রাম/usr-এ, config/etc-এ, log-এর ফোল্ডার/var/log-এ। কোন ফাইল কার, সেই হিসাব থাকে/var/lib/dpkg/-এ। - শেষের কাজ। Package-এর সাথে থাকা
postinstscript root হিসেবে চলে: user বানানো, service চালু করা ইত্যাদি। Debian পরিবারে service সাধারণত নিজে থেকে চালু হয়, RHEL পরিবারে সাধারণত নয়। Package install মানে তাই root হিসেবে অন্যের code চালানো।
যা করবেন না: [trusted=yes] বা --allow-unauthenticated সিল যাচাই বন্ধ করে দেয়। আর curl ... | sudo bash অচেনা script সরাসরি root হিসেবে চালায়। বাইরের repository যোগ করতে হলে key আলাদা ফাইলে রেখে Signed-By দিন। পুরোনো apt-key add পদ্ধতি বাতিল করা হয়েছে, কারণ এতে একটি key সব repository-র জন্য বিশ্বস্ত হয়ে যেত।
স্বয়ংক্রিয় নিরাপত্তা update
নিরাপত্তা-ত্রুটি (CVE) প্রকাশের পর হাতে update-এর অপেক্ষা করা মানে ঝুঁকি খোলা রাখা। তাই unattended security update চালু রাখা হয়: শুধু নিরাপত্তা-সংশোধন নিজে থেকে বসে।
# Debian, Ubuntu
sudo apt-get install unattended-upgrades
sudo dpkg-reconfigure --priority=low unattended-upgrades
# RHEL family: in /etc/dnf/automatic.conf set
# upgrade_type = security
# apply_updates = yes
sudo dnf install dnf-automatic
sudo systemctl enable --now dnf-automatic.timerএকটি বিষয় মনে রাখুন: live patch ব্যবস্থা না থাকলে kernel-এর update চালু হয় কেবল reboot-এর পর, আর চলমান service-কে নতুন library পেতে restart করতে হয়। Unattended tool ডিফল্টভাবে সাধারণত reboot করে না। Ubuntu-তে /var/run/reboot-required ফাইল থাকলে বুঝবেন reboot বাকি।
৮ · Disk — df, du, mount আর fstab
Production-এর একটি খুব পরিচিত ঘটনা: রাত তিনটায় app থেমে গেল, log-এ No space left on device. Disk-এর কাজ বুঝতে তিনটি প্রশ্ন যথেষ্ট: কতটুকু ভরেছে, কে ভরেছে, আর কোন disk কোথায় বসেছে। নিচের সব আউটপুট নমুনা, version-ভেদে আলাদা হতে পারে।
# উদাহরণ: কতটুকু ভরেছে (নমুনা আউটপুট)
$ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/nvme0n1p1 30G 27G 1.4G 96% /
/dev/nvme1n1 100G 61G 34G 65% /data
tmpfs 1.9G 0 1.9G 0% /run
# উদাহরণ: কে ভরেছে (নমুনা আউটপুট)
$ sudo du -xh --max-depth=1 /var | sort -h | tail -4
120M /var/cache
1.8G /var/lib
19G /var/log
21G /var
হিসাব পড়ুন: / ৯৬% ভরা, আর তার ২১ GB যাচ্ছে /var-এ, যার ১৯ GB log. কারণটি প্রায়ই এমনই। সমাধান হলো log-এর ঘূর্ণন (logrotate) আর log-কে বাইরে পাঠানো (পর্ব ৬৪). হাতে মুছলে দুটি জিনিস মাথায় রাখুন। Size থেকে Used বাদ দিলে Avail মেলে না, কারণ ext4 সাধারণত root-এর জন্য কিছু জায়গা সংরক্ষিত রাখে। আর কোনো প্রসেস ফাইল খোলা রেখে থাকলে সেটি মোছার পরও জায়গা ফেরে না, যতক্ষণ না প্রসেস ফাইলটি বন্ধ করে।
আরেকটি ফাঁদ: df -h-এ জায়গা খালি, তবু একই error. তখন df -i দেখুন। প্রতিটি ফাইলের জন্য একটি inode লাগে, আর লাখ লাখ ছোট ফাইল inode শেষ করে দিতে পারে।
mount আর fstab
নতুন disk নিজে থেকে দেখা যায় না। তাকে গাছের কোনো একটি ফোল্ডারে বসাতে হয়; একে বলে mount. গুদামের একটি নির্দিষ্ট দরজা দিয়ে পাশের গুদামে যাওয়ার মতো: /data-এ ঢুকলেই আপনি আসলে অন্য disk-এ। Reboot-এর পরও বসে থাকতে হলে লিখতে হয় /etc/fstab-এ।
# device mount type options dump pass
UUID=11111111-2222-3333-4444-555555555555 /data ext4 defaults,noatime,nofail 0 2UUID: disk-এর নাম (/dev/nvme1n1) reboot-এ বদলে যেতে পারে, UUID বদলায় না।nofail: disk না পেলেও boot চলতে থাকে। Cloud-এ এটি জরুরি, কারণ volume খুলে নেওয়া (detach) থাকলে এই option ছাড়া server boot-এ আটকে যেতে পারে, আর তখন SSH দিয়েও ঢোকা যায় না।noatime: প্রতিবার পড়ার সময় “শেষ পড়ার সময়” লেখা বন্ধ করে, ফলে বাড়তি লেখা কমে।- যাচাই: reboot-এর আগে
sudo findmnt --verifyচালান। ভুল fstab পরের boot ভাঙতে পারে।
Cloud-এর disk কেমন, আর কোনটি VM বন্ধ করলে মুছে যায়, তা দেখবেন পর্ব ২০-এ।
৯ · নতুন server শক্ত করা — প্রথম ঘণ্টার চেকলিস্ট
Public IP পাওয়া একটি server-এ কয়েক মিনিটের মধ্যেই অচেনা login চেষ্টা আসতে শুরু করে, কারণ scanner সারাক্ষণ internet ঘুরে বেড়ায়। Hardening মানে অপ্রয়োজনীয় দরজা বন্ধ করে আক্রমণের সুযোগ কমানো। নতুন দোকান খোলার আগে যেমন তালা বদলান, হিসাবের খাতা গুছিয়ে রাখেন, তেমন।
নিচের stepper-এ একটি কাল্পনিক Ubuntu VM ধাপে ধাপে শক্ত হচ্ছে। ঠিকানাটি উদাহরণের জন্য সংরক্ষিত 203.0.113.10. প্রতিটি ধাপে ডান পাশের অবস্থা কীভাবে বদলায়, খেয়াল করুন। RHEL পরিবারে কমান্ড একটু আলাদা, কিন্তু ক্রম একই।
| OS patch | |
| দৈনন্দিন login | |
| SSH | |
| খোলা port | |
| নিরাপত্তা update | |
| App-এর পরিচয় | |
| Log আর backup |
- প্রথম login. Cloud image-এর শুরুর user দিয়ে key-সহ ঢুকলেন। এখনো কিছু বদলাননি। আপনি জানেন না কোন port খোলা, আর image-টি কতদিন আগের।
- আগে update. Image তৈরির পর আসা সব সংশোধন বসান। Kernel বদলালে reboot দিন। এই ধাপ আগে, কারণ পরের কাজগুলো আপডেট করা ভিত্তির ওপর হওয়া উচিত।
- নিজের user. নিজের নামে account বানিয়ে sudo group-এ দিন, আর নিজের public key তার
~/.ssh/authorized_keys-এ রাখুন। নতুন user দিয়ে আলাদা terminal-এ login করে দেখুন, sudo-ও চালিয়ে দেখুন, তারপরই পরের ধাপে যান। - শুধু key দিয়ে SSH. Password login আর root login বন্ধ করুন (নিচের config).
sshd -tফাইলটি যাচাই করে, তারপর reload. পুরোনো session খোলা রেখে নতুন session-এ পরীক্ষা করুন, নইলে ভুল হলে নিজেই আটকে যাবেন। বিস্তারিত পর্ব ১২-তে। - দরজা কমান। শুধু SSH আর 443 খোলা রাখুন। Cloud-এ এই কাজের প্রধান জায়গা হলো security group (পর্ব ২৭), আর SSH খোলা থাকা উচিত শুধু আপনার জানা ঠিকানার জন্য। Host firewall তার ওপরে দ্বিতীয় স্তর।
- Update স্বয়ংক্রিয়। নিরাপত্তা-সংশোধন এখন নিজে থেকে বসবে। Reboot কখন হবে, সেটির একটি পরিকল্পনাও রাখুন।
- App-এর নিজস্ব পরিচয়। App root হিসেবে চলবে না।
webappaccount বানালেন। যা চলছে না তেমন service বন্ধ রাখুন, আরsudo ss -tlnpদিয়ে দেখুন কে কোন port শুনছে (পর্ব ১৩). - দেখার ব্যবস্থা। সময় ঠিক আছে কি না দেখুন, কারণ ভুল সময়ে log আর TLS দুটোই বিভ্রান্তি ছড়ায়। Log বাইরে পাঠান, disk-এর জন্য alert দিন, backup নিন, আর একবার restore করে দেখুন। সব ধাপ একটি runbook-এ লিখে রাখুন।
# /etc/ssh/sshd_config.d/10-hardening.conf
# Keep your current session open while you test a new login.
PermitRootLogin no
PasswordAuthentication no
KbdInteractiveAuthentication noএখানে ফাইলের নাম 10- দিয়ে শুরু, কারণ sshd একটি সেটিংয়ের প্রথম পাওয়া মানটি রাখে, আর ফাইলগুলো নামের ক্রমে পড়া হয়। Cloud image নিজস্ব ফাইল রাখতে পারে। তাই sudo sshd -T | grep -i passwordauth দিয়ে শেষ পর্যন্ত কী কার্যকর হলো, তা দেখে নিন।
হাতে একটি server শক্ত করা শেখার জন্য ভালো, কিন্তু একশোটির জন্য নয়। বাস্তবে এই ধাপগুলো যায় cloud-init বা machine image-এ (পর্ব ১৬), আর Ansible-এ (পর্ব ৫৬), যাতে প্রতিটি নতুন server জন্ম থেকেই শক্ত হয়। পরিবর্তন লাগলে পুরোনো server ঠিক না করে নতুন image থেকে বদলে ফেলাও একটি প্রচলিত পথ। মান হিসেবে দেখতে পারেন CIS Benchmarks.
পরীক্ষা ও ইন্টারভিউতে:
chmod 755মানে কী? Owner rwx, group ও other r-x.- umask 027-এ নতুন ফাইল আর directory? ফাইল
640, directory750. /etcআর/var-এর পার্থক্য?/etc-এ config,/var-এ চলার সময় বদলানো ডেটা, যেমন log.sudoআরsu-এর পার্থক্য?sudoনিজের password-এ, নিয়ম মেনে একটি কমান্ড চালায়;suঅন্য user-এর shell খোলে, সাধারণত তার password লাগে।- Disk খালি, তবু “No space left” কেন? সম্ভবত inode শেষ;
df -iদেখুন।
১০ · AI-এর যুগে server চালানো
AI “Permission denied” দেখলে প্রায়ই সবচেয়ে ছোট সমাধানটি দেয়, আর সেটিই সবচেয়ে বিপজ্জনক। কাজ চলে যায়, ঝুঁকি থেকে যায়, আর আপনি টেরও পান না।
| AI যা দেয় | ঝুঁকি | যা করা উচিত |
|---|---|---|
chmod -R 777 /var/www | যে কেউ code বদলাতে পারে | কোন user-কে কী লাগবে বের করে ঠিক owner, group আর mode দেওয়া |
সব কমান্ডে sudo, app root হিসেবে | একটি ত্রুটিতে পুরো server | Service account |
curl ... | sudo bash | না দেখা code root হিসেবে চলে | Script নামিয়ে পড়া, অথবা স্বাক্ষরিত repository |
[trusted=yes], apt-key add | Package-এর সিল যাচাই দুর্বল | Key আলাদা ফাইলে, Signed-By |
setenforce 0, ufw disable | পুরো সুরক্ষা স্তর বন্ধ | Log পড়ে নির্দিষ্ট অনুমতি যোগ করা |
rm -rf দিয়ে disk খালি করা | ভুল path-এ ডেটা হারানো | আগে du আর ls দিয়ে দেখা, সম্ভব হলে snapshot |
| নেই এমন flag, পুরোনো distro-র কমান্ড | ভুল ফল বা ভুল ধারণা | man পাতা ও distribution-এর docs দেখা |
AI-কে শুধু error না দিয়ে পরিস্থিতি দিন, আর ঝুঁকির কথাও জিজ্ঞেস করুন। Password, key বা token কখনো prompt-এ দেবেন না; path আর নামও দরকার হলে বদলে নিন।
AI-এর কমান্ড চালানোর আগে যাচাইয়ের চেকলিস্ট
ভাবনার প্রশ্ন
প্রতিটি প্রশ্ন নিয়ে নিজে কিছুক্ষণ ভাবুন, তারপর “→ উত্তর” চাপুন।
প্র ০১Setuid এত ঝুঁকিপূর্ণ হলে পঞ্চাশ বছর ধরে এটি টিকে আছে কেন?
সমস্যাটি পুরোনো আর আসল। ধরুন একটি সাধারণ user-কে একটি ছোট, নির্দিষ্ট কাজ করতে হবে, যেমন নিজের password বদলানো, অথচ সেই কাজের জন্য যে ফাইলে লিখতে হয় তা শুধু root-এর। Dennis Ritchie এর সমাধান হিসেবে setuid-এর ধারণা দেন, আর ১৯৭৯ সালে এর একটি মার্কিন patent মঞ্জুর হয়। ভাবনাটি সুন্দর: ক্ষমতা মানুষের কাছে নয়, একটি যাচাই করা প্রোগ্রামের কাছে থাকবে। প্রোগ্রামটি নিজেই ঠিক করবে কতটুকু করতে দেবে।
দুর্বলতাও সেখানেই। পুরো নিরাপত্তা নির্ভর করে সেই প্রোগ্রামের প্রতিটি লাইনের ওপর। ২০২২ সালের শুরুতে Qualys জানায়, polkit-এর pkexec প্রোগ্রামে এমন একটি ত্রুটি আছে (PwnKit নামে পরিচিত, CVE-2021-4034), যা বারো বছরেরও বেশি সময় অলক্ষ্যে ছিল, আর যা একজন সাধারণ user-কে root করে দিতে পারত। প্রোগ্রামটি বহু distribution-এ ডিফল্টভাবেই ছিল। ২০২১ সালে sudo-তেও একটি গুরুতর ত্রুটি (Baron Samedit, CVE-2021-3156) প্রকাশ পায়।
তবু এটি রাতারাতি সরানো যায় না, কারণ বহু পুরোনো ব্যবস্থা এর ওপর দাঁড়িয়ে। তাই পথটি ধীরে ধীরে কমানোর:
- Capability: পুরো root-এর বদলে একটি ছোট ক্ষমতা, যেমন শুধু নিচের port খোলা।
- Mount option:
nosuidদিলে সেই filesystem-এ setuid কাজ করে না, যেমন upload বা/tmp-এ। - Container: কম capability আর
no-new-privilegesদিয়ে চালানো (পর্ব ৪৯). - নজরদারি: তালিকা রাখা, আর দ্রুত patch বসানো।
Cloud-এর পরিবেশেও ঝুঁকিটি একই, কারণ container বা VM-এর ভেতরে একটি setuid প্রোগ্রাম থাকলে সেখানকার সাধারণ user-ও root হয়ে উঠতে পারে।
মূল উপলব্ধি: নিরাপত্তায় “বিশ্বাসযোগ্য অংশ” যত ছোট, ঝুঁকি তত কম। প্রতিটি setuid প্রোগ্রাম সেই অংশকে একটু বড় করে, তাই তালিকাটি যতটা সম্ভব ছোট রাখা দরকার।
প্র ০২Package স্বাক্ষর করা থাকলে কি সরবরাহ-শৃঙ্খল নিরাপদ বলা যায়?
না। স্বাক্ষর একটি নির্দিষ্ট প্রশ্নের উত্তর দেয়: “এই জিনিস কি পথে বদলে গেছে, আর এটি কি সেই প্রকাশকের কাছ থেকেই এসেছে?” এটি বলে না যে ভেতরের code ভালো। সিল করা ওষুধের প্যাকেট মানে প্যাকেট খোলা হয়নি, কারখানায় ভুল হয়নি এমন নয়।
২০২৪ সালের মার্চে এর সবচেয়ে বড় উদাহরণ দেখা যায়। xz compression library-র একজন রক্ষণাবেক্ষণকারী দীর্ঘদিন ধরে বিশ্বাস অর্জন করে তার release-এ একটি backdoor লুকিয়ে রাখেন (CVE-2024-3094). Release-টি বৈধ প্রকাশকের কাছ থেকেই এসেছিল, তাই স্বাক্ষর দিয়ে এটি ধরা পড়ার কথা নয়। ধরা পড়ে এক প্রকৌশলীর, Andres Freund-এর, কৌতূহলে: তিনি SSH-এ অস্বাভাবিক ধীরগতি লক্ষ করেছিলেন। মজার বিষয়, ত্রুটিপূর্ণ version মূলত কিছু নতুন বা rolling ধারায় পৌঁছেছিল; স্থিতিশীল ধারার বড় distribution-গুলো লেখার সময়ের বিবরণ অনুযায়ী মূলত রক্ষা পায়, কারণ সেখানে নতুন version ধীরে ঢোকে। LTS-এর ধীরগতি সেদিন একটি বাড়তি সুবিধা হয়ে দাঁড়ায়।
apt আর dnf-এর স্বাক্ষরের ধরনও আলাদা। apt সাধারণত repository-র তালিকায় স্বাক্ষর দেখে, তারপর hash-এর শিকল ধরে প্রতিটি package যাচাই করে। RPM-এ সাধারণত প্রতিটি package নিজেই স্বাক্ষর করা। দুই পদ্ধতিতেই আস্থার গোড়া হলো key, তাই key-এর ব্যবস্থাপনাই আসল।
তাহলে বাড়তি কী লাগে? Reproducible build, যেখানে যে কেউ একই source থেকে একই ফাইল বানিয়ে মেলাতে পারেন; SBOM, যা জানায় ভেতরে কী আছে; আর কম সংখ্যক repository. পর্ব ৪১ আর ৬১-তে এই পথগুলো দেখবেন।
মূল উপলব্ধি: স্বাক্ষর প্রমাণ করে উৎস, গুণ নয়। আস্থা একটি শিকল, আর যাচাই করতে হয় তার প্রতিটি আংটা।
প্র ০৩Container-এর জন্য Alpine-ই কি সবসময় সেরা, কারণ সেটি সবচেয়ে ছোট?
ছোট image-এর লাভ বাস্তব: কম download, দ্রুত শুরু, আর কম package মানে কম সম্ভাব্য ত্রুটি। Alpine-এর base image মাত্র কয়েক MB, কারণ এটি BusyBox-এর ছোট tool আর musl libc ব্যবহার করে। Debian বা Ubuntu ব্যবহার করে glibc. এই একটি পার্থক্যই অনেক সময় আসল গল্প।
প্রথম সমস্যা build-এ। অনেক Python বা Node.js library-র আগে থেকে বানানো অংশ দীর্ঘদিন glibc-এর জন্য তৈরি হতো। Alpine-এ সেগুলো হয় পাওয়া যেত না, নয়তো নিজে compile করতে হতো। ফলে Dockerfile-এ compiler আর header জড়ো হতো, build ধীর হতো, আর image-ও আর ছোট থাকত না। এখন musl-এর জন্য অনেক package পাওয়া যায়, তবে সব নয়।
দ্বিতীয় সমস্যা আচরণে। musl-এর DNS resolver আর glibc-এর resolver সব পরিস্থিতিতে একইভাবে চলে না। আবার মেমরি বরাদ্দের কিছু কাজের গতিও আলাদা হতে পারে। এসব সমস্যা production-এ চাপ পড়লে তবেই দেখা দেয়, আর খুঁজে পেতে সময় লাগে।
তৃতীয় বিষয় হলো debug. Container-এর ভেতরে পরিচিত tool না থাকলে সমস্যা খোঁজা কঠিন হয়, যদিও এই আপত্তির একটি উত্তর আছে: পাশে আলাদা debug container চালানো।
বিকল্পও আছে। Debian-এর slim image glibc রেখে আকার কমায়। আর distroless ধরনের image-এ shell বা package manager-ই থাকে না, শুধু app আর তার দরকারি library. Go-র মতো static binary-র জন্য Alpine বা আরও ছোট image চমৎকার। অন্যদিকে native library-র ওপর নির্ভরশীল Python app-এ slim প্রায়ই কম ঝামেলার। পর্ব ৩৮-এ multi-stage build দিয়ে এই সিদ্ধান্ত হাতে-কলমে দেখবেন।
মূল উপলব্ধি: আকার একটি মাপকাঠি মাত্র। মাপুন নিজের app দিয়ে: build-এর সময়, চলার আচরণ, debug-এর সুবিধা আর ত্রুটির সংখ্যা। “সবচেয়ে ছোট” আর “সবচেয়ে উপযুক্ত” এক নয়।
প্র ০৪CentOS-এর ঘটনা distribution বাছাই নিয়ে কী শেখায়?
বহু বছর ধরে CentOS ছিল RHEL-এর বিনামূল্যের পুনর্নির্মাণ। অনেক প্রতিষ্ঠান এর ওপর হাজার হাজার server চালাত, এই ভরসায় যে প্রতিটি release দশ বছরের কাছাকাছি সংশোধন পাবে। ২০২০ সালের ডিসেম্বরে ঘোষণা আসে: প্রকল্পের মনোযোগ যাবে CentOS Stream-এ, যা RHEL-এর পরবর্তী release-এর ঠিক আগের ধারায় থাকে। CentOS Linux 8 শেষ হয় ২০২১ সালের শেষে, প্রত্যাশার অনেক আগে। CentOS Linux 7 শেষ হয় ২০২৪ সালের মাঝামাঝি।
ব্যবহারকারীদের ক্ষোভের কারণ শুধু কারিগরি ছিল না। তাঁদের পরিকল্পনা একটি প্রতিশ্রুতির ওপর দাঁড়িয়ে ছিল, আর সেই প্রতিশ্রুতি বদলে গেল। এরপর সম্প্রদায় থেকে আসে Rocky Linux আর AlmaLinux. ২০২৩ সালে Red Hat source প্রকাশের নিয়মে আরও পরিবর্তন আনে, আর এই প্রকল্পগুলোকে আবার পথ বদলাতে হয়। বিস্তারিত সময়ের সাথে বদলাচ্ছে, তাই সর্বশেষ অবস্থা তাদের নিজেদের ঘোষণায় দেখুন।
একজন প্রকৌশলীর জন্য শিক্ষাগুলো হলো:
- End of life-এর তারিখ লিখে রাখুন। প্রতিটি image আর OS-এর মেয়াদ একটি তালিকায় থাকুক। পর্ব ৩৫-এর governance-এর সাথে এটি মেলে।
- বিনামূল্যের ঝুঁকিও হিসাব করুন। কে এটি চালায়, তাদের অর্থ কোথা থেকে আসে, আর কে দায় নেয়।
- সরে যাওয়ার খরচ কম রাখুন। Server যদি IaC আর image pipeline দিয়ে বানানো থাকে, তবে OS বদলানো একটি পরিকল্পিত কাজ। হাতে গড়া server হলে সেটি বছরের ঝুঁকি।
- ঘন ঘন আপগ্রেডের অভ্যাস রাখুন। দশ বছরে একবার করা কাজ কেউ ভালো পারে না।
মূল উপলব্ধি: Distribution বাছাই একটি প্রযুক্তিগত সিদ্ধান্তের চেয়েও বেশি কিছু, এটি একটি দীর্ঘমেয়াদি নির্ভরতা। প্রতিশ্রুতি বদলাতে পারে, তাই এমনভাবে নির্মাণ করুন যাতে বদলানোর ক্ষমতা আপনার হাতেই থাকে।
প্র ০৫Production server-এ স্বয়ংক্রিয় update চালু রাখা উচিত, নাকি সব হাতে যাচাই করে বসানো উচিত?
দুই দিকেই ইতিহাস আছে। ২০১৭ সালে Equifax-এর তথ্য ফাঁসের সরকারি প্রতিবেদনে বলা হয়, Apache Struts-এর একটি জানা ত্রুটির সংশোধন মার্চে প্রকাশিত হলেও কিছু system-এ তা বসানো হয়নি, আর সেই পথেই পরের মাসগুলোতে অনুপ্রবেশ ঘটে। এখানে দেরিই ক্ষতি করেছে। অন্যদিকে ২০২৪ সালের জুলাইয়ে CrowdStrike-এর একটি ত্রুটিপূর্ণ content update বিশ্বজুড়ে বিপুল সংখ্যক Windows যন্ত্র একসাথে অচল করে দেয়। এখানে একসাথে সবখানে স্বয়ংক্রিয়ভাবে পৌঁছানোই ক্ষতি করেছে, যদিও ঘটনাটি Linux package-এর ছিল না।
তাই উত্তর “হ্যাঁ” বা “না” নয়। আসল প্রশ্ন: ঝুঁকি কতটা, আর একসাথে কতটা ছড়াবে?
- নিরাপত্তা-সংশোধন আর feature আলাদা। LTS-এর security ধারায় পরিবর্তন ছোট রাখা হয়, তাই সেটি স্বয়ংক্রিয় করা তুলনামূলক কম ঝুঁকির। সব package-এর সব upgrade স্বয়ংক্রিয় করা আলাদা কথা।
- ধাপে ধাপে ছড়ান। আগে test পরিবেশ, তারপর অল্প কিছু server, তারপর বাকি। একই সময়ে সব server-এ নয়। পর্ব ৫৯-এর canary ভাবনা এখানেও খাটে।
- Immutable পথ। চলমান server বদলানোর বদলে নতুন patch-সহ image বানিয়ে, পরীক্ষা করে, পুরোনো server ধীরে সরিয়ে দিন। এতে update আর deployment এক হয়ে যায়।
- Reboot-এর পরিকল্পনা। live patch ব্যবস্থা না থাকলে kernel patch reboot ছাড়া কাজ করে না। একাধিক server আর load balancer থাকলে একটি একটি করে reboot করা যায়, ব্যবহারকারী টের পান না।
- ফেরার পথ। Snapshot, আগের image, আর monitoring, যাতে সমস্যা দ্রুত দেখা যায়।
একটি একা server-এর ছোট প্রকল্পে উত্তর সাধারণত সহজ: নিরাপত্তা update চালু রাখুন, কারণ হাতের কাজ বাস্তবে প্রায়ই ভুলে যাওয়া হয়। বড় fleet-এ update একটি নিয়ন্ত্রিত pipeline.
মূল উপলব্ধি: Update না করার ঝুঁকি আর update করার ঝুঁকি, দুটোই আসল। ভালো ব্যবস্থা update-কে নিয়মিত, ছোট, ধাপে ধাপে আর ফেরানো যায় এমন বানায়।
অনুশীলন
প্রথম দুটি খাতায় করুন, তারপর পাতার কোড-রানারে মিলিয়ে নিতে পারেন। কোনো cloud account লাগবে না।
-
হাতে হিসাব: (ক)
rw-r-x--x-এর octal কত? (খ) umask007-এ নতুন ফাইল আর directory-র mode কত? (গ) একটি/srvগাছে এমন সব ফাইল খোঁজারfindকমান্ড লিখুন, যেগুলোতে group বা other লিখতে পারে।(ক) owner rw- = ৪+২ = ৬; group r-x = ৪+১ = ৫; other --x = ১. উত্তর
651.(খ) ফাইল:
666 & ~007 = 660. Directory:777 & ~007 = 770.(গ)
find /srv -type f -perm /022./মানে বলা বিটগুলোর যেকোনো একটি থাকলেই চলবে।-perm -022লিখলে দুটি বিটই থাকতে হতো, তাই শুধু group লিখতে পারে এমন ফাইল বাদ পড়ত। -
ফল আগে বলুন: একটি খালি ফোল্ডারে এই কমান্ডগুলো পরপর চলল। শেষে
aআরd-এর mode কত হবে? প্রথমে নিজে হিসাব করুন।umask 026 touch a mkdir d chmod g+w,o-r a chmod u=rwx,go= d stat -c '%a %n' a dআউটপুট:
660 a 700 dtouch:666 & ~026 = 640.mkdir:777 & ~026 = 751.a-তে g+w যোগ হলো (660); other-এর r আগেই বন্ধ ছিল, তাইo-rকিছু বদলায়নি।d-তেu=rwx,go=আগের মান মুছে একদম নতুন করে বসাল:700.=চিহ্ন বদলায়,+আর-শুধু যোগ বা বাদ দেয়। -
সমালোচনা করুন: সহকর্মী একটি কাল্পনিক অনলাইন বাজার অ্যাপের জন্য এই setup দিলেন: app চলে root হিসেবে;
chmod -R 777 /var/www/app;.envফাইল644; SSH-এ password login চালু; ৮ মাস কোনো update নেই। সমস্যাগুলো গুরুত্ব অনুসারে সাজান, আর প্রতিটির সমাধান বলুন।- ৮ মাস update নেই, আর password login: এগুলোই বাইরে থেকে সবচেয়ে সহজ পথ। সাথে সাথে update, শুধু key দিয়ে SSH, আর স্বয়ংক্রিয় নিরাপত্তা update.
- App root হিসেবে: app-এ একটি ত্রুটি মানেই পুরো server.
webappservice account বানান। 777: যে কেউ, এমনকি app নিজে, code বদলাতে পারে। Code থাকবেroot:webapp, ফাইল640, directory750; শুধু upload-এর ফোল্ডারে app লিখতে পারবে।.env644: server-এর যেকোনো user password পড়তে পারে।root:webapp 640করুন। ফাইলটি যদি আগে উন্মুক্ত ছিল, তবে ভেতরের secret বদলে ফেলুন (পর্ব ৩৩).
ক্রমটি বিতর্কের বিষয় হতে পারে, তবে মূল কথা: বাইরে থেকে পৌঁছানো যায় এমন ঝুঁকি আগে, ভেতরের স্তরগুলো পরে।
-
নকশা করুন:
deployuser code আপডেট করে,webappservice সেই code চালায়, আর ব্যবহারকারীর upload জমা হয়। Code, config, upload আর log-এর জন্য owner, group আর mode ঠিক করুন, যাতে app নিজের code বদলাতে না পারে।Path Owner:group Mode কারণ /srv/appdeploy:webappdir 750, ফাইল640deployলেখে, app শুধু পড়ে/etc/webapp/app.envroot:webapp640Secret, app শুধু পড়ে /var/lib/webapp/uploadswebapp:webapp750App লেখে; আলাদা disk হলে noexec,nosuidদিয়ে mount করা ভালো/var/log/webappwebapp:adm750App লেখে, admin দল পড়ে এতে app-এর ত্রুটি কাজে লাগিয়ে কেউ code বদলাতে পারবে না, আর upload-এ রাখা ফাইল চালানোও কঠিন হবে।
deploy-কে sudo-তে শুধুsystemctl restart webappদিন। group-এর নাম distribution-ভেদে আলাদা হতে পারে।
নিজেকে যাচাই করুন
ভুল হলে কারণসহ ব্যাখ্যা পাবেন, আবার চেষ্টাও করতে পারবেন।
ক্রমapt update থেকে চালু service পর্যন্ত ধাপগুলো সঠিক ক্রমে সাজান (▲▼ চেপে সরান)
- Repository থেকে স্বাক্ষরিত তালিকা আনা ও স্বাক্ষর যাচাই
- Dependency হিসাব করে পরিকল্পনা বানানো
.debফাইল download করে hash মেলানোdpkgদিয়ে ফাইল disk-এ বসানোpostinstscript চালানো, service চালু হওয়া
umask 027 থাকলে একটি প্রোগ্রাম mode 666 চেয়ে নতুন ফাইল বানাল। ফাইলের mode কত হবে?
644637640750
ফাইলটির mode ----r--r--, মালিক rahim. rahim (root নন) ফাইলটি পড়তে চাইলে কী হবে?
- পড়তে পারবেন, কারণ other-এর r আছে
- পড়তে পারবেন না, কারণ শুধু owner-বিট দেখা হয়
- পড়তে পারবেন, কারণ group-এর r আছে
- ফাইলটি মুছে যাবে
একটি Linux server-এর disk হঠাৎ ভরে গেছে। প্রথমে কোন জায়গায় খোঁজা সবচেয়ে যুক্তিসঙ্গত?
/proc/etc/usr/bin/var, বিশেষ করে/var/logআর/var/lib
Debian ধরনের repository-তে apt কীভাবে নিশ্চিত হয় যে একটি .deb ফাইল পথে বদলে যায়নি?
- স্বাক্ষরিত তালিকার hash-এর সাথে ফাইলের hash মিলিয়ে
- শুধু HTTPS ব্যবহার করে
- ফাইলের নাম আর আকার মিলিয়ে
- ফাইলটি চালিয়ে দেখে
একটি web app-এর জন্য nologin shell-সহ আলাদা service account বানানোর প্রধান কারণ কী?
- App দ্রুত চলে
- Disk-এর জায়গা বাঁচে
- App-এর ত্রুটির ক্ষতি সেই account-এর সীমিত অনুমতিতে আটকে রাখা
- App-কে root-এর সব ক্ষমতা দেওয়া
df -h দেখাচ্ছে disk ৪০% ভরা, তবু নতুন ফাইল বানাতে গেলে No space left on device আসছে। পরের কাজ কী?
- Server reboot করা
df -iদিয়ে inode-এর ব্যবহার দেখাchmod -R 777চালানোapt updateচালানো
শব্দকোষ
লেখার মধ্যে ডটেড দাগ দেওয়া শব্দে মাউস রাখুন বা চাপুন, অর্থ দেখাবে। এই পর্বের সব নতুন শব্দ এখানে একসাথে:
মনে রাখুন
- Distribution বাছাই মানে support-এর সময় বাছাই; server-এ সাধারণত LTS, আর end of life-এর তারিখ লিখে রাখুন।
/etcconfig,/usrপ্রোগ্রাম,/varবাড়তে থাকা ডেটা,/tmpসাময়িক,/prockernel-এর তথ্য।- Kernel একটিমাত্র শ্রেণি বেছে সেই বিটই মেলায়, আর পথের প্রতিটি directory-তে x লাগে। umask হলো
AND NOT, বিয়োগ নয়। - মানুষ নিজের নামে, app নিজের service account-এ; root দিয়ে সরাসরি login নয়,
chmod 777নয়। - স্বাক্ষরিত repository, স্বয়ংক্রিয় নিরাপত্তা update, নজরে রাখা disk, আর প্রথম ঘণ্টায় hardening.
আরও পড়ুন · ABCL TECH-এ আপনার পরবর্তী পদক্ষেপ
- পর্ব ০৯ · Ops-এর shell — pipe, grep, awk, sed আর log বিশ্লেষণপরবর্তী পর্বলেখা আর log নিয়ে কাজ করার হাতিয়ার।
- ক্লাউড কম্পিউটিং ও DevOps · কোর্স হোম৮১টি পর্বপুরো কোর্সের রোডম্যাপ।
- পর্ব ০৭ · DevOps আর SREআগের পর্বযে দল বানায়, সে-ই চালায়: এই মডিউলের কারণ।
- Linux permissionগভীরে যানUID, directory-র rwx, setuid আর sudo-র পূর্ণ তত্ত্ব।
- File concept আর access methodগভীরে যানফাইল, inode আর open-file table.