SSD Nodes Learn 🎉 VPS $5.50/মাস থেকে
নির্দেশিকা Matt Connorদ্বারা Matt Connor

সার্ভারে ব্যবহারকারীর কমান্ড অডিট করার সঠিক উপায়

Shell history অডিট ট্রেইল হিসেবে নিরাপদ নয়। sudo লগিং, সেশন রেকর্ডিং, শেল হুক এবং auditd execve রুলস ব্যবহার করে কীভাবে সার্ভারের কমান্ড লগগুলো সুরক্ষিতভাবে সংরক্ষণ করবেন তা জানুন।

সার্ভারে ব্যবহারকারীরা কী কী কমান্ড চালিয়েছেন তা আসলে কীভাবে রেকর্ড করা হয়

আপনার সার্ভারে ব্যবহারকারীরা কোন কমান্ডগুলো চালিয়েছেন তা অডিট করার জন্য এমন একটি রেকর্ড প্রয়োজন যা ব্যবহারকারী নিজে পরিবর্তন করতে পারেন না। Shell history এই ধরনের রেকর্ড নয়। এটি কেবল একটি সুবিধাজনক ফাইল, যার মালিকানা সেই অ্যাকাউন্টেরই থাকে যে এটি তৈরি করেছে। যে কেউ সেই শেলে টাইপ করতে সক্ষম, সে চাইলে এটি বন্ধ করে দিতে পারে বা মুছে ফেলতে পারে।

চারটি স্তর প্রকৃত রেকর্ড রাখতে পারে এবং প্রতিটিরই কিছু সীমাবদ্ধতা বা খরচ আছে। sudo প্রতিটি কমান্ডের জন্য syslog-এ একটি লাইন লেখে। sudo I/O logging একটি অ্যাকাউন্টের পুরো সেশন ক্যাপচার করে। PROMPT_COMMAND-এর মতো একটি shell hook একজন interactive bash ব্যবহারকারী কী টাইপ করেছেন তা লগ করে। কার্নেল অডিট সাবসিস্টেম সরাসরি execve syscall রেকর্ড করে, আর এই কারণেই এটিই একমাত্র স্তর যা প্রতিটি প্রসেসকে দেখতে পায়। এই নির্দেশিকাটি সেই ধাপগুলো পর্যায়ক্রমে আলোচনা করবে, প্রতিটি স্তরের সীমাবদ্ধতা জানাবে এবং সবশেষে সেই গুরুত্বপূর্ণ অংশে শেষ হবে যা নির্ধারণ করে যে এই রেকর্ডগুলোর কোনো মূল্য আছে কি না: অডিট করা ব্যক্তি রেকর্ডগুলো মুছে ফেলার আগেই সেগুলোকে মেশিন থেকে সরিয়ে ফেলা।

শুরু করার আগে একটি সতর্কতা। অডিট সাবসিস্টেম কার্নেলের কাজ, তাই হোস্ট কার্নেল শেয়ার করে এমন কোনো কন্টেইনারের ভেতরে এগুলো পরীক্ষা করা সম্ভব নয়। এই কমান্ডগুলো এমন একটি KVM VPS-এ চালান যেখানে কার্নেলটি আপনার নিজস্ব।

কেন শেল হিস্ট্রি কোনো অডিট ট্রেইল নয়

~/.bash_history চারটি সাধারণ কারণে প্রমাণ হিসেবে অকার্যকর, এবং এর কোনোটির জন্যই আক্রমণকারীকে খুব চতুর হতে হয় না।

এটি ব্যবহারকারীর নিজস্ব ফাইল। ফাইলটির মোড 600 এবং এর মালিক সংশ্লিষ্ট অ্যাকাউন্টটি, তাই rm ~/.bash_history-এর জন্য কোনো বিশেষ প্রিভিলেজের প্রয়োজন হয় না। এমনকি কোনো এডিটরে ফাইলটি খুলে গুরুত্বপূর্ণ বিশটি লাইন মুছে ফেলাও খুব সহজ।

শেল বন্ধ হওয়ার সময় এটি লেখা হয়। যে সেশন kill -9 $$ দিয়ে শেষ হয়, অথবা সংযোগ বিচ্ছিন্ন হয়ে যায়, তা কোনো কিছুই রেকর্ড করে না। exit-এর আগে history -c চালালে একই ফলাফল পাওয়া যায় এবং মনে হয় যেন কিছুই ঘটেনি।

একটি শব্দেই এটি বন্ধ করা যায়। unset HISTFILE কমান্ডটি ওই সেশনের জন্য ফাইলটিতে লেখা বন্ধ করে দেয়। set +o history তাৎক্ষণিকভাবে রেকর্ডিং বন্ধ করে দেয়। HISTCONTROL=ignorespace কমান্ডটি শুরুতে একটি স্পেস দিয়ে টাইপ করা যেকোনো কমান্ডকে লুকিয়ে ফেলে। এই সবকিছুই man bash-এর অংশ, কারণ এটি ব্যবহারকারীর নিয়ন্ত্রণে থাকার জন্যই তৈরি।

এটি কী টাইপ করা হয়েছে তা রেকর্ড করে, কী রান করেছে তা নয়। কোনো অ্যালিয়াস বা শেল ফাংশন থাকলে ফাইলে থাকা টেক্সটটি সেই প্রোগ্রাম নয় যা কার্নেল আসলে এক্সিকিউট করেছে।

এতে কোনো টাইমস্ট্যাম্পও থাকে না, যদি না এন্ট্রিটি লেখার সময় HISTTIMEFORMAT সেট করা থাকে, কারণ bash তার #1755043200 মার্কার লাইনগুলো কেবল তখনই লেখে যখন সেই ভেরিয়েবলটি সেট করা থাকে।

