# क्या रद्द SSH होस्ट कुंजी फिर भी एजेंट को प्रवेश दे सकती है?

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

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

## निरस्तीकरण कुंजी के साथ चलना चाहिए, होस्टनाम के साथ नहीं

होस्ट कुंजी SSH कुंजी विनिमय के दौरान सर्वर को प्रमाणित करती है। RFC 4253 बताता है कि क्लाइंट सर्वर की सार्वजनिक होस्ट कुंजी प्राप्त करता है, जांचता है कि वह इच्छित सर्वर की है, और विनिमय पर सर्वर के हस्ताक्षर को सत्यापित करता है। निरस्तीकरण इसी जांच पर लागू होना चाहिए: सर्वर निषिद्ध सार्वजनिक कुंजी प्रस्तुत करे, तो क्लाइंट को उपयोगकर्ता कुंजी, पासवर्ड या रिमोट कमांड पर विचार करने से पहले उसे अस्वीकार करना चाहिए।

OpenSSH दो ऐसे तरीके देता है जो देखने में समान हैं, लेकिन उनकी पहुंच अलग है। known-hosts फ़ाइल में `@revoked` से शुरू होने वाली पंक्ति होस्ट पैटर्न को रद्द कुंजी से जोड़ती है। यह तब काम करती है जब कनेक्शन का लुकअप नाम उस पंक्ति से मेल खाता है। उपनाम या पते का दूसरा रूप पैटर्न से चूक सकता है, भले ही सर्वर वही कुंजी प्रस्तुत करे। OpenSSH का `sshd` मैनुअल कहता है कि मेल खाने वाली रद्द प्रविष्टि कभी स्वीकार नहीं होनी चाहिए, लेकिन यहां “मेल खाने वाली” शर्त मायने रखती है।

क्लाइंट का `RevokedHostKeys` विकल्प घटना के दौरान निरस्तीकरण के लिए बेहतर है। यह सार्वजनिक कुंजियों वाली टेक्स्ट फ़ाइल या OpenSSH Key Revocation List (KRL) की ओर इशारा करता है। OpenSSH प्रस्तुत पहचान को उस फ़ाइल से मिलाता है, चाहे उपयोगकर्ता ने `build-test`, `build-test.example` या सीधा IP पता टाइप किया हो। मैं किसी खास होस्ट की known-hosts व्यवस्था के लिए `@revoked` प्रविष्टि इस्तेमाल करता हूं; जब क्रिप्टोग्राफ़िक पहचान को हर जगह बंद करना हो, तब `RevokedHostKeys` इस्तेमाल करता हूं।

इन दोनों को `StrictHostKeyChecking=yes` न समझें। सख्त जांच अज्ञात होस्ट और बदली हुई कुंजियां अस्वीकार करती है, जिससे पहली बार उपयोग पर चुपचाप भरोसा नहीं बनता। वह किसी ऐसी कुंजी को रद्द घोषित नहीं करती जिस पर पहले भरोसा था। पुराने known-host रिकॉर्ड को हटाकर अज्ञात होस्ट की विफलता पर खुशी मनाने वाला परीक्षण खाली भरोसा डेटाबेस जांचता है, निरस्तीकरण नहीं।

## ऐसा परीक्षण होस्ट बनाएं जिसे जानबूझकर तोड़ सकें

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

नीचे की संरचना सारे प्रमाण को एक डायरेक्टरी में रखती है। हर ऑपरेटिंग सिस्टम में `sshd` का पथ और अनुमति मॉडल अलग हो सकता है, इसलिए डेमन को उसी कंटेनर, VM या परीक्षण फ़िक्स्चर में चलाएं जिसे आपकी टीम SSH इंटीग्रेशन परीक्षणों के लिए पहले से इस्तेमाल करती है।

```bash
set -eu
work="$PWD/ssh-revocation-fixture"
mkdir -p "$work/client" "$work/server"
chmod 700 "$work/client"

ssh-keygen -q -t ed25519 -N '' \
  -C revoked-host-test -f "$work/server/ssh_host_ed25519_key"
ssh-keygen -q -t ed25519 -N '' \
  -C agent-test-user -f "$work/client/id_ed25519"

ssh-keygen -lf "$work/server/ssh_host_ed25519_key.pub"
```

आखिरी कमांड इस आकार की पंक्ति दिखाता है:

```text
256 SHA256:<base64-fingerprint> revoked-host-test (ED25519)
```

उस फ़िंगरप्रिंट को परीक्षण लॉग में दर्ज करें। टिकट से फ़िंगरप्रिंट कॉपी करके यह न मानें कि फ़िक्स्चर फ़ाइल में वही कुंजी है। फ़िंगरप्रिंट उस सार्वजनिक कुंजी फ़ाइल से निकालें जिसे परीक्षण सर्वर सच में लोड करता है।

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

निरस्तीकरण जोड़ने से पहले एक सख्त कनेक्शन सफल कराएं और `printf BASELINE_OK` जैसा सुरक्षित संकेतक कमांड चलाएं। होस्ट कुंजी को प्रमाणित प्रोविज़निंग चरण से लें, उसी नेटवर्क पथ पर बिना जांचा `ssh-keyscan` चलाकर नहीं जिसे आप सुरक्षित करना चाहते हैं। `ssh-keyscan` कुंजियां लाता है, लेकिन यह साबित नहीं करता कि उन्हें किसने दिया।

## रद्द पहचान को KRL में रखें

KRL परीक्षण को गंतव्य की वर्तनी के बजाय कुंजी पर केंद्रित करता है। फ़िक्स्चर द्वारा लोड की गई सार्वजनिक कुंजी से इसे सीधे बनाएं, फिर किसी नेटवर्क प्रयास से पहले इसे पूछकर जांचें:

```bash
work="$PWD/ssh-revocation-fixture"
ssh-keygen -k -f "$work/client/revoked-hosts.krl" \
  "$work/server/ssh_host_ed25519_key.pub"

if ssh-keygen -Q -f "$work/client/revoked-hosts.krl" \
  "$work/server/ssh_host_ed25519_key.pub"; then
  printf '%s\n' 'FAIL: fixture host key is not revoked'
  exit 1
else
  printf '%s\n' 'OK: fixture host key is revoked'
fi
```

उलटी निकास स्थिति लोगों को अक्सर भ्रमित करती है। `ssh-keygen` मैनुअल के अनुसार `-Q` तब गैर-शून्य लौटाता है जब पूछी गई कोई कुंजी रद्द हो या कोई त्रुटि आए; शून्य का मतलब है कि कोई पूछी गई कुंजी रद्द नहीं है। stderr को न फेंकें, और आसपास के परीक्षण लॉग में अपठनीय KRL को सही निरस्तीकरण मिलान से अलग दिखाएं।

अब फ़ाइल को एजेंट द्वारा इस्तेमाल क्लाइंट कॉन्फ़िगरेशन के सबसे व्यापक दायरे में लगाएं:

```sshconfig
Host *
    BatchMode yes
    StrictHostKeyChecking yes
    UserKnownHostsFile ./ssh-revocation-fixture/client/known_hosts
    RevokedHostKeys ./ssh-revocation-fixture/client/revoked-hosts.krl
    ConnectTimeout 5
    ConnectionAttempts 1
```

यदि `RevokedHostKeys` फ़ाइल मौजूद न हो या पढ़ी न जा सके, तो OpenSSH जानबूझकर बंद होकर विफल होता है: उस कॉन्फ़िगरेशन में आने वाले हर गंतव्य का होस्ट प्रमाणीकरण रोक दिया जाता है। यह फ़ाइल को अनदेखा करने से अधिक सुरक्षित है, लेकिन टूटी तैनाती को सफल निरस्तीकरण परीक्षण जैसा दिखा सकता है। ऊपर की पूर्व-जांच साबित करती है कि फ़ाइल पढ़ी जा सकती है और उसमें इच्छित कुंजी है।

प्रति पंक्ति एक सार्वजनिक कुंजी वाली साधारण टेक्स्ट फ़ाइल भी काम करती है। बहुत सी कुंजियों या होस्ट प्रमाणपत्रों पर KRL की जटिलता उपयोगी होती है, क्योंकि वह सामान्य कुंजियां, प्रमाणपत्र क्रमांक, प्रमाणपत्र कुंजी ID या किसी CA से हस्ताक्षरित कुंजियां रद्द कर सकती है। वितरण और जांच प्रक्रिया जिस सबसे सरल प्रारूप को संभाल सके, उसे चुनें, फिर उसी प्रारूप का परीक्षण करें जिसे तैनात करते हैं।

