# क्या SSH होस्टनेम कैननिकलाइज़ेशन स्वीकृत लक्ष्य बदल सकता है?

`ssh build` लिखी हुई स्वीकृति उस मशीन को अधिकृत करे, यह ज़रूरी नहीं जो अंत में TCP कनेक्शन स्वीकार करती है। OpenSSH छोटे नाम को बढ़ा सकता है, अनुमत CNAME का अनुसरण कर सकता है, कॉन्फ़िगरेशन को दूसरी बार पढ़ सकता है, अलग उपयोगकर्ता या पोर्ट चुन सकता है और बने हुए नाम को कई पतों में से किसी एक पर रिज़ॉल्व कर सकता है। अगर कोई एजेंट गेटवे केवल एजेंट का दिया हुआ टेक्स्ट स्वीकृत करता है, तो स्वीकृति एक लक्ष्य का वर्णन कर सकती है जबकि SSH क्लाइंट किसी दूसरे लक्ष्य का उपयोग करे।

इसका अर्थ यह नहीं कि कैननिकलाइज़ेशन गलत है। छोटे नाम उपयोगी हैं, कैननिकल नाम कॉन्फ़िगरेशन संभालना आसान बनाते हैं और होस्ट कुंजियां अब भी सर्वर की पहचान जाँचती हैं। स्वीकृति की सीमा उस समय होनी चाहिए जब OpenSSH प्रभावी गंतव्य निकाल चुका हो, लेकिन सॉकेट अभी न खोला गया हो। स्वीकृति देने वाले व्यक्ति को माँगा गया नाम, अंतिम नाम और पता, तथा कॉन्फ़िग से हुए सभी महत्वपूर्ण बदलाव दिखने चाहिए।

## एक SSH कमांड में चार अलग पहचान होती हैं

SSH लक्ष्य केवल एक स्ट्रिंग नहीं है। उसे एक स्ट्रिंग मानने से ही यह गड़बड़ी पैदा होती है। सही स्वीकृति पथ चार पहचानों को अलग रखता है:

- माँगा गया नाम एजेंट का दिया तर्क है, जैसे `build`।
- प्रभावी होस्टनेम वह मान है जिसे OpenSSH `Hostname` प्रतिस्थापन और कैननिकलाइज़ेशन के बाद उपयोग करता है, जैसे `build.ops.example`।
- पीयर पता वह IP पता है जिसे क्लाइंट सॉकेट खोलते समय चुनता है।
- प्रमाणित पहचान वह होस्ट कुंजी या होस्ट प्रमाणपत्र है जिसे कनेक्शन के लिए स्वीकार किया गया।

ये मान अलग प्रश्नों के उत्तर देते हैं। माँगा गया नाम इरादा दर्ज करता है। प्रभावी नाम आगे के कॉन्फ़िग मिलान और आम तौर पर होस्ट कुंजी खोज को नियंत्रित करता है। पता बताता है कि पैकेट कहाँ गए। होस्ट कुंजी बताती है कि किस सर्वर ने निजी कुंजी रखने का प्रमाण दिया। स्वीकृति से पहले पहले तीन मान चाहिए, और कुंजी विनिमय के बाद ऑडिट परिणाम में चौथा जुड़ना चाहिए।

OpenSSH खुद `ssh_config` में नामों का यह अंतर दिखाता है। `%n` कमांड लाइन पर दिया मूल दूरस्थ होस्टनेम है, जबकि `%h` कॉन्फ़िगरेशन का काम पूरा होने के बाद का दूरस्थ होस्टनेम है। `%k` एक और मान है: सेट होने पर `HostKeyAlias`, अन्यथा कमांड लाइन का मूल नाम। ये टोकन इसलिए हैं क्योंकि OpenSSH हर चरण के नाम को एक जैसा मानकर नहीं चल सकता।

इसी अंतर के कारण सफल होस्ट कुंजी जाँच अस्पष्ट प्राधिकरण निर्णय को ठीक नहीं कर सकती। प्रमाणीकरण साबित कर सकता है कि एंडपॉइंट के पास अपेक्षित कुंजी है। वह यह साबित नहीं कर सकता कि कार्ड पर केवल `build` दिखने पर व्यक्ति इसी एंडपॉइंट को अधिकृत करना चाहता था। प्राधिकरण पूछता है कि क्या यह कार्रवाई इस गंतव्य तक जा सकती है। प्रमाणीकरण पूछता है कि क्या जवाब देने वाला सर्वर पहचान रिकॉर्ड से मेल खाता है। दोनों जाँच जरूरी हैं और अलग समय पर होती हैं।