শেয়ারড লগইনের ক্ষেত্রে এটি কে কাজ করেছে তাও বলতে পারে না। তিনজন মানুষ একটি deploy অ্যাকাউন্ট ব্যবহার করলে একটি ইউআইডি (uid)-এর অধীনে একটি ইন্টারলিভড ফাইল তৈরি হয়। যখন দুইজন মানুষ একটি ইউআইডি শেয়ার করে, তখন কোনো লগিং লেয়ারই কোনো কাজকে নির্দিষ্ট ব্যক্তির সাথে যুক্ত করতে পারে না, যা শেয়ারড লগইনের পরিবর্তে প্রতি ব্যক্তির জন্য আলাদা আনপ্রিভিলেজড অ্যাকাউন্ট ব্যবহারের বাস্তবসম্মত যুক্তি।

শেল হিস্ট্রি তার আসল কাজের জন্য ভালো, যা হলো গতকালের কমান্ডটি পুনরায় টাইপ করতে সাহায্য করা। এটিকে কেবল একটি ইঙ্গিত হিসেবে ব্যবহার করুন। কখনোই এটিকে প্রমাণ হিসেবে উপস্থাপন করবেন না।

sudo কী লগ করে এবং এটি কোথায় থেমে যায়

sudo তার চালানো প্রতিটি কমান্ডের একটি লাইন authpriv syslog ফ্যাসিলিটিতে পাঠায়।

sudo grep 'sudo:' /var/log/auth.log | tail -5
journalctl -t sudo -n 5

প্রতিটি লাইনে ব্যবহারকারীর নাম, টার্মিনাল, ওয়ার্কিং ডিরেক্টরি, টার্গেট ব্যবহারকারী এবং কমান্ডের নাম উল্লেখ থাকে:

sudo:    alice : TTY=pts/0 ; PWD=/home/alice ; USER=root ; COMMAND=/usr/bin/apt update

যদি /var/log/auth.log বিদ্যমান না থাকে, তবে সেই ইমেজে rsyslog ইনস্টল করা নেই এবং একই রেকর্ডগুলো শুধুমাত্র journal-এ থাকে। journal-এর ওপর নির্ভর করার আগে নিশ্চিত হয়ে নিন যে এটি volatile নয়:

journalctl --list-boots

শুধুমাত্র বর্তমান বুট তালিকাভুক্ত থাকার অর্থ হলো /var/log/journal বিদ্যমান নেই, তাই journal /run-এ থাকে এবং প্রতিটি লাইন পরবর্তী রিবুটের সময় মুছে যায়। এটিকে persistent করুন:

sudo mkdir -p /var/log/journal
sudo systemd-tmpfiles --create --prefix /var/log/journal
sudo systemctl restart systemd-journald

এখন সীমাবদ্ধতার বিষয়টি দেখুন। sudo শুধুমাত্র সেই কমান্ডটি লগ করে যা তাকে চালানোর জন্য অনুরোধ করা হয়েছে। সেই কমান্ডটি পরবর্তীতে কী কাজ করে তা এটি লগ করে না। তাই একটি লাইনই ট্রেইল বা অনুসন্ধানের শেষ সীমা:

sudo -i

লগটি শেলের জন্য একটি মাত্র রেকর্ড পায়। সেই রুট শেলের ভেতরে টাইপ করা প্রতিটি কমান্ড sudo-এর কাছে অদৃশ্য থাকে, কারণ sudo তখন আর পাথে (path) থাকে না। sudo su -, sudo bash এবং sudo vim /etc/shadow এর পরে :!bash ব্যবহার করলে সবগুলোর গঠন একই রকম হয়। একটি sudoers রুল যা শেল এস্কেপসহ যেকোনো প্রোগ্রামকে অনুমতি দেয়, যেমন vim বা find, তা মূলত এমন একটি রুল যা আনলগড রুট অ্যাক্সেস প্রদান করে। কোনো অ্যাকাউন্টের লগ লাইনের ওপর আস্থা রাখার আগে দেখুন সেই অ্যাকাউন্টটি আসলে কী কী অ্যাক্সেস করতে পারে:

sudo -l -U alice

একটি অ্যাকাউন্টের জন্য সম্পূর্ণ সেশন রেকর্ড করা

প্রথমে আপনার কোন sudo সংস্করণটি আছে তা খুঁজে বের করুন, কারণ Rust-এ নতুন করে লেখা সংস্করণে এই সুবিধাটি নেই:

sudo --version | head -1

যদি আউটপুটে sudo-rs নাম আসে, তবে এই অংশটি এড়িয়ে যান এবং audit সাবসিস্টেম ব্যবহার করুন। Ubuntu-এর 25.10 এবং 26.04 রিলিজের নিজস্ব ডকুমেন্টেশনে I/O লগিং এবং sudoreplay সমর্থিত নয় বলে উল্লেখ করা হয়েছে, এবং 2026 সালের আগস্ট পর্যন্ত এটি অপরিবর্তিত ছিল। এটি গুরুত্বপূর্ণ কারণ এই রিলিজগুলোতে sudo-rs হলো ডিফল্ট sudo, তাই আপগ্রেড করলে আপনার পূর্বের নিয়ন্ত্রণ ব্যবস্থাটি মুছে যেতে পারে। sudo-ভিত্তিক লগিং পরিকল্পনা করার আগে sudo-rs-এর আচরণের সম্পূর্ণ তালিকা পড়ে নেওয়া জরুরি।

মূল sudo-এর সাথে, যা Ubuntu 24.04 LTS-এ এখনো দেওয়া হয়, একটি অ্যাকাউন্টের জন্য I/O লগিং চালু করুন:

sudo visudo -f /etc/sudoers.d/iolog
Defaults:deploy log_output
Defaults!/usr/bin/sudoreplay !log_output

এডিটর ব্যবহার না করে visudo ব্যবহার করুন, কারণ এটি এমন কোনো ফাইল সংরক্ষণ করতে দেয় না যা পার্স করা সম্ভব নয়। একটি ত্রুটিপূর্ণ sudoers ফাইল সবাইকে sudo থেকে বিচ্ছিন্ন করে দিতে পারে। এরপর একটি সেশন রিপ্লে করুন:

sudo sudoreplay -l user=deploy
sudo sudoreplay 000001

sudoreplay -l সেশনগুলোকে তাদের ID সহ তালিকাভুক্ত করে, আর যদি log_output সেই ব্যবহারকারীর ক্ষেত্রে কখনো প্রয়োগ না করা হয়ে থাকে তবে এটি কিছুই প্রদর্শন করবে না। এর খরচ: টার্মিনালের মধ্য দিয়ে যাওয়া প্রতিটি বাইট /var/log/sudo-io-এর অধীনে সংরক্ষিত হয়, তাই একটি দীর্ঘ সেশন অনেক বড় জায়গা নিতে পারে। দ্বিতীয় sudoers লাইনটি রিপ্লে চলাকালীন পুনরায় রেকর্ড হওয়া বন্ধ করে। আসল ঝুঁকি হলো গোপনীয় তথ্য, কারণ একটি I/O লগে যা কিছু টাইপ করা বা প্রিন্ট করা হয় তা জমা থাকে, যার মধ্যে সেশনের ভেতরে প্রম্পটে টাইপ করা পাসওয়ার্ডও অন্তর্ভুক্ত। তাই এটিকে পাসওয়ার্ড স্টোরের মতোই সুরক্ষিত রাখা প্রয়োজন। এর আওতাও সীমিত। এটি শুধুমাত্র sudo-এর মাধ্যমে চালানো কমান্ডগুলোই দেখতে পায়। কেউ যদি লগ-ইন করে সম্পূর্ণ নিজের পরিচয়ে কাজ করে, তবে তার কোনো কিছুই রেকর্ড হয় না।

Shell hooks এবং এগুলো যেভাবে বাইপাস করা হয়

"প্রতিটি কমান্ড লগ করুন" এই উদ্দেশ্যে বহুল প্রচলিত পদ্ধতি হলো PROMPT_COMMAND হুক, যা /etc/profile.d/ ফাইলে রাখা হয়:

# /etc/profile.d/00-cmdlog.sh
PROMPT_COMMAND='logger -p local6.info -t cmdlog "$(whoami) $$ $(history 1 | sed "s/^ *[0-9]* *//")"'

bash প্রতিটি প্রম্পট দেখানোর আগে PROMPT_COMMAND রান করে, তাই কমান্ড টাইপ করার সাথে সাথেই তা syslog-এ পৌঁছে যায়, সেশন শেষ হওয়ার জন্য অপেক্ষা করতে হয় না। এছাড়া logger সিস্টেম লগ ডেমনের মাধ্যমে লেখা হয়, তাই ব্যবহারকারীর নিজস্ব ফাইল পারমিশন এখানে কোনো বাধা সৃষ্টি করে না। একটি নতুন লগইন শেল খুলুন এবং sudo tail -f /var/log/syslog দিয়ে যাচাই করুন, অথবা rsyslog নেই এমন ইমেজের ক্ষেত্রে journalctl -t cmdlog -f ব্যবহার করুন।

তবে এটি পাঁচটি উপায়ে কাজ করা বন্ধ করে দেয়, যার প্রতিটি আপনি এক মিনিটের মধ্যে পরীক্ষা করতে পারবেন।

  • নন-ইন্টারেক্টিভ শেল কখনোই প্রম্পট দেখায় না। ssh you@server 'id' কমান্ডটি রান করে ফিরে আসে এবং কিছুই লগ হয় না, কারণ PROMPT_COMMAND কখনোই ইভালুয়েট হয়নি।
  • এটি একটি ভেরিয়েবল। unset PROMPT_COMMAND সেশনের বাকি সময়ের জন্য এটিকে নিষ্ক্রিয় করে দেয় এবং এর জন্য কোনো প্রিভিলেজের প্রয়োজন হয় না।
  • ফাইলটি শুধুমাত্র লগইন শেল দ্বারা পড়া হয়। bash --noprofile --norc কখনোই /etc/profile.d/ সোর্স করে না।
  • এটি শুধুমাত্র bash-এর জন্য নির্দিষ্ট। vim-এর ভেতরে zsh, sh, python3 -c 'import os; os.system("id")' এবং :!id এমন সব প্রোগ্রাম রান করে যা কোনো bash প্রম্পট হুক দেখতে পায় না।
  • এটি টাইপ করা লাইনটি লগ করে, তাই কোনো alias বা function ব্যবহার করলে প্রকৃত কমান্ডটি আড়ালেই থেকে যায়।

Shell hook-কে শুধুমাত্র সুবিধার জন্য ব্যবহার করুন। এটি সহযোগিতামূলক ব্যবহারকারীদের ক্ষেত্রে "গত মঙ্গলবার আমি কী চালিয়েছিলাম" প্রশ্নের উত্তর দেয়। কোনো চেকলিস্টে এটিকে নিয়ন্ত্রণ ব্যবস্থা (control) হিসেবে গণ্য করবেন না।

কার্নেল অডিট সাবসিস্টেম প্রতিটি execve পর্যবেক্ষণ করে