## होस्टनाम तक सीमित मार्कर का विरोधी परीक्षण जरूरी है

फ़िक्स्चर में एक जानबूझकर कमजोर मामला रखें, ताकि KRL की जरूरत साफ़ दिखे। दूसरा क्लाइंट कॉन्फ़िगरेशन बनाएं जिसमें `RevokedHostKeys` न हो और केवल इस known-hosts प्रविष्टि पर भरोसा हो:

```text
@revoked revoked-lab ssh-ed25519 AAAA...fixture-public-key...
```

`revoked-lab` नाम से जुड़ें और पुष्टि करें कि OpenSSH मिलती प्रविष्टि को अस्वीकार करता है। फिर उसी लिसनर से `127.0.0.1` नाम से जुड़ें, जबकि `[127.0.0.1]:2222` के लिए अलग भरोसेमंद known-host प्रविष्टि मौजूद हो। यदि इस पते से सफलता मिलती है, तो फ़िक्स्चर ने कवरेज का अंतर दोहरा दिया: कुंजी नहीं बदली, लेकिन लुकअप नाम अब रद्द मार्कर से नहीं मिलता। इस प्रदर्शन को उत्पादन कॉन्फ़िगरेशन से अलग रखें, क्योंकि इसका उद्देश्य एक अपर्याप्त नियंत्रण दिखाना है।

उदाहरण का छोटा किया हुआ `AAAA...` मान चिपकाएं नहीं। रिकॉर्ड असली सार्वजनिक कुंजी फ़ाइल से बनाएं ताकि एल्गोरिदम और base64 कुंजी डेटा बिल्कुल सही हों। सुरक्षित फ़िक्स्चर कमांड सार्वजनिक फ़ाइल से एल्गोरिदम और कुंजी फ़ील्ड पढ़कर उनके आगे मार्कर और इच्छित होस्ट पैटर्न जोड़ सकता है। परिणाम को `ssh-keygen -F revoked-lab -f known_hosts` से जांचें; फिर सीधे पते के लिए खोज दोहराकर दिखाएं कि वहां रिकॉर्ड नहीं है।

यह विफलता बताती है कि हर ज्ञात उपनाम को `@revoked` पंक्ति में जोड़ना नाजुक क्यों है। जब भी कोई छोटा नाम, DNS रिकॉर्ड, स्थानीय hosts फ़ाइल प्रविष्टि, गैर-डिफ़ॉल्ट पोर्ट, टनल उपनाम या `HostKeyAlias` जोड़ता है, सूची बदल जाती है। हैश किए known-host नामों की मानवीय समीक्षा कठिन है, हालांकि `ssh-keygen -F` उन्हें खोज सकता है। वाइल्डकार्ड मार्कर मिलान बढ़ाता है, पर सार्वजनिक कुंजी तभी रद्द होगी जब गंतव्य उस पैटर्न के अंदर आए; इसके इच्छित दायरे की समीक्षा भी कठिन होती है।

KRL मामले में वही सर्वर, उपयोगकर्ता कुंजी, नेटवर्क रास्ता और भरोसेमंद known-host रिकॉर्ड इस्तेमाल होने चाहिए। केवल निरस्तीकरण तरीका बदलें। `RevokedHostKeys` सक्रिय होने पर `revoked-lab` और `127.0.0.1`, दोनों को फ़िक्स्चर कुंजी मिलने के बाद विफल होना चाहिए। यह जोड़ा प्रयोग उपनाम से जुड़ी अमूर्त चेतावनी को ऐसी विफलता में बदलता है जिसे समीक्षक देख और दोहरा सकते हैं।

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

सिस्टम और उपयोगकर्ता कॉन्फ़िगरेशन एक और विभाजन बनाते हैं। इंजीनियर का `/etc/ssh/ssh_config` संगठन के KRL की ओर इशारा कर सकता है, जबकि एजेंट `ssh -F private-config` से शुरू हो, जो OpenSSH को वैकल्पिक कॉन्फ़िगरेशन देता है। दूसरी दिशा में, साफ़ CI खाता परीक्षण पास कर सकता है लेकिन उत्पादन रनर द्वारा कमांड लाइन पर डाले विकल्पों का मॉडल न बनाए। एजेंट की कार्रवाई सीमा पर पूरी कॉल दर्ज करें और वहीं निरस्तीकरण पथ स्पष्ट रखें।