## कैननिकलाइज़ेशन कनेक्शन से पहले नाम बदल सकता है

`CanonicalizeHostname` तय करता है कि OpenSSH स्पष्ट रूप से नाम बदलेगा या नहीं। इसका डिफ़ॉल्ट `no` है, जो नाम खोज सिस्टम रिज़ॉल्वर पर छोड़ देता है। `yes` होने पर OpenSSH सीधे कनेक्शन के लिए `CanonicalDomains` के सफ़िक्स आज़माता है। `always` होने पर `ProxyCommand` या `ProxyJump` के जरिए पहुँचे गंतव्य भी कैननिकलाइज़ होते हैं।

मान लें एजेंट यह कार्रवाई माँगता है:

```text
host: build
user: deploy
command: /usr/local/bin/release status
```

क्लाइंट पर यह कॉन्फ़िगरेशन हो सकता है:

```sshconfig
Host *
    CanonicalizeHostname yes
    CanonicalDomains ops.example
    CanonicalizeFallbackLocal no
    CanonicalizeMaxDots 1
    CanonicalizePermittedCNAMEs *.ops.example:*.hosts.example
```

OpenSSH पहले `build.ops.example` आज़माता है। अगर DNS अनुमत CNAME देकर `build-07.hosts.example` पर भेजता है, तो वही कैननिकल नाम बन सकता है। अनुरोध अब भी `build` कहता है, लेकिन क्लाइंट उस नाम से कनेक्ट नहीं करता। केवल अनुरोध दिखाने वाला स्वीकृति कार्ड महत्वपूर्ण बदलाव छिपा देता है।

सीमाओं पर ध्यान देना जरूरी है। `CanonicalizeMaxDots` का डिफ़ॉल्ट 1 है, इसलिए एक डॉट वाला नाम भी कैननिकलाइज़ेशन के योग्य है, केवल बिना डॉट का लेबल नहीं। `CanonicalizeFallbackLocal` का डिफ़ॉल्ट `yes` है; यदि कॉन्फ़िग किए कैननिकल डोमेन परिणाम न दें, तो OpenSSH मूल नाम सिस्टम रिज़ॉल्वर और उसके खोज नियमों को दे सकता है। इसे `no` रखने पर विफलता साफ दिखती है। स्वीकृति गेटवे के लिए स्पष्ट विफलता बेहतर है, क्योंकि स्थानीय खोज सूची नेटवर्क और समय के साथ बदल सकती है।

CNAME का अनुसरण अलग से सीमित होता है। `CanonicalizePermittedCNAMEs` का डिफ़ॉल्ट `none` है और इसके नियम अनुमत स्रोत पैटर्न को लक्ष्य पैटर्न से जोड़ते हैं। यह डिफ़ॉल्ट समझदार है। `*:*` जैसा व्यापक नियम DNS उपनाम को बिना सीमा वाला पुनर्लेखन बना देता है। संकरा नियम उस नेमस्पेस बदलाव को दर्ज करता है जिसकी सच में अपेक्षा है, जैसे `ops.example` के सेवा उपनाम से `hosts.example` के होस्ट तक।

OpenSSH मैनुअल इन नियंत्रणों को ठीक-ठीक बताता है, पर नीति परत केवल विकल्पों के मान कार्ड पर नहीं लिख सकती। उसे उसी क्लाइंट कॉन्फ़िगरेशन के साथ वही गणना चलानी होगी। स्वीकृति सेवा में सफ़िक्स खोज और CNAME नियम फिर से लिखने पर वे SSH क्लाइंट के संस्करण और स्थानीय कॉन्फ़िग बदलने के साथ अलग हो जाते हैं।

## दूसरा कॉन्फ़िग पास DNS से अधिक बदल सकता है

कैननिकलाइज़ेशन चालू होने पर OpenSSH नए लक्ष्य नाम के साथ कॉन्फ़िगरेशन फिर पढ़ता है। दूसरा पास ऐसे `Host` और `Match` ब्लॉक सक्रिय कर सकता है जो मूल उपनाम से नहीं मिलते थे। इसलिए केवल DNS की पूर्व जाँच गंतव्य के दूसरे बदलाव छोड़ सकती है।

मान लें कैननिकल नाम इस ब्लॉक से मिलता है:

```sshconfig
Match canonical host *.prod.ops.example
    User release
    Port 2222
    IdentityFile ~/.ssh/prod_release
    ProxyJump bastion.ops.example
```