Linux অডিট সাবসিস্টেম, যা auditd ডেমনের মাধ্যমে পরিচালিত হয়, এটিই একমাত্র স্তর যা কোনো ব্যবহারকারী এড়িয়ে যেতে পারে না। কারণ syscall চলার মুহূর্তে কার্নেলের ভেতরেই রেকর্ডটি তৈরি হয়। কোনো প্রসেস যদি একটি প্রোগ্রাম এক্সিকিউট করে, তবে একটি ইভেন্ট তৈরি হবেই। শেল, প্রোগ্রামিং ল্যাঙ্গুয়েজ বা টার্মিনালের উপস্থিতি এখানে কোনো পার্থক্য তৈরি করে না।

sudo apt update && sudo apt install -y auditd audispd-plugins
sudo systemctl enable --now auditd
sudo auditctl -s

auditctl -s কমান্ডটি ডেমনের অবস্থা প্রদর্শন করে। enabled 1-এর মান যদি শূন্য না হয় এবং pid-এর মান থাকে, তবে বুঝতে হবে এটি চলছে। lost 0 নির্দেশ করে যে এখন পর্যন্ত কোনো রেকর্ড বাদ পড়েনি। lost কাউন্টারটি মনে রাখুন, এটি পরবর্তীতে কাজে লাগবে।

auid হলো সেই ফিল্ড যা অডিটকে কার্যকর করে তোলে। সেশন শুরু হওয়ার সময় PAM একটি login uid সেট করে এবং এরপর থেকে কার্নেল প্রতিটি চাইল্ড প্রসেসের ক্ষেত্রে এটি বহন করে। আপনারটি পরীক্ষা করুন:

cat /proc/self/loginuid

একটি ইন্টারঅ্যাক্টিভ SSH সেশন আপনার uid প্রিন্ট করে, কারণ /etc/pam.d/sshd-এর মধ্যে pam_loginuid.so অন্তর্ভুক্ত থাকে। 4294967295 মানের অর্থ হলো loginuid কখনো সেট করা হয়নি, যা বুট করার সময় সিস্টেম ডেমনের মাধ্যমে শুরু হওয়া প্রসেসের জন্য স্বাভাবিক। গুরুত্বপূর্ণ বিষয় হলো, sudo -i এটি পরিবর্তন করে না: alice-এর খোলা একটি root শেল-এও auid 1000 থাকে, তাই এর ভেতরের প্রতিটি কমান্ড alice-এর নামে চিহ্নিত করা যায়। sudo ব্যবহারের ক্ষেত্রে ঠিক এই ফাঁকটিই থেকে যায়। একবার সেট হয়ে গেলে loginuid পরিবর্তন করতে CAP_AUDIT_CONTROL প্রয়োজন, যা সাধারণ ব্যবহারকারীদের থাকে না। এমনকি root-এর জন্যও পরবর্তী রিবুট পর্যন্ত sudo auditctl --loginuid-immutable এই সুযোগ বন্ধ করে দেয়।

নিশ্চিত করুন যে /etc/pam.d/sshd, /etc/pam.d/login এবং /etc/pam.d/cron প্রতিটির মধ্যে pam_loginuid.so অন্তর্ভুক্ত আছে, অন্যথায় ইভেন্টগুলো কোনো ব্যবহারকারীর তথ্য ছাড়াই আসবে। এটি সেই একই ফাইল তালিকা যা আপনি VPS-এ SSH অ্যাক্সেস হার্ডেনিং করার সময় পরিবর্তন করেন, তাই কাজ দুটি একসাথে সম্পন্ন করুন।

auditd-এর জন্য একটি প্রাথমিক রুল সেট