अनुमतियां स्वीकृति परीक्षण का हिस्सा हैं। OpenSSH मैनुअल के अनुसार `RevokedHostKeys` पढ़ने में विफलता हर होस्ट का प्रमाणीकरण रोकती है। कनेक्शन से पहले एजेंट के ऑपरेटिंग-सिस्टम उपयोगकर्ता के रूप में फ़ाइल जांचें और इच्छित कुंजी पूछें। इससे तीन ऐसे नतीजे अलग होते हैं जो सभी विफल SSH कमांड जैसे दिखते हैं: सही निरस्तीकरण मिलान, गायब या अपठनीय निरस्तीकरण फ़ाइल, और खराब KRL।

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

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

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

## नया कनेक्शन संकेतक चलने से पहले विफल होना चाहिए

पहले नकारात्मक मामले को नया ट्रांसपोर्ट बनाने के लिए मजबूर करें। उपयोगकर्ता के SSH कॉन्फ़िगरेशन में कनेक्शन साझाकरण चालू हो तब भी कमांड लाइन पर उसे बंद करें, क्लाइंट को गैर-संवादात्मक रखें, और रिमोट कमांड में ऐसा चिन्ह डालें जो चलने पर साफ़ दिखाई दे।

```bash
work="$PWD/ssh-revocation-fixture"
config="$work/client/config"
log="$work/client/direct.stderr"

set +e
ssh -F "$config" \
  -o ControlMaster=no -o ControlPath=none \
  -i "$work/client/id_ed25519" \
  -p 2222 testuser@127.0.0.1 \
  'printf REVOKED_KEY_EXECUTED' \
  >"$work/client/direct.stdout" 2>"$log"
rc=$?
set -e

if [ "$rc" -eq 0 ]; then
  printf '%s\n' 'FAIL: SSH accepted a revoked host identity'
  exit 1
fi
if grep -q REVOKED_KEY_EXECUTED "$work/client/direct.stdout"; then
  printf '%s\n' 'FAIL: remote sentinel ran'
  exit 1
fi
printf 'PASS rc=%s\n' "$rc"
```

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

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

खाली लेकिन पठनीय KRL या किसी दूसरी गैर-रद्द सर्वर कुंजी के साथ एक नियंत्रण मामला चलाएं। उस कनेक्शन को `BASELINE_OK` तक पहुंचना चाहिए। सकारात्मक नियंत्रण के बिना नकारात्मक परीक्षण अक्सर इसलिए पास होता है क्योंकि DNS, रूटिंग, फ़ाइल अनुमति या फ़िक्स्चर खाता पहले से खराब था।

## हर उपनाम और पता रूप का अपना मामला होना चाहिए

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

फ़िक्स्चर से जुड़ी छोटी सूची से शुरू करें:

1. कॉन्फ़िगर उपनाम, जैसे `revoked-lab`, जिसका `HostName` परीक्षण पते की ओर जाता है।
2. पूर्ण डोमेन होस्टनाम और स्थानीय रिज़ॉल्वर नियमों से स्वीकार कोई छोटा होस्टनाम।
3. सीधा IPv4 पता और, यदि लिसनर के पास हो, सीधा IPv6 पता।
4. गैर-डिफ़ॉल्ट पोर्ट वाला known-host टोकन, जिसे known-hosts औज़ार आम तौर पर `[host]:port` लिखते हैं।
5. `HostKeyAlias` सेट करने वाला उपनाम, क्योंकि यह विकल्प होस्ट-कुंजी लुकअप और होस्ट प्रमाणपत्र सत्यापन के लिए असली होस्टनाम को बदल देता है।

शेल ब्लॉक दोहराने के बजाय रूपों को डेटा फ़ाइल या परीक्षण फ़ंक्शन में रखें। हर उपयोगकर्ता-दिखने वाले नाम के लिए `ssh -G destination` देखें और निकले `hostname`, `port`, `hostkeyalias`, `userknownhostsfile`, `revokedhostkeys`, `proxycommand`, `proxyjump`, `controlmaster` और `controlpath` मान बचाएं। `ssh -G` बिना जुड़े कॉन्फ़िगरेशन फैलाता है, इसलिए वह ऐसे `Host` खंड को पकड़ता है जो चुपचाप KRL पथ बदलता है।