`deploy` का अनुरोध पहले `deploy.prod.ops.example` बन सकता है, फिर अलग दूरस्थ उपयोगकर्ता, पोर्ट, पहचान फ़ाइल और जंप होस्ट चुन सकता है। OpenSSH अधिकतर निर्देशों के लिए पहले मिले मान का उपयोग करता है, इसलिए सेटिंग लागू होगी या नहीं, यह पहले के ब्लॉक और उनके क्रम पर निर्भर है। अकेले मिलते हुए ब्लॉक को पढ़कर अंतिम कॉन्फ़िग नहीं जाना जा सकता।

`canonical` शर्त केवल होस्टनेम कैननिकलाइज़ेशन के बाद दोबारा पढ़े जा रहे कॉन्फ़िग में मिलती है। `final` शर्त कैननिकलाइज़ेशन बंद होने पर भी अंतिम पास माँगती है। कैननिकलाइज़ेशन चालू हो तो `canonical` और `final` एक ही पास में मिलते हैं। `host` उस लक्ष्य से मिलता है जिसे `Hostname` या कैननिकलाइज़ेशन ने बदला है, जबकि `originalhost` कमांड लाइन के मान से मिलता है। इन बातों के कारण साधारण दिखने वाला कॉन्फ़िग भी स्थिति पर निर्भर है।

खतरनाक समीक्षा तरीका यह है कि `host=deploy, user=agent, port=22` स्वीकृत कर दिया जाए, फिर `ssh deploy` सामान्य क्लाइंट को देकर मान लिया जाए कि फ़ील्ड नहीं बदलेंगे। अगर क्लाइंट कॉन्फ़िग अब भी `User`, `Port`, `ProxyJump`, `RemoteCommand`, फ़ॉरवर्डिंग या पहचान चयन बदल सकता है, तो स्वीकृति ने प्रस्ताव को कवर किया, चली हुई कार्रवाई को नहीं।

सुरक्षित डिज़ाइन अंतिम पास के बाद महत्वपूर्ण प्रभावी कॉन्फ़िग को जमा देता है। कम से कम प्रभावी होस्ट, चुना पता, पोर्ट, दूरस्थ उपयोगकर्ता, प्रॉक्सी मार्ग, दूरस्थ कमांड, फ़ॉरवर्डिंग अनुरोध, होस्ट कुंजी उपनाम और क्लाइंट के पहचान स्रोत को स्वीकृति से बाँधें। कनेक्शन से पहले कोई बँधा मान बदले तो स्वीकृति रद्द करके फिर पूछें। दूसरी गणना के पार पुरानी स्वीकृति चुपचाप न चलने दें।

## कॉन्फ़िगरेशन का स्रोत भी लक्ष्य का हिस्सा है

अंतिम गंतव्य इस पर निर्भर है कि OpenSSH ने कौन सी कॉन्फ़िग फ़ाइलें, कमांड लाइन विकल्प, वातावरण और स्थानीय नेटवर्क पढ़े। इन इनपुट को दर्ज किए बिना लक्ष्य स्वीकृत करने से स्वीकृत अर्थ बदलने का आसान रास्ता खुला रहता है। OpenSSH मैनुअल का सामान्य क्रम कमांड लाइन विकल्प, उपयोगकर्ता कॉन्फ़िग फ़ाइल और सिस्टम कॉन्फ़िग फ़ाइल है। अधिकतर निर्देशों में पहले मिला मान चलता है।

मनमाने SSH फ़्लैग जोड़ सकने वाला एजेंट सावधानी से रखे डिफ़ॉल्ट को पार कर सकता है। `-F` दूसरी कॉन्फ़िग फ़ाइल चुनता है, जबकि `-o` सीधे `Hostname`, `ProxyCommand`, `ProxyJump`, `Port`, `User`, `HostKeyAlias` या फ़ॉरवर्डिंग निर्देश सेट कर सकता है। गेटवे को SSH कार्रवाई को प्रकार वाले फ़ील्ड में पढ़कर असमर्थित विकल्प रोकने चाहिए, न कि अपारदर्शी कमांड स्ट्रिंग स्वीकार करनी चाहिए। कच्चे फ़्लैग जरूरी हों, तो गंतव्य को प्रभावित करने वाले हर फ़्लैग को वर्गीकृत करें और उसका सामान्यीकृत मान स्वीकृति में रखें।

कॉन्फ़िग फ़ाइलें आगे के इनपुट भी लाती हैं। `Include` कई पथ, वाइल्डकार्ड, टोकन और वातावरण चर लेता है तथा वाइल्डकार्ड मेल को शब्दकोश क्रम में पढ़ता है। शामिल डायरेक्टरी में नई फ़ाइल जोड़ने से, ऊपरी फ़ाइल बदले बिना, पहले मिलने वाला मान बदल सकता है। केवल पहली फ़ाइल का पथ नहीं, हर लोड हुई फ़ाइल का सामग्री डाइजेस्ट और मालिक दर्ज करें। एजेंट या अविश्वसनीय रिपॉज़िटरी की कार्य डायरेक्टरी से लिखी जा सकने वाली फ़ाइलें अस्वीकार करें।

