- ssh-init-vm नई VM पर पहली SSH कनेक्शन के दौरान man-in-the-middle attack को रोकने के लिए cloud-init के जरिए अस्थायी SSH host private key inject करता है, और long-term host key को generate या import करने के दौरान केवल उसी पर trust करता है
- यह Hetzner Cloud जैसे ऐसे VPS या cloud में भी काम करता है जहाँ dedicated connection protection feature नहीं है; इसके लिए सिर्फ व्यापक रूप से supported cloud-init चाहिए
- सामान्य Trust On First Use में जब
ssh “The authenticity of host [...] can't be established” पूछता है और उपयोगकर्ता yes दर्ज करता है, तो हमलावर traffic को proxy कर सकता है या उपयोगकर्ता की VM जैसा दिखने वाली मशीन दे सकता है
- अगर long-term SSH host private key को सीधे cloud-init userdata में रखा जाए, तो यह पहली कनेक्शन authentication में मदद करता है, लेकिन sensitive key material metadata service, SSRF, cloud provider systems, या admin workstation के जरिए उजागर हो सकता है
- ssh-init-vm अस्थायी key को temporary directory में रखता है और
~/.ssh/known_hosts में नहीं जोड़ता, VM output को ज्यों का त्यों save नहीं करता, और long-term key को record करने के लिए OpenSSH की host key rotation पर निर्भर करता है
cloud-init userdata के उजागर होने की समस्या
- cloud-init के जरिए long-term SSH host private key inject करने पर public key को
~/.ssh/known_hosts में डालकर पहली कनेक्शन authenticate की जा सकती है, लेकिन private key कई रास्तों से लीक हो सकती है
- VM के अंदर कोई भी arbitrary process आम तौर पर पढ़ी जा सकने वाली metadata service से userdata हासिल कर सकता है; Hetzner VM में
http://169.254.169.254/hetzner/v1/userdata पर cloud-init की सामग्री देखी जा सकती है
- हमलावर SSRF के जरिए process से metadata leak करवा सकता है, और ऐसी blocking dedicated protection feature वाले environment में भी हमेशा लागू नहीं होती
- cloud provider के अन्य systems में भी userdata उजागर हो सकती है; Hetzner अपने server creation API docs में स्पष्ट रूप से कहता है कि “passwords or other sensitive information” वहाँ store न करें
- admin workstation भी cloud-init userdata के बचने या होकर गुजरने की जगह हो सकता है, इसलिए उसमें long-term private key रखना key के वैध रहने तक exposure का जोखिम पैदा करता है
security analysis और threat model
- आधार यह है कि OpenSSH protocol और implementation पर trust किया जाता है, और admin की attack detect करने की क्षमता पर निर्भर नहीं रहा जाता
-
network attacker के खिलाफ protection
- जिनकी रक्षा की जा रही है वे हैं admin workstation की integrity और VM
- हमलावर network को पूरी तरह control करने वाला man-in-the-middle है, और script के सफल या असफल होकर समाप्त होने के बाद किसी समय cloud-init userdata जान सकता है
- protection इसलिए संभव है क्योंकि हमलावर key material को उस समय नहीं जानता जब उसका मूल्य बाकी हो
- script accidental use को रोकने के लिए अस्थायी SSH host key को temporary directory में रखती है और अस्थायी SSH host key को
~/.ssh/known_hosts में नहीं डालती
-
admin workstation के compromise होने की स्थिति
- protection केवल VM और VM की long-term SSH host private key तक सीमित है
- माना जाता है कि हमलावर network और admin workstation दोनों को पूरी तरह control करता है, लेकिन वास्तविक VM तक पहुँचता नहीं है
- long-term SSH host private key कभी admin workstation पर रही ही नहीं, और हमलावर वास्तविक VM तक नहीं पहुँचता, इसलिए वह VM की long-term host key हासिल नहीं कर पाता
- अगर हमलावर वास्तविक VM तक पहुँच जाए, तो
ssh root@<VM> cat /etc/ssh/ssh_host_* जैसे तरीके से SSH host key जान लेने की संभावना बहुत अधिक है
-
VM या provider के compromise होने की स्थिति
- protection केवल admin workstation की integrity तक सीमित है
- हमलावर network को पूरी तरह control करता है और VM या provider को भी पूरी तरह control कर सकता है
- इस स्थिति में भी OpenSSH के सुरक्षित होने की धारणा के कारण admin workstation की integrity सुरक्षित रहती है
- अतिरिक्त defense के तौर पर script VM output को सीधे
~/.ssh/known_hosts में नहीं लिखती, बल्कि OpenSSH की key rotation पर निर्भर करती है ताकि long-term SSH host key डाली जा सके
- यह तरीका compromised host को
known_hosts parser में malicious data खिलाने से रोकता है, और केवल वही key ~/.ssh/known_hosts में दर्ज होने देता है जिसे VM वास्तव में control करता है
HashKnownHosts जैसे OpenSSH options और भविष्य के संबंधित options को भी सही तरह से handle किया जा सकता है
किन शर्तों में वास्तविक man-in-the-middle attack सफल होता है
- man-in-the-middle attack की सफलता इस पर निर्भर करती है कि क्या उपयोगकर्ता वास्तव में पहचान पाता है कि सारी कनेक्शन शुरुआत से ही गलत मशीन पर जा रही हैं, क्या वह password दर्ज करने से इनकार करता है, और क्या वह
ssh के agent या X11 forwarding को enable करता है
- ssh-mitm के अनुसार सरल शर्तों में, अगर हमलावर वास्तविक target host के बजाय अपने control वाली machine तक पहुँच देकर उपयोगकर्ता को धोखा दे सके, तो सफलता की संभावना अधिक है
- अगर हमलावर उपयोगकर्ता को धोखा देकर वास्तविक host में login करने वाली जानकारी हासिल कर ले, तब भी वह सफल हो जाता है
- यदि उपयोगकर्ता हमलावर की machine में password से login करता है, तो हमलावर सफल हो सकता है
- यदि उपयोगकर्ता किसी भी authentication method से login करने के बाद prompt पर password दर्ज करता है, तो हमलावर सफल हो सकता है
- यदि उपयोगकर्ता किसी भी authentication method से login करके ssh-agent connection forward करता है, तो हमलावर सफल हो सकता है
- यदि ऊपर की शर्तें मौजूद नहीं हैं, तो हमलावर को उपयोगकर्ता को धोखा देने के लिए वास्तविक host तक पहुँच चाहिए होगी, लेकिन केवल उपयोगकर्ता के input के आधार पर वह वास्तविक host में login नहीं कर पाएगा, इसलिए उसके असफल होने की संभावना अधिक है
- यदि उपयोगकर्ता X11 connection forward करता है, तो हमलावर authentication method से अलग भी admin workstation पर attack करने में सफल हो सकता है
1 टिप्पणियां
Lobste.rs टिप्पणियाँ
इसे automate किया जा सकता है, यह बढ़िया है। manual तरीके से मैं cloud provider console में server के SSH fingerprint को अलग channel से verify करता रहा हूँ
मैं बहुत ज़्यादा cloud instances manage नहीं करता, इसलिए provisioning में कुछ manual steps हों तो भी ठीक है
अगर आपने DNS zone को automate कर रखा है, तो एक और तरीका संभव है: बहुत सीमित scope वाला one-time token बनाइए, जिसे उदाहरण के लिए सिर्फ
my-server-hostname.example.netपर एक record बनाने की अनुमति होउस token को
cloud-initके ज़रिए server तक भेजें, और server अपने public SSH key को DNS के SSHFP record के रूप में publish कर दे। इसके बाद SSH client को SSHFP record अपने-आप verify करने के लिए सेट किया जा सकता है, और DNS zone का DNSSEC-signed होना ज़रूरी हैयह flow server को private SSH host key बनाए रखने देता है और key rotation से भी बचाता है। ज़्यादातर DNS providers इतने granular one-time access tokens support नहीं करते, लेकिन आप एक simple internal web service रख सकते हैं जो token verify करने के बाद permanent और scope-unrestricted token के साथ API call कर दे। SSH server उस permanent token तक पहुँच नहीं पाएगा
हालांकि DNSSEC domain में लिखने की बजाय मैं शायद SSH certificates generate करना ज़्यादा पसंद करूँगा, और उस बिंदु पर यह सवाल बन जाता है कि किस environment में कौन-सा solution बेहतर बैठता है
जानना चाहूँगा कि क्या आप ऐसे flexible tokens बनाने वाला कोई software या provider जानते हैं, या फिर कुछ हद तक खुद development करना पड़ेगा
काफ़ी साफ़-सुथरा है। लेकिन लगता है कि पोस्ट की तारीख़ में महीना और दिन उलट गए हैं
मैंने पहले इसी SSH chicken-and-egg problem को explore करने के लिए एक experimental service बनाई थी
यह request पर SSHFP DNS records बनाती है; रुचि हो तो https://github.com/tedb/sshfp देख सकते हैं
अच्छा लगा कि VM providers के बीच काफ़ी हद तक consistent 169.254.169.254 metadata service को कवर किया गया है। यह
cloud-initsource में कईcloudinit/source/DataSource*.pyentries देखकर भी पता चलता हैनिजी तौर पर मुझे
cloud-initकी design और limitations की वजह से उससे बढ़ती हुई थकान महसूस होती है। मेरी दिलचस्पी local QEMU virtual machines, remote machines, containers, और physical hardware में system configuration को unify करने में हैarch-boxes project दिखाता है कि ArchLinux cloud-init image कैसे बनाई जाती है, और यह बेहद simple shell scripts का एक bundle है। अगर इस तरीके को
guestfishया µvm के साथ अपनाया जाए, तो OCI-compatible images, QEMU या cloud providers के लिए disk images, और नई physical machines की provisioning के लिए बिलकुल वही scripts इस्तेमाल की जा सकती हैंकुछ QEMU flags के साथ
cloud-initपर निर्भर हुए बिना यही approach दोहराई जा सकती है। जहाँ तक मुझे पता है,systemd.system-credentialsसे temporary host keys pass नहीं की जा सकतीं; वहाँ सिर्फssh.authorized_keys.rootजैसे~/.ssh/authorized_keysके लिए credentials हैंइसकी जगह एक unit file बनाई जा सकती है जो initrd stage में चले या
systemd-firstboot.serviceके साथ चले। इस unit file को image में पहले से रखा जा सकता है याsystemd.extra-unit.*credential के रूप में temporary inject किया जा सकता है, औरsystemd.wants=…kernel command-line option से enable किया जा सकता है। QEMU में-netdev user,id=metadata,net=169.254.0.0/16,dhcpstart=169.254.0.15,guestfwd=tcp:169.254.169.254:80-cmd:…entry के ज़रिए metadata service की मौजूदगी का अनुकरण किया जा सकता है। हालाँकि, बने हुए interface को activate करना पड़ सकता है, और यह भी शायद temporary unit file से करना बेहतर होगाइस तरह अलग-अलग तरह की “machines” में consistent system configuration करते समय अपेक्षाकृत कम complexity के साथ काफ़ी flexibility मिलती है। दरअसल सिर्फ इस काम के लिए देखें तो सबसे अच्छा तरीका शायद यही है कि image-generation tool fixed host keys वाली machine image बनाए, और first reboot या shutdown पर चलने वाली custom host-key rotation script को SystemD service के रूप में install कर दे
/etc/mkinitcpio.confमेंsystemdHOOKenable कर दें, तो initrd में किए जाने वाले काम के लिए SystemD unit files लिख सकते हैं, और लगभग लिखनी ही चाहिएव्यवहार में यह
{/etc,/usr/lib}/initcpio/hooksलिखने से बस थोड़ा-सा अधिक झंझट वाला हैलेकिन initrd में
systemd-networkingऔरsystemd-resolvedचालू करना काफ़ी आसान है, इसलिए initrd system startup की ज़िम्मेदारी ले सकता है और root filesystem पर switch करने से पहले काम schedule कर सकता हैबेशक laptop जैसे physical hardware पर Wi‑Fi connectivity के लिए
NetworkManagerजैसी किसी चीज़ की ज़रूरत पड़ सकती है, इसलिए वहाँ यह उतना फिट नहीं बैठता, लेकिन QEMU VM और hosted VM के लिए यह काफ़ी अच्छा है, और system startup के बहुत-से काम स्वाभाविक रूप से इसी जगह फिट होते हैंलक्ष्य यह है कि
cloud-initपर निर्भर न रहना पड़े, किसी एक cloud provider से बँधना न पड़े, physical machines, containers, local VMs, और hosted VMs में consistency मिले, और dependencies लगभग सिर्फ SystemD तक सिमट जाएँ