OpenVPN ক্রেডেনশিয়াল ফাইল নাকি ম্যানেজমেন্ট সকেট: কোনটি স্ক্রিপ্ট করবেন
auth-user-pass অ্যাকাউন্টের প্রম্পট কভার করে; ম্যানেজমেন্ট সকেট চারটিই কভার করে। এক্সপোজার, স্ক্রিপ্টিং খরচ এবং একটি সার্ভিসে প্রত্যেকটি কীভাবে ব্যর্থ হয় তা তুলনা করুন।
যে স্ক্রিপ্ট OpenVPN চালু করে কিন্তু কখনও সংযোগ করে না, সেটি সাধারণত নেটওয়ার্কের সমস্যা নয়: ক্লায়েন্ট একটি প্রম্পটে বসে আছে, যা আঁকার কোনো টার্মিনাল নেই। OpenVPN-এর কাছে মানুষ ছাড়া সেই প্রম্পটের উত্তর দেওয়ার ঠিক দুইটি সমর্থিত উপায় আছে, auth-user-pass-এর পেছনের ক্রেডেনশিয়াল ফাইল এবং ম্যানেজমেন্ট সকেট, এবং এগুলি একে অপরের বদলে ব্যবহারযোগ্য নয়। ফাইলটি একটি নির্দেশনার খরচে একটি প্রম্পটের উত্তর দেয়; সকেটটি প্রতিটি প্রম্পটের উত্তর দেয় এবং loopback পোর্ট খুলতে পারে এমন যেকোনো কিছুকে একটি অননুমোদিত নিয়ন্ত্রণ চ্যানেল দেয়। আপনার ডিপ্লয়মেন্টে কোনটি উপযুক্ত তা নির্ভর করে কোন প্রম্পটটি আসলে আটকে আছে এবং কোন গোপন তথ্য আপনি বিশ্রামে রাখার সামর্থ্য রাখেন তার উপর।
কোন প্রক্রিয়া বেছে নেওয়ার আগে প্রম্পটের নাম দিন
চারটি প্রম্পট টার্মিনালে একই রকম দেখায়। অ্যাকাউন্ট জোড়াটি আসে সার্ভারের PAM বা auth-user-pass-verify সেটআপ থেকে এবং auth-user-pass দিয়ে উত্তর দেওয়া হয়। একটি প্রাইভেট কী পাসফ্রেজ কী ফাইলের অন্তর্গত এবং --askpass দিয়ে পড়া হয় বা হাতে টাইপ করা হয়। PKCS#12 বান্ডল নিজের একটি পাসওয়ার্ড চায়। প্রক্সি প্রমাণীকরণ অ্যাকাউন্ট ক্রেডেনশিয়াল নয়, --http-proxy যে auth ফাইল নেয় সেটি ব্যবহার করে।
OpenVPN যখন systemd, PHP বা Node-এর চাইল্ড হিসেবে চলে, তখন কোনো টার্মিনাল থাকে না, তাই এগুলোর যেকোনোটি নীরবে আটকে যায়। প্রক্রিয়াটি বসে থাকে, সাইফার লাইনের পরে লগ থেমে যায়, এবং ইউনিটটি শেষে সময় শেষ হয়ে যায়; সেই নীরবতাই মানুষকে খতিয়ে দেখার বদলে পুনরায় চেষ্টার লুপ বা sleep যোগ করতে প্ররোচিত করে। শুধু ম্যানেজমেন্ট সকেট চারটিরই উত্তর দিতে পারে। ক্রেডেনশিয়াল ফাইল প্রথমটির উত্তর দেয় এবং আর কিছুই না।
auth-user-pass: একটি ফাইল, একটি প্রম্পট
ফাইলটিতে প্রথম লাইনে ব্যবহারকারীর নাম এবং দ্বিতীয় লাইনে পাসওয়ার্ড থাকে, আর কিছুই না: কোনো উদ্ধৃতি নেই, কোনো কী-নাম নেই, কোনো মন্তব্য নেই। মোড 600 সেট করুন এবং মালিককে openvpn চালায় এমন অ্যাকাউন্ট করুন, যা কোনো সার্ভিসের ক্ষেত্রে প্রায়ই আপনার লগইন নয় বরং একটি নিবেদিত ব্যবহারকারী। /root-এর অধীনে root-এর মালিকানার ফাইল হলো আপনার শেলে কাজ করা কমান্ড এবং বুটে ব্যর্থ হওয়া ইউনিটের মধ্যে পার্থক্য।
দুটি বিবরণ একটি সঠিক ফাইলকে প্রম্পটে পরিণত করে। যে এডিটর CRLF সংরক্ষণ করে সে পাসওয়ার্ডের সঙ্গে লেগে থাকা একটি ক্যারেজ রিটার্ন রেখে যায়, তাই সার্ভার এমন পাসওয়ার্ড প্রত্যাখ্যান করে যা ফাইলে সঠিক দেখায়; চোখে নয়, cat -A বা od -c দিয়ে যাচাই করুন। আর প্রোফাইলের ভেতরে আর্গুমেন্ট-হীন auth-user-pass ডিজাইন অনুসারে «ব্যবহারকারীকে জিজ্ঞাসা করুন» বোঝায়, যা কমান্ড লাইনের দ্বিতীয় নির্দেশনা সম্ভবত অগ্রাহ্য করতে পারে না, কারণ প্রোফাইল যেখানে আছে সেখানেই পার্স হয়।
অপশনের ক্রম তৃতীয় ফাঁদ, এবং এটি সংস্করণ-নির্দিষ্ট। কিছু OpenVPN 2.4 বিল্ড --config-এর আগে থাকলে --auth-user-pass উপেক্ষা করে, তাই একই দুটি অপশন উল্টো ক্রমে সংযোগ করে। নির্দেশনাটি প্রোফাইলের ভেতরে বা কমান্ড লাইনে --config-এর পরে রাখুন, এবং অন্য কিছু বদলানোর আগে প্রোফাইলে প্রতিটি উপস্থিতি grep করুন।
auth-nocache এই প্রক্রিয়ার অন্তর্গত কিন্তু কিছুই সরবরাহ করে না। এটি ক্লায়েন্ট কতক্ষণ ক্রেডেনশিয়াল মেমরিতে রাখে তা সীমিত করে, যা ক্র্যাশের পরে সাহায্য করে এবং ফাইল অনুপস্থিত থাকলে একেবারেই না। সার্ভার-সাইড সেশন টাইমআউটের পরে পুনঃসংযোগ ফাইলটি আবার পড়ে, তাই বুটে কাজ করা ক্রেডেনশিয়াল দিনের মাঝখানেও মেয়াদোত্তীর্ণ হতে পারে।
ম্যানেজমেন্ট সকেট: প্রতিটি প্রম্পট, আরও পৃষ্ঠতল
একটি লিসেনার দিয়ে ক্লায়েন্ট শুরু করুন এবং স্পষ্টভাবে জানান যে প্রম্পটগুলি তার উপর রিপোর্ট করা হবে, OpenVPN 2.6 ম্যানুয়ালে নথিভুক্ত নির্দেশনাগুলি ব্যবহার করে:
management 127.0.0.1 3030
management-query-passwords
bash থেকে সংযোগটি একটি অতিরিক্ত ফাইল ডেস্ক্রিপ্টরে ধরে রাখুন এবং অবস্থানের বদলে প্রম্পটের নাম দিয়ে উত্তর দিন, কারণ পুনঃসংযোগ ভিন্ন ক্রমে জিজ্ঞাসা করতে পারে:
exec 3<>/dev/tcp/127.0.0.1/3030
while read -r -u 3 line; do
case "$line" in
*"Need 'Auth' username/password"*)
echo 'username "Auth" alice' >&3
echo 'password "Auth" secret' >&3 ;;
*"Need 'Private Key' password"*)
echo 'password "Private Key" secret' >&3 ;;
esac
done
সীমাটি হলো পরিবহন। ম্যানেজমেন্ট প্রোটোকল loopback-এ TCP-র উপর প্লেইনটেক্সট, তাই দূরবর্তী নিয়ন্ত্রক যাতে পৌঁছাতে পারে সেজন্য লিসেনারটি LAN বা টানেল ঠিকানায় প্রকাশ করা উচিত নয়; দূরবর্তী নিয়ন্ত্রক মানে SSH ফরওয়ার্ড, আরও প্রশস্ত বাইন্ড নয়। কমিউনিটি ডেমনও একবারে একটি ম্যানেজমেন্ট ক্লায়েন্ট গ্রহণ করে, তাই একটি GUI বা মনিটর আপনার স্ক্রিপ্টের সঙ্গে সকেট ভাগ করতে পারে না। দ্বিতীয় সংযোগ সারিতে না রেখে প্রত্যাখ্যান করা হয়, এবং ব্যর্থতাটি বধির হয়ে যাওয়া স্ক্রিপ্টের মতো দেখায়।
সেই সকেটটি একটি নিয়ন্ত্রণ চ্যানেলও। ম্যানেজমেন্ট পাসওয়ার্ড ছাড়া 127.0.0.1:3030-এ সংযোগ করতে পারে এমন যেকোনো কিছু স্ট্যাটাস পড়তে, টানেল মেরে ফেলতে বা নিজেই একটি প্রম্পটের উত্তর দিতে পারে। ম্যানেজমেন্ট পাসওয়ার্ড এবং ক্রেডেনশিয়াল ফাইল একই শ্রেণির গোপন তথ্য, এবং দুটিই একই যত্নের যোগ্য।
কোনটি ডিপ্লয়মেন্টে মানায়
ক্রেডেনশিয়াল ফাইল বেছে নিন যখন একমাত্র প্রম্পট অ্যাকাউন্ট জোড়া, ক্লায়েন্ট স্থিতিশীল মালিকসহ একটি সার্ভিস হিসেবে চলে, এবং আপনি 600 ফাইল এমন ব্যাকআপের বাইরে রাখতে পারেন যা আপনি নিয়ন্ত্রণ করেন না। ম্যানেজমেন্ট সকেট বেছে নিন যখন একটি কী পাসফ্রেজ বা PKCS#12 পাসওয়ার্ড জড়িত, যখন র্যাপার ইতিমধ্যেই প্রক্রিয়াটি তদারকি করে, বা যখন পুনঃসংযোগ ডিবাগ করার সময় স্ট্যাটাস ও প্রম্পট দেখতে হয়।
দুটি শর্ত সিদ্ধান্ত সরায়। যদি র্যাপার /bin/sh হয়, বাইনারিকে সরাসরি ডাকা systemd ইউনিট হয়, বা ন্যূনতম কনটেইনার হয়, তবে শুধু-bash সকেট গ্লু পাওয়া যায় না এবং ফাইলই সস্তা উত্তর। যদি গোপন তথ্য প্রায়ই ঘোরে, কোনো ফাইলই তার জন্য ভালো বাসস্থান নয়: একটি ছোট র্যাপার থেকে keyring জিজ্ঞাসা করুন এবং ইউনিটকে র্যাপার ডাকতে দিন, যা ঘূর্ণন এক জায়গায় রাখে এবং পাসওয়ার্ড শেল ইতিহাসের বাইরে।
প্রসেস সাবস্টিটিউশন দুটির মাঝখানে দাঁড়ায় এবং কোনোটিরই নয়। নিচের একলাইনারটি কাজ করে কারণ bash openvpn শুরুর আগেই এটি প্রসারিত করে, ক্লায়েন্ট সিনট্যাক্স বোঝে বলে নয়:
openvpn --config client.ovpn --auth-user-pass <(printf "%s
%s
" "$USER" "$PASS")
এটি /bin/sh-এর অধীনে, শেল এড়িয়ে যাওয়া ইউনিটে, এবং bash বা /dev/fd ছাড়া ইমেজে ভেঙে যায়। এটি ইন্টারঅ্যাকটিভ পরীক্ষার জন্য রাখুন, কখনও এমন চুক্তি হিসেবে নয় যার উপর একটি সার্ভিস নির্ভর করে।
গোপন তথ্য রক্ষা করুন, তারপর লগ থেকে যাচাই করুন
উভয় প্রক্রিয়া OpenVPN প্রক্রিয়ার কাছে পঠনযোগ্য একটি গোপন তথ্য রেখে যায়। পাসওয়ার্ড কখনও কমান্ড লাইনে বা ইউনিট ফাইলে রাখবেন না, যেখানে ps এবং systemctl এটি প্রত্যেক স্থানীয় ব্যবহারকারীকে দেখায়; ফাইলের পথ দিন, ভেতরের মান নয়। যেখানে সার্টিফিকেট অ্যাকাউন্ট জোড়া প্রতিস্থাপন করতে পারে, সেখানে এটি প্রম্পটের শ্রেণিটি লুকানোর বদলে সরিয়ে দেয়।
সঠিক রান প্রম্পট অনুক্রম সম্পূর্ণ হওয়া এবং সেশন «Initialization Sequence Completed»-এ পৌঁছানো দেখায়। ক্লায়েন্ট একই প্রম্পটে থেমে গেলে মিলটি ব্যর্থ হয়েছে: সকেট যে সঠিক লাইনগুলি পাঠিয়েছে তা প্রিন্ট করুন, উদ্ধৃতি ও প্রম্পটের নাম যাচাই করুন, এবং sleep যোগ করার বদলে প্যাটার্নটি ঠিক করুন। যে টানেল সফল বলে জানায় কিন্তু কিছুই বহন করে না, সেটি রাউটিং বা push সমস্যা, ক্রেডেনশিয়াল সমস্যা নয়।
তারপর শুধু প্রথম শুরু নয়, পুনঃসংযোগও পরীক্ষা করুন। সার্ভার-সাইড সেশনটি ফেলে দিন বা তার টাইমআউট শেষ হওয়া পর্যন্ত অপেক্ষা করুন; ক্লায়েন্ট আবার জিজ্ঞাসা করে, এবং ঠিক সেখানেই বুটে সঠিক দেখানো ফাইলটি পুনঃসংযোগকারী অ্যাকাউন্টের জন্য এখনও পঠনযোগ্য কি না তা দেখায়।