`Match exec` केवल शर्त की स्ट्रिंग तुलना नहीं है: OpenSSH दी गई कमांड उपयोगकर्ता के shell में चलाता है और शून्य निकास स्थिति को मेल मानता है। `Match localnetwork` सक्रिय स्थानीय इंटरफ़ेस के पतों के अनुसार कॉन्फ़िग बदल सकता है। मैनुअल भी सावधान करता है कि DHCP से कॉन्फ़िग नेटवर्क सुरक्षा-संवेदनशील सेटिंग के लिए भरोसेमंद कसौटी नहीं है। उसी `ssh build` अनुरोध को VPN जुड़ने, स्क्रिप्ट की निकास स्थिति बदलने या शामिल फ़ाइल आने पर दूसरा प्रभावी लक्ष्य मिल सकता है।

स्वीकृति एक्ज़ीक्यूटर गणना से पहले बंद इनपुट सेट बनाए। निश्चित क्लाइंट बाइनरी, नियंत्रित कॉन्फ़िग मूल, साफ वातावरण, ज्ञात फ़ाइल स्वामित्व, स्पष्ट पता परिवार और उपयोगकर्ता तथा सिस्टम कॉन्फ़िग की घोषित नीति अपनाएँ। उस सेट का डाइजेस्ट निकालकर निष्पादन टिकट में रखें। डाइजेस्ट कार्ड पर प्रमुख होने की जरूरत नहीं, लेकिन ऑडिट रिकॉर्ड में होना और उपयोग के समय फिर जाँचा जाना चाहिए।

कॉन्फ़िग जमाने का अर्थ उपयोगी प्रति-होस्ट सेटिंग रोकना नहीं है। प्रश्न यह है कि उन्हें कौन लिख सकता है। ऑपरेटर का बनाया `build` उपनाम, जो कैननिकल उत्पादन होस्ट से जुड़ता है, तब सुरक्षित हो सकता है जब कार्ड मैपिंग दिखाए। एजेंट-नियंत्रित चेकआउट का बनाया उपनाम अविश्वसनीय अनुरोध का हिस्सा है, भले उसका सिंटैक्स सामान्य OpenSSH कॉन्फ़िग जैसा हो।

यह स्रोत जाँच आम परीक्षण अंतर भी बंद करती है। टीमें अक्सर साफ अस्थायी कॉन्फ़िग से कैननिकलाइज़ेशन जाँचती हैं, फिर डेवलपर के पूरे कॉन्फ़िग और सिस्टम डिफ़ॉल्ट से कार्रवाई चलाती हैं। परीक्षण अस्थायी फ़ाइल को साबित करता है, असली कार्रवाई को नहीं। ठीक वही इनपुट एक बार पकड़ें और स्वीकृति से कनेक्शन तक साथ रखें।

OpenSSH संस्करण को भी इनपुट मानें। डिफ़ॉल्ट और स्वीकृत निर्देश बदलते हैं, और एक साझा फ़ाइल पढ़ने वाली मशीनों पर भी अलग क्लाइंट बिल्ड हो सकते हैं। टिकट में एक्ज़ीक्यूटेबल पथ और संस्करण दर्ज करें, फिर एजेंट ट्रैफ़िक पर अपग्रेड से पहले संगतता परीक्षण चलाएँ। एक रिलीज़ के लिए लिखा पार्सर अनजान आउटपुट को रोके, यह अनुमान न लगाए कि नया नाम या फ़ील्ड हानिरहित है।

कॉन्फ़िग स्रोत यह भी तय करता है कि स्वीकृति दोबारा उपयोग हो सकती है या नहीं। पुन: उपयोग तभी ठीक है जब अनुरोध, पूरा निकला कॉन्फ़िग, रिज़ॉल्यूशन परिणाम और कनेक्टर स्थिति छोटी वैधता अवधि में एक समान रहें। वही उपनाम अपने आप कुछ साबित नहीं करता। ऐसे लंबे अनुदान से बेहतर नई छोटी स्वीकृति है जिसका प्रभावी लक्ष्य एजेंट रन के बीच चुपचाप बदल सकता है।

## कार्ड दिखने के बाद DNS उत्तर बदल सकता है