রুলগুলো /etc/audit/rules.d/*.rules ডিরেক্টরিতে থাকে। augenrules ফাইলনামের ক্রমানুসারে সেগুলোকে একটি তালিকায় যুক্ত করে এবং এই ক্রমই আচরণ নির্ধারণ করে, কারণ কার্নেল প্রথম মিলে যাওয়া রুলটিতেই থেমে যায়। নতুন কিছু যোগ করার আগে সেখানে কী আছে তা পড়ে দেখুন, কারণ পরবর্তী কোনো ফাইলে থাকা -D তার আগে লোড হওয়া সবকিছু মুছে ফেলে।

ls /etc/audit/rules.d/
cat /etc/audit/rules.d/audit.rules

এরপর /etc/audit/rules.d/50-exec.rules লিখুন:

## Suppressions first: the kernel takes the first matching rule.
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-deb
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-query
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-split
-a never,exit -F arch=b64 -S execve -F exe=/usr/bin/dpkg-trigger

## Every program started by a logged-in human.
-a always,exit -F arch=b64 -S execve,execveat -F auid>=1000 -F auid!=unset -k exec
-a always,exit -F arch=b32 -S execve,execveat -F auid>=1000 -F auid!=unset -k exec

## Changes to who may become root.
-w /etc/sudoers -p wa -k sudoers
-w /etc/sudoers.d/ -p wa -k sudoers
-w /etc/passwd -p wa -k identity
-w /etc/shadow -p wa -k identity
-w /etc/group -p wa -k identity

## Changes to the audit configuration itself.
-w /etc/audit/ -p wa -k auditconfig

এটি লোড করুন এবং নিশ্চিত করুন:

sudo augenrules --load
sudo auditctl -l

auditctl -l আপনার রুলগুলো প্রিন্ট করছে মানে সেগুলো কার্যকর আছে। No rules মানে লোড ব্যর্থ হয়েছে এবং journalctl -u auditd -n 20 সেই ফাইল ও লাইনের নাম জানায় যা পার্সার প্রত্যাখ্যান করেছে। পুরনো audit userspace unset কিওয়ার্ডটি বোঝে না। যদি লোডার সেই ফিল্ডটি নিয়ে অভিযোগ করে, তবে তার পরিবর্তে -F auid!=4294967295 লিখুন, যা একই মান নির্দেশ করে।

এখন ইভেন্টগুলো পড়ুন:

sudo ausearch -k exec -ts recent -i | tail -40
sudo ausearch -ul 1000 -ts today -i
sudo aureport -k --summary -i

-i ইউজার আইডি (uid) এবং সিস্টেম কল নম্বরগুলোকে নামে রূপান্তর করে, এবং বাস্তবে এটি ঐচ্ছিক নয়। -ts recent গত দশ মিনিটের তথ্য কভার করে। প্রতিটি এক্সিকিউশন রেকর্ডের একটি গ্রুপ হিসেবে আসে: একটি SYSCALL রেকর্ড যাতে uid, auid, exit status এবং key থাকে, একটি EXECVE রেকর্ড যাতে সম্পূর্ণ আর্গুমেন্ট লিস্ট থাকে, এবং প্রসঙ্গের জন্য CWDPATH রেকর্ড থাকে।

একটি বাস্তব সীমাবদ্ধতা, কারণ এটি অনেককে বিভ্রান্ত করে। audit সিস্টেম কল রেকর্ড করে, আর শেল বিল্ট-ইন কোনো নিজস্ব সিস্টেম কল তৈরি করে না। cd /root কোনো প্রোগ্রাম চালায় না। bash প্রম্পটে টাইপ করা echo evil >> /etc/passwd-ও কোনো প্রোগ্রাম চালায় না, কারণ echo এবং রিডাইরেক্ট উভয়ই ইতিমধ্যে চলমান শেল প্রসেসের ভেতরেই ঘটে। তাই execve রুলগুলো প্রোগ্রাম দেখে এবং -w রুলগুলো রাইট (write) অপারেশন দেখে। কোনোটিই একা যথেষ্ট নয়।

পরিশেষে, কনফিগারেশন লক করুন:

## /etc/audit/rules.d/99-finalize.rules
-e 2

-e 2 পরবর্তী রিবুট পর্যন্ত রুল সেটকে অপরিবর্তনীয় (immutable) করে তোলে। এটি লোড হওয়ার পর, auditctl -s রিপোর্ট করে enabled 2, এবং রুট ইউজারসহ যে কেউ রুল যোগ বা মুছে ফেলার চেষ্টা করলে তা Operation not permitted এর মাধ্যমে ব্যর্থ হবে। এই ফাইলটি সবার শেষে যোগ করুন এবং রুল পরিবর্তনের জন্য প্রতিবার রিবুট করার প্রস্তুতি রাখুন। এই বিনিময়টিই মূল উদ্দেশ্য: যে রুল সেট যে কেউ গোপনে বন্ধ করে দিতে পারে, তা কোনো প্রমাণ হিসেবে গণ্য হয় না।

যে অডিট লগ কেউ পড়ে না তা কেবল একটি কমপ্লায়েন্সের দলিল

auditd-এর ব্যর্থতার কারণ এটি নয় যে এটি কোনো কিছু মিস করে। বরং এটি এত বেশি তথ্য রেকর্ড করে যে কেউ তা আর দেখে না, ফলে লগটি কোনো প্রশ্নের উত্তর দেওয়ার পরিবর্তে কেবল একটি চেকলিস্ট পূরণ করার কাজে ব্যবহৃত হয়।

কোনো কিছু টিউন করার আগে আপনার নিজের বক্সে হিসাবটি করে নিন:

sudo aureport -k --summary -i
sudo du -sh /var/log/audit

একটি sudo apt upgrade হাজার হাজার স্বল্পস্থায়ী প্রসেস চালায় এবং প্রতিটির সাথেই আপনার auid যুক্ত থাকে, তাই একটি প্যাকেজ আপডেট এক সপ্তাহের মানুষের টাইপিংয়ের চেয়েও বেশি লগ তৈরি করতে পারে। এই কারণেই উপরের সাপ্রেশনগুলোতে dpkg এবং এর সহায়কদের নাম উল্লেখ করা হয়েছে। এক্সিকিউটেবল অনুযায়ী সাপ্রেশন করুন, কখনোই ব্যবহারকারী অনুযায়ী নয়: /usr/bin/dpkg-এর জন্য একটি এক্সক্লুশন হলো এমন একটি ছিদ্র যা আপনি এক বাক্যে বর্ণনা করতে পারবেন, কিন্তু একটি অ্যাকাউন্টের জন্য এক্সক্লুশন হলো এমন একটি ছিদ্র যা ঠিক সেই জিনিসটির আকার ধারণ করে যা আপনি ধরার চেষ্টা করছিলেন।

প্রতিটি রুলে থাকা -k কি-টিই এক মাস পরে লগটিকে অনুসন্ধানযোগ্য করে তোলে। ausearch -k sudoers হলো উত্তরের অপেক্ষায় থাকা একটি প্রশ্ন। ফিল্টার ছাড়া ausearch হলো টেক্সটের একটি দেয়াল যা আপনাকে লগ পড়া বন্ধ করতে বাধ্য করবে। যদি আপনার কালেক্টর নেটিভ ফরম্যাটের পরিবর্তে JSON চায়, তবে laurel হলো একটি auditd প্লাগইন যা প্রতিটি ইভেন্টকে আর্গুমেন্ট ডিকোড করা একটি JSON অবজেক্ট হিসেবে নতুন করে লেখে। এটি অন্য যেকোনো প্লাগইনের মতো /etc/audit/plugins.d/-এ রেজিস্টার হয় এবং auditd sudo pkill -HUP auditd-এ প্লাগইনের পরিবর্তনগুলো গ্রহণ করে।

auditd-এর প্রকৃত খরচ

প্রতিটি ম্যাচিং syscall একটি রেকর্ডে পরিণত হয়, যা কার্নেল ফরম্যাট করে userspace-এ পাঠায়। এর খরচ দুটি জায়গায় প্রভাব ফেলে এবং অন্য কারো প্রকাশিত তথ্যের ওপর নির্ভর না করে আপনার নিজস্ব কাজের চাপের ওপর ভিত্তি করে তা পরিমাপ করা সম্ভব।

  • CPU এবং ল্যাটেন্সি। যে মেশিনে ক্রমাগত fork হয়, যেমন build host বা CI runner, সেখানে প্রতিটি exec-এর জন্য একটি রেকর্ড তৈরি হয়। যখন কার্নেলের backlog পূর্ণ হয়ে যায়, তখন --backlog_wait_time ইভেন্ট তৈরি করা প্রসেসটিকে সাময়িকভাবে থামিয়ে দেয় যতক্ষণ না জায়গা খালি হয়। ফলে audit-এর প্রভাব CPU ব্যবহারের শতাংশের চেয়ে ধীরগতির বিল্ড হিসেবে বেশি ধরা পড়ে। প্রকৃত লোডের সময় sudo auditctl -s-এ backlog এবং lost পর্যবেক্ষণ করুন। lost বৃদ্ধি পাওয়ার অর্থ হলো রেকর্ড ড্রপ হয়েছে, আর অসম্পূর্ণ লগ থাকা লগ না থাকার চেয়েও বিপজ্জনক, কারণ আপনি ভুলবশত সেটিকে নির্ভরযোগ্য মনে করবেন।
  • ডিস্ক। /etc/audit/auditd.conf পড়ুন এবং ডিস্ক পূর্ণ হয়ে গেলে কী ঘটবে তা ভেবেচিন্তে সিদ্ধান্ত নিন, কারণ ডিফল্ট মানগুলো কেবল একটি পরামর্শ মাত্র। max_log_file, num_logs এবং max_log_file_action রোটেশন নিয়ন্ত্রণ করে। space_left_action, admin_space_left_action এবং disk_full_action জরুরি অবস্থা নিয়ন্ত্রণ করে। উপলব্ধ কিছু অ্যাকশন, যার মধ্যে halt এবং single অন্তর্ভুক্ত, রেকর্ড হারানোর চেয়ে মেশিন বন্ধ করে দেওয়াকে অগ্রাধিকার দেয়।

/etc/audit/rules.d/audit.rules ফাইলের -f লাইনটি কার্নেল পর্যায়ে একই সিদ্ধান্তের প্রতিফলন ঘটায়: -f 1 audit ব্যর্থতার রিপোর্ট syslog-এ পাঠায় এবং -f 2 কার্নেলকে panic মোডে নিয়ে যায়। 2 কেবল তখনই নির্বাচন করুন যদি আপনি রেকর্ড হারানোর চেয়ে সার্ভার বন্ধ হয়ে যাওয়াকে বেশি গ্রহণযোগ্য মনে করেন। কোনো গুরুত্বপূর্ণ VPS-এর ক্ষেত্রে রোটেশন ব্যবহার করুন এবং স্টোরেজের সমস্যাটি সার্ভারের বাইরে স্থানান্তর করুন।

লগগুলো সার্ভারের বাইরে রিয়েল-টাইমে পাঠান

ইনসিডেন্ট রিপোর্টগুলোতে বারবার এটিই প্রমাণিত হয়। যে সার্ভারটি হ্যাক হয়েছে, সেখানে লগ রেখে দিলে আক্রমণকারী তা পরিবর্তন করতে পারে। root ব্যবহারকারী /var/log/auth.log নতুন করে লিখতে পারে, /var/log/audit/audit.log মুছে ফেলতে পারে এবং ডেমোন বন্ধ করে দিতে পারে। -e 2 রুলগুলো আনলোড হওয়া থেকে আটকায়, কিন্তু rm-এর ক্ষেত্রে এটি কোনো কাজ করে না। উপরের প্রতিটি স্তর তখনই প্রমাণ রাখতে পারে যদি লগের একটি কপি আগে থেকেই মেশিন থেকে সরিয়ে নেওয়া হয়।

অডিট লগের নিজস্ব ট্রান্সপোর্টের জন্য audispd-plugins-এর audisp-remote প্লাগইন ব্যবহার করা হয়। এটি /etc/audit/plugins.d/au-remote.conf-এ চালু করুন:

active = yes
direction = out
path = /usr/sbin/audisp-remote
type = always
format = string

রিলোড করার আগে command -v audisp-remote-এর বিপরীতে path যাচাই করে নিন, কারণ ভুল পাথ থাকলে জার্নালে একটি লাইন ছাড়া আর কিছুই পাওয়া যাবে না। /etc/audit/audisp-remote.conf-এ remote_server এবং port সেট করুন এবং কালেক্টর সার্ভারে তার নিজস্ব auditd.conf-এ tcp_listen_port = 60 সেট করুন। sudo pkill -HUP auditd দিয়ে রিলোড করুন। অনেক ইমেজে systemctl restart auditd প্রত্যাখ্যান করা হয়, কারণ ইউনিট ফাইলে RefuseManualStop=yes সেট করা থাকে, তাই সিগন্যাল পাঠানোই নির্ভরযোগ্য উপায়।

অন্য বিকল্পটি হলো অডিট লগগুলোকে আপনার বিদ্যমান syslog স্ট্রিমের সাথে যুক্ত করা। active = no-এর সাথে /etc/audit/plugins.d/syslog.conf থাকে। এটিকে yes-এ সেট করে রিলোড করুন, তাহলে অডিট ইভেন্টগুলো sudo-এর লাইন এবং অন্যান্য লগের সাথে যুক্ত হবে। এরপর rsyslog ব্যবহার করে TLS (transport layer security)-এর মাধ্যমে সেগুলো পাঠিয়ে দিন, যার জন্য rsyslog-gnutls প্যাকেজটি প্রয়োজন:

# /etc/rsyslog.d/60-forward.conf
*.* action(type="omfwd"
    target="logs.example.net" port="6514" protocol="tcp"
    StreamDriver="gtls" StreamDriverMode="1"
    StreamDriverAuthMode="x509/name"
    StreamDriverPermittedPeers="logs.example.net"
    action.resumeRetryCount="-1"
    queue.type="linkedList" queue.filename="fwd" queue.saveOnShutdown="on")

কিউ (queue) সেটিংসগুলো এখানে গুরুত্বপূর্ণ। action.resumeRetryCount="-1" সবসময় রিট্রাই করতে থাকে এবং queue.saveOnShutdown="on"-সহ ডিস্ক-অ্যাসিস্টেড কিউ রেকর্ডগুলো ধরে রাখে যতক্ষণ না কালেক্টর আবার সচল হয়। এই দুটি ছাড়া, কালেক্টর রিবুট হলে আপনার প্রমাণের তথ্যে ঘাটতি তৈরি হবে এবং সেই ঘাটতি সম্পর্কে আপনি কিছুই জানতে পারবেন না। sudo systemctl restart rsyslog দিয়ে সেটিংস প্রয়োগ করুন এবং কোনো কিছুতে আস্থা রাখার আগে নিশ্চিত করুন যে রেকর্ডগুলো কালেক্টরে সঠিকভাবে পৌঁছাচ্ছে।

একটি বিষয় বাকি রয়ে গেছে: কালেক্টর এমন একটি মেশিন হতে হবে যেখানে অডিট করা ব্যক্তিরা লগইন করতে পারে না। যদি একই অ্যাডমিন গ্রুপ লগ সার্ভারের root এক্সেস পায়, তবে আপনি ফাইলটি কপি করেছেন মাত্র, সুরক্ষিত করেননি। আলাদা ক্রেডেনশিয়াল, আলাদা কি (key) এবং সম্ভব হলে আলাদা প্রোভাইডার অ্যাকাউন্ট ব্যবহার করুন। এই একই যুক্তিতে অনেকগুলো Linux সার্ভার ম্যানেজ করার একটি কেন্দ্রীয় ব্যবস্থা আগে থেকেই তৈরি রাখা জরুরি। এটিই সেই পার্থক্য যা একটি হ্যাক হওয়া VPS নিয়ে কাজ করার সময় প্রথম এক ঘণ্টাকে কার্যকর বা অকার্যকর করে তোলে।

সাধারণ ব্যবহারকারী রেকর্ড পরিবর্তন করতে পারে না তা নিশ্চিত করুন

অনুমান না করে দাবিটি পরীক্ষা করুন। কোনো sudo সুবিধা নেই এমন একটি সাধারণ অ্যাকাউন্ট থেকে:

echo test >> /var/log/auth.log
cat /var/log/audit/audit.log
auditctl -D
id -nG

পর্যায়ক্রমে এগুলো আশা করুন: Permission denied, কারণ auth.log-এর মালিক syslog এবং এর গ্রুপ adm, যার মোড 640; পুনরায় Permission denied, কারণ অডিট লগটি 600 মোডের এবং এর মালিক root; একটি ত্রুটি যা চালানোর অনুমতি দেবে না, কারণ অডিট রুল পরিবর্তনের জন্য CAP_AUDIT_CONTROL প্রয়োজন; এবং এমন একটি গ্রুপ লিস্ট যাতে adm বা systemd-journal কোনটিই নেই।

শেষের এই পরীক্ষাটিই অনেকে করতে ব্যর্থ হন। adm-এর সদস্যপদ /var/log/auth.log-এ পড়ার অনুমতি দেয় এবং systemd-journal-এর সদস্যপদ পুরো জার্নালটি পড়ার অনুমতি দেয়। কোনোটিই লেখার অনুমতি দেয় না, তাই কোনোটিই তথ্য পরিবর্তনের সুযোগ দেয় না। উভয়ই একজন ব্যক্তিকে সার্ভারের প্রতিটি অথেন্টিকেশন লাইন পড়ার সুযোগ দেয়, যা কোনো ফোরামের উত্তর থেকে usermod -aG লাইন কপি না করে বরং সচেতনভাবে সিদ্ধান্ত নিয়ে করা উচিত।

পরিশেষে, রিবুটের পরেও টিকে থাকবে এমন দুটি বিষয় নিশ্চিত করুন:

sudo auditctl -s
systemctl is-enabled auditd

enabled 2 মানে হলো রুল সেটটি পরবর্তী রিবুট পর্যন্ত লক করা আছে। দ্বিতীয় কমান্ড থেকে প্রাপ্ত enabled মানে হলো রিবুটের পর auditd পুনরায় চালু হবে। যে রুল সেট কেবল পরবর্তী কার্নেল আপডেট পর্যন্ত টিকে থাকে, তা অডিট ট্রেইল হিসেবে গণ্য হয় না।

FAQ

কোনো নির্দিষ্ট ব্যবহারকারী কী কী কমান্ড চালিয়েছেন তা কীভাবে দেখব?

প্রথমে id -u alice ব্যবহার করে তাদের uid খুঁজে বের করুন, তারপর login uid দিয়ে অডিট লগ অনুসন্ধান করুন: sudo ausearch -ul 1000 -ts today -i। execve রুল-এ সীমাবদ্ধ রাখতে -k exec যোগ করুন। login uid লগইন করার সময় সেট হয় এবং এটি susudo -i-এর পরেও টিকে থাকে, তাই ওই অ্যাকাউন্ট থেকে খোলা root shell-এ চালানো কমান্ডগুলোও এতে ধরা পড়ে। এটি শুধুমাত্র রুল লোড হওয়ার পরের কমান্ডগুলোর ক্ষেত্রেই কাজ করে, কারণ অডিট এমন কোনো ইভেন্টের ইতিহাস রাখে না যা রেকর্ড করার জন্য কনফিগার করা হয়নি। আপনি যদি আগে ডেটার ধরন দেখতে চান, তবে sudo aureport -k --summary -i ব্যবহার করে প্রতি রুলের সংখ্যা দেখে নিতে পারেন।

কোনো ব্যবহারকারী কি তাদের bash history মুছে ফেলে কী করেছেন তা লুকাতে পারেন?

হ্যাঁ, এবং এর জন্য কোনো বিশেষ প্রিভিলেজের প্রয়োজন নেই। ~/.bash_history ফাইলটির মালিকানা ওই ব্যবহারকারীর এবং এর মোড 600, তাই তারা এটি এডিট করতে, ট্রাঙ্কেট করতে বা মুছে ফেলতে পারেন। তারা unset HISTFILE ব্যবহার করে এটি লেখা বন্ধ করতে পারেন, set +o history দিয়ে সেশনের মাঝপথে রেকর্ডিং থামাতে পারেন, অথবা HISTCONTROL=ignorespace সেট করা থাকলে কমান্ডের আগে স্পেস দিয়ে তা লুকিয়ে ফেলতে পারেন। শেল বন্ধ হওয়ার সময় bash ফাইলটি লেখে, তাই kill -9 $$ দিয়ে সেশন কিল করলে কোনো কিছুই রেকর্ড হয় না। শেল হিস্ট্রিকে কেবল একটি ইঙ্গিত হিসেবে ধরুন, প্রমাণ হিসেবে নয়।

sudo কি sudo -i-এর ভেতরে কী ঘটছে তা লগ করে?

না। sudo শুধুমাত্র যে কমান্ডটি চালানোর অনুরোধ করা হয়েছে তা লগ করে, তাই sudo -i শেলের জন্য একটি লাইন তৈরি করে এবং এরপর আর কিছু লগ করে না। ওই root shell-এ টাইপ করা প্রতিটি কমান্ড sudo-এর কাছে অদৃশ্য, কারণ তখন sudo আর যুক্ত থাকে না। sudo su -, sudo bash এবং শেল এস্কেপ সুবিধা আছে এমন যেকোনো অনুমোদিত প্রোগ্রাম একইভাবে কাজ করে। এই ঘাটতি পূরণের দুটি উপায় আছে: execve-এ অডিট রুল সেট করা, যা মূল login uid-সহ প্রতিটি প্রোগ্রাম রেকর্ড করে, অথবা এমন sudoers রুল ব্যবহার করা যা শুরুতেই শেল প্রদান করে না।

auditd কি আমার সার্ভারের গতি কমিয়ে দেবে?

এটি সম্পূর্ণ নির্ভর করে আপনার ওয়ার্কলোড কতগুলো প্রসেস শুরু করছে তার ওপর, তাই কোনো নির্দিষ্ট সংখ্যার ওপর নির্ভর না করে মেপে দেখুন। যে সার্ভার মূলত অনুরোধের উত্তর দেয়, সেখানে খুব কম exec হয় এবং কোনো প্রভাব পড়ে না। কিন্তু একটি build host বা CI runner-এ প্রতিনিয়ত exec হতে থাকে, যা প্রভাব ফেলতে পারে; কারণ কার্নেলের অডিট ব্যাকলগ পূর্ণ হয়ে গেলে, ইভেন্ট তৈরি করা প্রসেসটিকে জায়গা খালি না হওয়া পর্যন্ত থামিয়ে রাখা হয়। প্রকৃত লোডের সময় sudo auditctl -s চালান এবং backloglost পর্যবেক্ষণ করুন। lost-এর মান শূন্যের বেশি হওয়া মানে রেকর্ড ড্রপ হয়েছে, যা সবচেয়ে খারাপ ফলাফল, কারণ তখন লগে অদৃশ্য ফাঁক থেকে যায়।

অডিট লগগুলো কোথায় সংরক্ষণ করা উচিত?

কয়েক সেকেন্ডের বিলম্বসহ অন্য কোনো মেশিনে। অডিট করা হোস্টের root অ্যাক্সেস পাওয়া যেকোনো ব্যক্তি /var/log/audit/audit.log মুছে ফেলতে এবং /var/log/auth.log নতুন করে লিখতে পারে, তাই লোকাল কপিগুলো কেবল সেই ঘটনাগুলোর উত্তর দেয় যা কেউ লুকানোর চেষ্টা করেনি। audisp-remote প্লাগইন ব্যবহার করে একটি কেন্দ্রীয় auditd-তে ফরওয়ার্ড করুন, অথবা অডিট syslog প্লাগইন চালু করে rsyslog-এর মাধ্যমে TLS ব্যবহার করে পুরো syslog স্ট্রিম ফরওয়ার্ড করুন। কালেক্টরের জন্য আলাদা ক্রেডেনশিয়াল ব্যবহার করুন এবং নিশ্চিত করুন যে যাদের অডিট করা হচ্ছে, তাদের যেন ওই কালেক্টরে কোনো অ্যাক্সেস না থাকে।