`Hostname` और `HostKeyAlias` अलग काम करते हैं। `Hostname` नेटवर्क गंतव्य चुनता है। `HostKeyAlias` वह नाम चुनता है जिससे OpenSSH होस्ट कुंजियां पढ़ता या लिखता और होस्ट प्रमाणपत्र जांचता है। दोनों में से किसी को वैश्विक `RevokedHostKeys` जांच कमजोर नहीं करनी चाहिए, लेकिन दोनों यह बदल सकते हैं कि OpenSSH कौन सा भरोसेमंद known-host रिकॉर्ड देखता है। इसलिए केवल होस्टनाम वाला `@revoked` रिकॉर्ड घटना नियंत्रण के लिए खराब है।

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

`CheckHostIP=yes` को उपनाम कवरेज न मानें। OpenSSH मैनुअल कहता है कि यह known-hosts में गंतव्य IP भी जांचता है, और प्रॉक्सी कमांड वाले कनेक्शन में उपलब्ध नहीं है। यह बदला संबंध पहचान सकता है, पर कुंजी-केंद्रित निरस्तीकरण फ़ाइल की जगह नहीं लेता। प्रॉक्सी और जंप रास्तों में अंतिम लक्ष्य का पूरा परीक्षण तथा हर जंप होस्ट के लिए अलग भरोसा कॉन्फ़िगरेशन चाहिए।

## कैश किए कनेक्शन घटना प्रतिक्रिया की सीमा हैं

चालू मल्टीप्लेक्स SSH मास्टर सर्वर को पहले ही प्रमाणित कर चुका है। उसके कंट्रोल सॉकेट से दूसरा सत्र खोलने पर नया TCP कनेक्शन या होस्ट-कुंजी विनिमय नहीं होता, इसलिए नया KRL पिछली जांच को पलटकर कुंजी अस्वीकार नहीं कर सकता। इसे निरस्तीकरण बायपास कहना मॉडल को धुंधला करता है। यह उस प्रमाणित ट्रांसपोर्ट का दोबारा उपयोग है जो अभी मौजूद है।

फ़िक्स्चर में इस व्यवहार को साबित करें, यह न मानें कि पुनरारंभ सब साफ़ कर देगा। होस्ट कुंजी स्वीकार्य रहते मल्टीप्लेक्स मास्टर बनाएं। उसे `ControlPersist` से चालू रखें, कुंजी KRL में जोड़ें, फिर दिखाएं कि `ssh -O check` अभी भी मास्टर पाता है। उस सॉकेट से भेजा कमांड चल सकता है। इसे सुधार से पहले का अपेक्षित नियंत्रण मानें, निरस्तीकरण की सफल स्थिति नहीं।

इसके बाद प्रतिक्रिया करें: एजेंट को नया काम खोलने से रोकें, संबंधित कंट्रोल मास्टर बंद करें, और उनके मालिक एजेंट सत्र को रद्द या रोकें। फ़िक्स्चर के समर्पित सॉकेट के लिए स्थानीय कमांड इस आकार का है:

```bash
socket="$PWD/ssh-revocation-fixture/client/cm-testuser-127.0.0.1-2222"
ssh -S "$socket" -O exit testuser@127.0.0.1
```

सॉकेट गायब होने पर `ControlMaster=no` और `ControlPath=none` के साथ कनेक्शन दोहराएं; उसे रद्द कुंजी पर विफल होना चाहिए। सफ़ाई के बाद एजेंट का सामान्य मल्टीप्लेक्स कॉन्फ़िगरेशन भी जांचें। `ControlMaster auto` जैसे अवसरवादी मोड में मास्टर न मिलने पर नया कनेक्शन बनता है, और उस नए प्रयास को KRL रोकना चाहिए।

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

सक्रिय घटना में होस्ट पहचान रद्द करने के लिए दो नियंत्रण चाहिए: भविष्य के कुंजी विनिमय अस्वीकार करना और निरस्तीकरण से पहले प्रमाणित ट्रांसपोर्ट खत्म करना। केवल एक जांचने वाला परीक्षण एजेंट के लिए या तो नया रास्ता छोड़ेगा या ऐसा पुराना रास्ता जो कभी बंद नहीं हुआ।