प्रभावी होस्टनेम स्थिर रहे, तब भी स्वीकृति और कनेक्शन के बीच उसका पता बदल सकता है। DNS रोटेशन, अलग नेटवर्क दृश्य, VPN बदलाव, रिज़ॉल्वर खोज पथ और सामान्य रिकॉर्ड अपडेट अलग उत्तर दे सकते हैं। स्वीकृति सेवा नाम रिज़ॉल्व करके पता दिखाए और SSH प्रक्रिया बाद में फिर रिज़ॉल्व करे, तो जाँच और उपयोग के समय में अंतर बनता है।

समाधान DNS को अविश्वसनीय कहकर पते को अनदेखा करना नहीं है। निष्पादन को उसी रिज़ॉल्यूशन परिणाम से बाँधें जो स्वीकृति देने वाले ने देखा। विश्वसनीय एक्ज़ीक्यूटर में एक बार रिज़ॉल्व करें, क्लाइंट के पता परिवार नियम से पता चुनें, उसे दिखाएँ और बिना दूसरी नाम खोज के वही सॉकेट पता कनेक्शन पथ को दें। पहचान के लागू उपयोग, होस्ट कुंजी खोज, प्रमाणपत्र और लॉग के लिए कैननिकल नाम रखें, लेकिन ट्रांसपोर्ट को चुपचाप नया पता न चुनने दें।

कई A या AAAA रिकॉर्ड के लिए साफ नियम चाहिए। पतों का सेट दिखाकर क्लाइंट को कोई सदस्य आज़माने देना ठीक हो सकता है, पर स्वीकृति में कहना होगा कि दिखा हुआ सेट कवर है और ऑडिट लॉग में सफल सदस्य दर्ज होना चाहिए। सेट बदले तो पुरानी स्वीकृति नए पते तक न फैले। अधिक जोखिम वाले होस्ट के लिए एक चुना पता स्वीकृत करना समझने में आसान है।

प्रॉक्सी बदलता है कि स्थानीय DNS रिज़ॉल्यूशन कहाँ होता है। `ProxyJump` में क्लाइंट आम तौर पर जंप कनेक्शन से अंतिम होस्ट और पोर्ट तक ट्रैफ़िक पहुँचाने को कहता है। `ProxyCommand` लगभग कोई भी ट्रांसपोर्ट व्यवहार कर सकता है। स्थानीय रूप से दिखता पीयर पता प्रॉक्सी का हो सकता है, जबकि अंतिम नाम कहीं और रिज़ॉल्व हो। स्वीकृति में दोनों हॉप चाहिए: स्थानीय प्रक्रिया का ठोस प्रॉक्सी एंडपॉइंट और उसके भीतर भेजा अंतिम होस्ट मान। प्रॉक्सी पते को लक्ष्य मानना गंतव्य खोता है, उसे अप्रासंगिक मानना नेटवर्क पथ खोता है।

## सही होस्ट कुंजी माँगे गए नाम को सही नहीं बनाती

सख्त होस्ट कुंजी जाँच लक्ष्य स्वीकृति से अलग सीमा बचाती है। उसे चालू रखें, पर वह नहीं बता सकती कि कैननिकल परिणाम मानव के इरादे में था या नहीं। साझा होस्ट कुंजियां, कई principal वाले होस्ट प्रमाणपत्र और स्पष्ट `HostKeyAlias` ऐसे नाम के तहत क्रिप्टोग्राफ़िक रूप से सही कनेक्शन बना सकते हैं जो स्वीकृति पर नहीं दिखा।

RFC 4251 का SSH प्रोटोकॉल ढाँचा स्थानीय डेटाबेस बताता है जो उपयोगकर्ता के टाइप किए होस्ट नाम को होस्ट कुंजी से जोड़ता है। OpenSSH उस मूल मॉडल के ऊपर कॉन्फ़िग-आधारित नाम जोड़ता है। `HostKeyAlias` क्लाइंट को होस्ट कुंजी रिकॉर्ड पढ़ते या लिखते और प्रमाणपत्र जाँचते समय असली नाम की जगह उपनाम इस्तेमाल करने को कहता है। यह टनल और एक पते पर कई सर्वरों के लिए उपयोगी है, लेकिन ऑडिट में दर्ज करने योग्य एक और नाम बनाता है।

SSHFP रिकॉर्ड परिभाषित करने वाला RFC 4255 यहाँ खास मायने रखता है। वह अधूरे होस्ट नाम और घुसाए गए DNS खोज पथ से सावधान करता है, तथा उस स्थिति में DNS फ़िंगरप्रिंट से पहले स्थानीय होस्ट कुंजी डेटाबेस जाँचने की सलाह देता है। वह यह भी कहता है कि DNSSEC से प्रमाणित न हुआ SSHFP रिकॉर्ड भरोसेमंद नहीं है। सलाह सर्वर प्रमाणीकरण पर है, पर व्यापक बात यही है: नाम विस्तार सुरक्षा संदर्भ बदलता है और रिज़ॉल्वर आउटपुट पहचान का प्रमाण नहीं है।

RFC 4462 की GSS-API चेतावनी और साफ है। वह कहता है कि असुरक्षित DNS परिणाम से सर्वर लक्ष्य नाम नहीं बनाना चाहिए, क्योंकि हमलावर उपनाम या पता मैपिंग बदलकर सर्वर बन सकता है। एजेंट सामान्य सार्वजनिक कुंजी प्रमाणीकरण उपयोग करे, तब भी डिज़ाइन सीख वही है। असुरक्षित नाम बदलाव को उस पहचान का निर्णय नहीं करना चाहिए जिसे सुरक्षा नियंत्रण स्वीकृत बताता है।

होस्ट कुंजी सत्यापन कनेक्शन परिणाम को पूर्व जाँच रिकॉर्ड से फिर बाँधे। वास्तव में मिली फ़िंगरप्रिंट, खोज का नाम या उपनाम, प्रमाणपत्र principal का मेल और सख्त जाँच परिणाम लॉग करें। क्लाइंट नई कुंजी के संकेत पर लौटे, तो वह नया सुरक्षा निर्णय है। केवल इसलिए स्वचालित प्रक्रिया उसे स्वीकार न करे कि किसी ने पहले shell कमांड स्वीकृत की थी।

## पूर्व जाँच में वही OpenSSH इनपुट होने चाहिए

उपयोगी पूर्व जाँच क्लाइंट की अंतिम कॉन्फ़िग को दोहराती है और दूरस्थ कमांड चलाए बिना कनेक्शन पथ देखती है। `ssh -G` `Host` और `Match` ब्लॉक के मूल्यांकन के बाद कॉन्फ़िग दिखाता है। `ssh -vvv` रिज़ॉल्यूशन, कनेक्शन और होस्ट कुंजी निदान जोड़ता है; OpenSSH मैनुअल में तीन `-v` अधिकतम विस्तार हैं।

नियंत्रित वातावरण में यह क्रम चलाएँ और `build` को ठीक उसी अनुरोधित टोकन से बदलें:

```sh
ssh -G build | awk '
  $1 == "hostname" || $1 == "user" || $1 == "port" ||
  $1 == "proxyjump" || $1 == "proxycommand" ||
  $1 == "hostkeyalias" || $1 == "canonicalizehostname" {
    print
  }
'
ssh -vvv -o BatchMode=yes -o SessionType=none \
  -o ConnectTimeout=5 build 2>&1
```

पहली कमांड का आउटपुट इस रूप में होता है:

```text
user deploy
hostname build-07.hosts.example
port 22
canonicalizehostname true
proxyjump none
```

विस्तृत रन की पंक्तियां OpenSSH रिलीज़ के अनुसार बदलती हैं, लेकिन बढ़ा हुआ होस्ट, चुना पता और पोर्ट, कॉन्फ़िग पास तथा कुंजी विनिमय में मिली होस्ट कुंजी बताती हैं। एक्ज़ीक्यूटर से संरचित तथ्य लें, डिबग टेक्स्ट को स्थिर API न मानें। जाँच करने वाले ऑपरेटर के लिए कमांड अच्छे हैं; उत्पादन को वही तथ्य सॉकेट खोलने वाले कार्यान्वयन से लेने चाहिए।

इस निदान में दो जाल हैं। पहला, `ssh -G` निकली क्लाइंट कॉन्फ़िग दिखाता है, पर यह साबित नहीं करता कि बाद का कनेक्शन कौन सा पता चुनेगा और पाएगा। दूसरा, `SessionType=none` के साथ भी विस्तृत जाँच नेटवर्क कनेक्शन खोलकर कुंजी विनिमय कर सकती है; इसे तभी चलाएँ जब जाँच खुद अधिकृत हो। `BatchMode=yes` इंटरैक्टिव पासवर्ड और होस्ट कुंजी संकेत रोकता है, पर कनेक्शन को स्थानीय गणना नहीं बनाता।

दोहराई जा सकने वाली जाँच के लिए सभी इनपुट अलग करें। `-F` से अपेक्षित उपयोगकर्ता कॉन्फ़िग दें, क्लाइंट बिल्ड के सिस्टम कॉन्फ़िग व्यवहार को शामिल करें, `Include` या टोकन विस्तार के वातावरण चर तय करें और OpenSSH संस्करण दर्ज करें। यह भी दर्ज करें कि कंट्रोल सॉकेट पुराना मल्टीप्लेक्स कनेक्शन उपयोग कर सकता है या नहीं। निष्पादन पुराने मास्टर सत्र से जुड़ जाए तो नए DNS और कॉन्फ़िग की पूर्व जाँच बेकार है।