## एक सर्वर एक से अधिक पहचान प्रस्तुत कर सकता है

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

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

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

होस्ट प्रमाणपत्र एक और अंतर जोड़ते हैं। आप प्रमाणपत्र को सार्वजनिक वस्तु मानकर रद्द कर सकते हैं, KRL में क्रमांक या कुंजी ID रद्द कर सकते हैं, या होस्ट वर्ग को अधिकृत करने वाला CA रद्द कर सकते हैं। इन विकल्पों का प्रभाव क्षेत्र अलग है। OpenSSH का `ssh-keygen` मैनुअल क्रमांक, कुंजी ID, सार्वजनिक कुंजी और फ़िंगरप्रिंट के KRL निर्देश बताता है; तैयार KRL को उसी प्रमाणपत्र फ़ाइल से पूछें जिसे सर्वर प्रस्तुत करता है।

`UpdateHostKeys` पर भी ध्यान दें। OpenSSH पहले से भरोसेमंद सामान्य कुंजी से होस्ट प्रमाणित होने के बाद सर्वर की अतिरिक्त कुंजियां सीख सकता है। यह योजनाबद्ध रोटेशन में मदद करता है, लेकिन पहले सीखी वैकल्पिक कुंजियां उम्मीदवार रहती हैं जब तक निरस्तीकरण निर्णय उन्हें शामिल न करे। हर नाम और `[name]:port` रूप के लिए `ssh-keygen -F` से परीक्षण क्लाइंट के known-hosts रिकॉर्ड निकालें, फिर हर सार्वजनिक कुंजी को घटना दायरे से मिलाएं।

## नकारात्मक परीक्षण एजेंट के असली रास्ते से चलाएं

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

हर रूप के लिए संरचित प्रमाण लौटाएं: गंतव्य लेबल, निकला होस्टनाम और पोर्ट, प्रस्तुत फ़िंगरप्रिंट, KRL डाइजेस्ट, कनेक्शन-साझा स्थिति, निकास स्थिति, संकेतक दिखा या नहीं, और सर्वर ने प्रयास किस चरण पर बंद किया। उस रिकॉर्ड में रहस्य न रखें। उपयोगी दावा सीधा है: रद्द पहचान प्रस्तुत हुई, क्लाइंट ने उसे रद्द माना, और उसके बाद उपयोगकर्ता प्रमाणीकरण या कमांड नहीं हुआ।

परीक्षण वातावरण अलग करने से छिपी निर्भरताएं सामने आती हैं। फ़िक्स्चर में SSH कॉन्फ़िगरेशन पथ, known-hosts फ़ाइल, KRL, पहचान फ़ाइल और कंट्रोल पथ साफ़ सेट करें। यदि एजेंट को असंबंधित उपयोगकर्ता कुंजियां नहीं लेनी चाहिए, तो `SSH_AUTH_SOCK` हटाएं या बदलें। कनेक्शन समय सीमित रखें ताकि CI न अटके। विफलता पर stderr और सर्वर लॉग कलाकृति के रूप में रखें; सफल रिपोर्ट उनके हैश और निर्णायक पंक्तियां रख सकती है।

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

ऑटोमेशन आसान करने के लिए क्लाइंट कमजोर न करें। `StrictHostKeyChecking=no`, खाली known-hosts लक्ष्य या निदान को `/dev/null` में फेंकना सुरक्षा परीक्षण को कनेक्टिविटी जांच बना देता है। `BatchMode=yes` संकेत हटाता है; वह गायब भरोसा सामग्री की भरपाई नहीं करता।

## निरस्तीकरण परीक्षण केवल एक कारण से विफल होना चाहिए

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

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

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

सूट को ऐसे एजेंट प्रोसेस से चलाएं जो संकेत नहीं दिखा सकता। मंजूरी संवाद, पासवर्ड अनुरोध या होस्ट-पुष्टि सवाल काम को सामान्य टाइमआउट तक लटका सकते हैं और असली कारण छिपा सकते हैं। `BatchMode=yes` को ये रास्ते तुरंत विफल करने चाहिए, जबकि सकारात्मक नियंत्रण साबित करता है कि फ़िक्स्चर को संवाद की जरूरत नहीं। बाहरी काम पर कड़ा टाइमआउट रखें, पर उसे निरस्तीकरण प्रमाण न मानें।

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

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