स्वीकृति के लिए एक बार और निष्पादन के लिए दूसरी बार अलग पार्स न करें। बेहतर रचना में एक एक्ज़ीक्यूटर कॉन्फ़िग लोड करता, कैननिकलाइज़ करता, रिज़ॉल्व करता, अपरिवर्तनीय उम्मीदवार रिकॉर्ड के साथ रुकता और स्वीकृति के बाद उसी स्थिति मशीन को आगे चलाता है। SSH लाइब्रेरी सुरक्षित रूप से न रुक सके तो सभी महत्वपूर्ण फ़ील्ड वाली हस्ताक्षरित या कुंजी-सुरक्षित टिकट बनाएँ और किसी भी अंतर पर कनेक्टर से मना कराएँ।

## स्वीकृति रिकॉर्ड में बदलाव दिखना चाहिए

अच्छा कार्ड बदलाव स्पष्ट करता है, लेकिन व्यक्ति को डिबग लॉग नहीं पढ़ाता। माँगा लक्ष्य, प्रभावी लक्ष्य और पता साथ रखें। बदलाव न हो तो संक्षेप में कहें। कैननिकलाइज़ेशन या `Match` ब्लॉक ने महत्वपूर्ण फ़ील्ड बदला हो तो पुराना और नया मान दिखाएँ।

व्यावहारिक स्वीकृति रिकॉर्ड यह रूप ले सकता है:

```json
{
  "requested": {
    "host": "build",
    "user": "deploy",
    "command": "/usr/local/bin/release status"
  },
  "effective": {
    "host": "build-07.hosts.example",
    "address": "192.0.2.44",
    "port": 22,
    "user": "deploy",
    "proxy": null,
    "host_key_alias": null
  },
  "resolution": {
    "canonicalized": true,
    "source": "build.ops.example",
    "permitted_cname": true
  },
  "binding": "sha256:REDACTED"
}
```

बाइंडिंग में अनुरोधित और प्रभावी फ़ील्ड की तय एन्कोडिंग, दूरस्थ कमांड, फ़ॉरवर्डिंग विकल्प, संबंधित कॉन्फ़िग पहचान, चुना पता या स्वीकृत पता सेट और छोटी समाप्ति शामिल हो। कनेक्टर सॉकेट खोलने से ठीक पहले बाइंडिंग फिर निकाले। DNS, कॉन्फ़िग, कमांड, उपयोगकर्ता, पोर्ट या प्रॉक्सी मार्ग अलग हो तो रुक जाए।

केवल इसलिए कार्ड से फ़ील्ड न हटाएँ कि वह बाइंडिंग में है। मनुष्य वही अधिकृत करते हैं जो उन्हें दिखता है। `build -> build-07.hosts.example (192.0.2.44)` को एक पढ़ने योग्य बदलाव की तरह दिखाएँ, फिर उपयोगकर्ता, पोर्ट, प्रॉक्सी और कमांड रखें। कच्ची फ़िंगरप्रिंट और कॉन्फ़िग स्रोत विस्तार वाले विवरण में रह सकते हैं, सिवाय उस समय के जब नई या बदली होस्ट पहचान पर ध्यान चाहिए।

मुश्किल स्थिति वह नाम है जो बड़े या तेज़ी से बदलते पूल में रिज़ॉल्व होता है। इस नाम के वर्तमान किसी भी पते जैसी असीम धारणा स्वीकृत न करें। एक उम्मीदवार चुनें, समाप्ति वाला सीमित प्रकाशित सेट स्वीकृत करें, या विश्वसनीय CA वाले होस्ट प्रमाणपत्र principal जैसी स्थिर मजबूत पहचान माँगें। मॉडल स्पष्ट लिखा होना चाहिए, कनेक्टर अनुमान न लगाए।

## प्रॉक्सी और कनेक्शन पुन: उपयोग की अलग बाइंडिंग चाहिए

प्रॉक्सी के साथ कैननिकलाइज़ेशन अलग चलता है। `CanonicalizeHostname yes` केवल बिना `ProxyCommand` या `ProxyJump` कनेक्शन पर लागू है; `always` प्रॉक्सी कनेक्शन भी शामिल करता है। एक शब्द का अंतर अंतिम नाम बदलकर दूसरा कॉन्फ़िग पास चला सकता है। स्वीकृति सिस्टम वास्तविक मान दर्ज करे, यह न माने कि यह हर जगह चालू या बंद है।

हर जंप होस्ट अपनी SSH कनेक्शन है, जिसका अनुरोधित नाम, प्रभावी नाम, पता, उपयोगकर्ता, पोर्ट और प्रमाणित होस्ट कुंजी है। टनल का अंतिम लक्ष्य भी अपनी पहचान रखता है। केवल अंतिम लेबल स्वीकृत करने से अप्रत्याशित या कब्ज़े वाला जंप मार्ग छूटता है। केवल जंप सर्वर स्वीकृत करने से उसका अंतिम फ़ॉरवर्ड गंतव्य छूटता है।

कनेक्शन मल्टीप्लेक्सिंग कम स्पष्ट रास्ता बनाती है। मिलता `ControlMaster` सत्र मौजूद हो तो नया `ssh` कॉल पूर्व जाँच वाला कनेक्शन बनाने की जगह उसे उपयोग कर सकता है। पुराने मास्टर ने पहले DNS रिज़ॉल्व किया, पुराना कॉन्फ़िग इस्तेमाल किया और मौजूदा स्वीकृति से पहले होस्ट कुंजी प्रमाणित की हो सकती है। नियंत्रित एजेंट कार्रवाई में पुन: उपयोग बंद करें या स्वीकृति को मास्टर सत्र की अपरिवर्तनीय कनेक्शन पहचान से बाँधकर चैनल खोलने से पहले जाँचें।

यही नियम दोबारा कोशिश पर लागू है। एक पता विफल होने पर दूसरा पता तभी अधिकृत है जब दिखाए स्वीकृत सेट में था। प्रॉक्सी फ़ॉलबैक, वैकल्पिक पोर्ट या नया कैननिकल नाम साधारण ट्रांसपोर्ट विवरण नहीं हैं। वे प्राधिकरण की वस्तु बदलते हैं और नया निर्णय माँगते हैं।

## ऑडिट प्रमाण में इरादा और परिणाम दोनों रहें

उपयोगी SSH ऑडिट प्रविष्टि जाँचकर्ता को DNS फिर चलाए बिना पूरा बदलाव बनाने देती है। मूल एजेंट अनुरोध, प्रभावी OpenSSH कॉन्फ़िग फ़ील्ड, कैननिकल नाम, DNS शृंखला, उम्मीदवार पते, चुना पता, प्रॉक्सी हॉप, स्वीकृत होस्ट फ़िंगरप्रिंट, प्रमाणपत्र principal और माँगी कमांड या सबसिस्टम रखें। रिज़ॉल्यूशन और सॉकेट कनेक्शन के समय अलग दर्ज करें ताकि समय अंतर दिखे।

Sallyport अपने साथ आए `sp-ssh` सहायक से SSH कार्रवाई चलाता है जबकि कुंजियां एन्क्रिप्टेड वॉल्ट में रहती हैं, इसलिए एजेंट को SSH निजी कुंजी नहीं मिलती। इसकी Activity और Sessions जर्नल एक एन्क्रिप्टेड, हैश-चेन ऑडिट लॉग से बनती हैं, जिससे स्वीकृति और निष्पादन पथ केवल shell जैसी स्ट्रिंग के बजाय अनुरोधित और देखे गए दोनों लक्ष्य रख सकते हैं।

रिकॉर्ड रखना पर्याप्त नहीं है। परीक्षण योग्य नियम बनाएँ: चला पता स्वीकृत उम्मीदवार सेट में था, प्रभावी होस्ट और पोर्ट टिकट से मिले, स्वीकृत होस्ट पहचान दर्ज हुई और हर प्रयास या प्रॉक्सी हॉप अधिकृत था। परीक्षण को `CanonicalizeHostname`, अनुमत CNAME, `Match canonical` ब्लॉक और दो DNS उत्तर वाला कॉन्फ़िग दें। पूर्व जाँच और कनेक्शन के बीच एक तथ्य बदलें और पक्का करें कि निष्पादन रुकता है।

रोकने योग्य विफलता साधारण है: एजेंट `build` माँगता है, व्यक्ति उपनाम पहचानकर स्वीकृत करता है और दूसरे नेटवर्क का क्लाइंट उसे दूसरे डोमेन में बढ़ा देता है। SSH सत्र एन्क्रिप्टेड हो सकता है और सर्वर अपने नाम के लिए सही कुंजी दे सकता है। स्वीकृति फिर भी गलत है। माँगा नाम, अंतिम नाम और चुना पता एक निर्णय में रखें और कनेक्टर से साबित कराएँ कि उसने वही मान उपयोग किए।
