Autonomous agents के लिए SSH port forwarding: अधिक सुरक्षित tunnels
Autonomous agents के लिए SSH port forwarding में सख्त route limits, समय-सीमा वाला access और ऐसे approval records चाहिए जो incident review में टिक सकें।

Autonomous agents के लिए SSH port forwarding का design सामान्य developer access से अधिक सख्त होना चाहिए। कोई tunnel localhost तक सीमित database, admin panel या staging service को एक ही SSH command के ज़रिए agent की पहुँच में ला सकता है। अगर agent के पास व्यापक SSH credentials हैं, तो tunnel केवल एक लक्षण है। असली समस्या यह है कि उस command के पीछे destination, duration या authority को किसी ने सीमित नहीं किया।
मैंने teams को किसी tunnel को «temporary» कहते देखा है, सिर्फ इसलिए कि किसी ने terminal में ssh -L टाइप किया था। फिर terminal कई दिनों तक खुला रहा, उसका port किसी दूसरे process की dependency बन गया और security team के पूछने पर tunnel खोलने वाला व्यक्ति उपलब्ध नहीं था कि production के पास वाली service पर यह अनजान listener क्यों चल रहा है। Autonomous work इस pattern को और खराब करता है, क्योंकि agent किसी distracted human से कहीं अधिक लगातार retry, reconnect और tunnel का इस्तेमाल कर सकता है।
सुरक्षित तरीका सीधा है: agent को सीमित connection path दें, किसी खास temporary exposure को मंज़ूरी दें, इतना context रिकॉर्ड करें कि बाद में पूरी घटना समझी जा सके और closure को इच्छा नहीं, enforce होने वाली घटना बनाएँ।
Tunnel केवल SSH behavior नहीं, network reachability बदलता है
SSH port forward, SSH connection के एक तरफ listener बनाता है और उसका traffic दूसरी तरफ से reachable destination तक पहुँचाता है। यह listener एक access path है। इसे केवल «SSH access» के रूप में review करने पर जोखिम का असली हिस्सा छूट जाता है: कौन connect कर सकता है, traffic कहाँ पहुँचता है और इसके ज़रिए क्या भेजा जा सकता है।
मान लें कि build host पर चल रहा agent db-admin.internal.example के port 5432 पर query करना चाहता है। Local forward इस service को build host पर 127.0.0.1:15432 के रूप में उपलब्ध करा सकता है। Database public internet से private रहता है, लेकिन उस host पर listener तक पहुँचने वाला हर process अब connection का प्रयास कर सकता है। SSH server database तक जाने वाला authorized route भी बन जाता है।
यह स्वीकार्य हो सकता है। लेकिन यह agent को «maintenance के लिए SSH इस्तेमाल करने» देने के बराबर नहीं है। Approval में यह exact route होना चाहिए:
- initiating workload और host
- listener address और port
- target host और port
- route का कारण
- expiry और approving person
Remote forward में listener की जगह उलट जाती है। अगर agent bastion से बाहर connect करके bastion को port 18080 पर listen करने को कहता है, तो उस listener तक पहुँचने वाला process agent host की ओर वापस traffic प्राप्त कर सकता है। Remote forwarding अक्सर teams को इसलिए चौंकाता है क्योंकि यह inbound firewall rule खोले बिना firewall के पीछे की service को expose कर सकता है।
OpenSSH इन modes को ssh(1) में अलग-अलग दर्ज करता है: -L local forwards, -R remote forwards और -D SOCKS proxy बनाता है। यह operationally उपयोगी अंतर है। «Port forwarding» को एक ही permission न मानें। हर mode अलग listener expose करता है और अलग restrictions माँगता है।
Local, remote और dynamic forwarding के लिए अलग फैसले चाहिए
जब agent को controlled jump host के ज़रिए किसी एक ज्ञात service की ज़रूरत हो, तो local forward आम तौर पर सही विकल्प होता है। Listener agent की ओर होता है और SSH server internal destination से connect करता है। Command इस तरह दिख सकती है:
ssh -N \
-L 127.0.0.1:15432:db-admin.internal.example:5432 \
[email protected]
-N SSH को remote command न चलाने के लिए कहता है। इससे connection harmless नहीं हो जाता। Bind address 127.0.0.1 listener को local host तक सीमित करता है, जबकि db-admin.internal.example:5432 requested destination बताता है। ये अलग properties हैं और approval record में दोनों होनी चाहिए।
Remote forward तभी उचित है जब किसी ने remote side पर listener बनाने का स्पष्ट निर्णय लिया हो। नीचे दी गई command bastion को उसके loopback interface पर listen करने और traffic को agent machine के port 8080 तक वापस ले जाने को कहती है:
ssh -N \
-R 127.0.0.1:18080:127.0.0.1:8080 \
[email protected]
Remote loopback listener को अपने आप सुरक्षित न मानें। Bastion पर चलने वाले local process को agent की source machine से कहीं अधिक access हो सकता है और shared bastion पर कोई दूसरा user भी वहाँ पहुँच सकता है। इसे अनुमति देने से पहले remote host के users और local processes की समीक्षा करें।
Autonomous agents के लिए dynamic forwarding को default रूप से अस्वीकार करें:
ssh -N -D 127.0.0.1:1080 [email protected]
इससे SOCKS listener शुरू होता है। Client बाद में SOCKS requests के ज़रिए destinations चुनता है, इसलिए SSH command में किसी एक destination का नाम नहीं होता। Teams इसे पसंद करती हैं क्योंकि इससे internal web interface को browser या test harness में जल्दी चलाया जा सकता है। लेकिन यह सुविधा unattended work के लिए ज़रूरी destination boundary हटा देती है। Reviewer किसी एक route को approve नहीं कर सकता और सामान्य SSH destination restrictions arbitrary SOCKS traffic के लिए उपयोगी allowlist व्यक्त नहीं कर सकतीं।
इस समस्या को लंबे approval form से हल न करें। Agent account के लिए dynamic forwarding deny करें। अगर task को कई destinations चाहिए, तो हर forward अलग define करें या services के आगे purpose-built proxy रखें, जिसमें अपना authentication और logs हों।
Bind address तय करता है कि listener का इस्तेमाल कौन कर सकता है
Bind address security decision का हिस्सा है, क्योंकि इससे पता चलता है कि कौन-सी machines tunnel listener से connect कर सकती हैं। Loopback पर bind होने वाला forward और हर interface पर bind होने वाला forward एक ही target इस्तेमाल कर सकते हैं, फिर भी exposure पूरी तरह अलग होगा।
Local forward के लिए explicit loopback address इस्तेमाल करें:
-L 127.0.0.1:15432:db-admin.internal.example:5432
Default पर निर्भर न रहें। Bind address न देने पर OpenSSH आम तौर पर local forwards को loopback पर bind करता है, लेकिन explicit address review, logs और incident investigation को स्पष्ट बनाता है। इससे बाद में client configuration बदलने पर listener scope चुपचाप बदलने से भी बचाव होता है।
यह खतरनाक version है:
-L 0.0.0.0:15432:db-admin.internal.example:5432
यह client host के हर IPv4 interface पर port 15432 expose करता है। Client तक पहुँचने वाला कोई भी host tunnel का प्रयास कर सकता है। Shared subnet में मौजूद build runner internal database तक bridge बन सकता है, भले ही database खुद केवल bastion से connections स्वीकार करता हो।
IPv6 पर भी यही ध्यान दें। ::1 loopback है, जबकि :: सभी IPv6 interfaces पर listen करता है। दोनों address families जाँचें। मैंने teams को 127.0.0.1 को सुरक्षित मानने के बाद यह पता लगाते देखा है कि automation ने अलग configuration path के ज़रिए IPv6 listener भी खोल दिया था।
Remote forwards के लिए SSH server यह नियंत्रित करता है कि कौन-से bind addresses स्वीकार किए जाएँ। sshd_config में GatewayPorts remote forward bind behavior को प्रभावित करता है। OpenSSH के अनुसार remote forwards requested address और server policy के अधीन default रूप से loopback पर bind होते हैं। जब तक broader remote listeners की समीक्षा की हुई वजह न हो, GatewayPorts no रखें। GatewayPorts clientspecified agent account को बहुत अधिक control देता है।
Forward खोलने के बाद उस machine पर listener देखें जो उसका owner है। macOS या Linux पर यह local check उपयोगी है:
lsof -nP -iTCP:15432 -sTCP:LISTEN
Output में ssh process और 127.0.0.1:15432 या ::1:15432 जैसा address दिखना चाहिए। अगर *:15432 दिखे, तो job रोकें और command तथा client configuration की जाँच करें। यह command केवल local listener address साबित करती है। यह साबित नहीं करती कि दूर वाला endpoint intended destination तक ही सीमित है।
Dedicated SSH account को allowed route व्यक्त करना चाहिए
Agent tunnels के लिए server-side restrictions वाला dedicated SSH account न्यूनतम उचित सीमा है। Client configuration file ऐसे agent के विरुद्ध enforcement नहीं कर सकती जो अपने command arguments बदल सकता है। Limits वहीं रखें जहाँ SSH server connection स्वीकार करता है।
Local-only forwarding account के लिए sshd_config में इस तरह के match block से शुरू करें:
Match User agent-db-tunnel
PasswordAuthentication no
KbdInteractiveAuthentication no
PubkeyAuthentication yes
PermitTTY no
X11Forwarding no
AllowAgentForwarding no
AllowStreamLocalForwarding no
AllowTcpForwarding local
PermitOpen db-admin.internal.example:5432
GatewayPorts no
PermitUserEnvironment no
AllowTcpForwarding local local forwards की अनुमति देता है और remote forwards रोकता है। PermitOpen उस destination का नाम बताता है जिसे account request कर सकता है। यह restriction महत्वपूर्ण है, क्योंकि इसके बिना local forward command bastion से reachable किसी भी host और port की ओर जा सकती है। PermitOpen के बिना database की ज़रूरत वाला agent admin API, cache, metadata service या किसी दूसरे SSH server तक भी forward माँग सकता है।
Hostnames का इस्तेमाल सावधानी से करें। SSH server destination host को resolve करता है, इसलिए PermitOpen में दिया नाम वहीं resolve होना चाहिए। उस नाम को stable और आपके infrastructure के ownership में रखें। अगर DNS name मनमाने addresses में बदल सकता है, तो configuration संकीर्ण दिखेगी, लेकिन वास्तविक destination उसके नीचे बदलती रहेगी। Fixed appliance के लिए IP address अधिक स्पष्ट हो सकता है, हालांकि disciplined internal DNS control और service ownership होने पर hostname भी ठीक है।
OpenSSH का sshd_config(5) manual PermitOpen को host:port के रूप में destination restriction बताता है। यह account को policy engine नहीं बनाता। इसका एक स्पष्ट काम है: ऐसी forwarding request अस्वीकार करना जिसका destination सूची में नहीं है। Account design भी इतना ही सटीक रखें।
इस account को यह सोचकर shell न दें कि «agent इसका इस्तेमाल नहीं करेगा»। क्षमता ही हटा दें। Dedicated account एक connection role के लिए होना चाहिए। अगर interactive use के विरुद्ध अतिरिक्त guard चाहिए, तो authorized public key पर forced command लगाएँ जो आगे कुछ न होने पर exit कर दे, लेकिन अपने environment में forwarding behavior के साथ इसे ज़रूर test करें। कुछ forced-command patterns और wrappers अपेक्षित SSH sessions में बाधा डालते हैं। खराब restriction अक्सर deadline के दबाव में पूरा block हटवा देती है।
Agent forwarding से भी बचें। AllowAgentForwarding no connected server को client-side SSH agent से authentication requests sign करने से रोकता है। SSH tunnel account को traffic ले जाना चाहिए, दूसरे hosts तक पहुँचने का stepping stone नहीं बनना चाहिए।
अगर target पर दो वैध services हैं, तो दो explicit PermitOpen entries लिखें। Wildcard का इस्तेमाल न करें और केवल एक account बचाने के लिए general bastion account पर न लौटें। एक अतिरिक्त account बनाना उस स्थिति को समझाने से सस्ता है जिसमें code agent पूरे internal subnet तक पहुँच सकता था।
Temporary का अर्थ enforced expiry और साफ़ closure है
Tunnel तभी temporary है जब अच्छी नीयत के अलावा कोई व्यवस्था उसे बंद करे। SSH connection तब तक खुला रखता है जब तक client उसे बंद न करे, network fail न हो या timeout न आ जाए। Autonomous agent test के सफल, असफल या timeout होने के बाद भी process चला छोड़ सकता है।
हर job को agent के नियंत्रण से बाहर fixed maximum session duration दें। जहाँ उपलब्ध हो, job runner इसे timeout से लागू कर सकता है:
timeout 20m ssh -N \
-o ExitOnForwardFailure=yes \
-o ServerAliveInterval=30 \
-o ServerAliveCountMax=3 \
-L 127.0.0.1:15432:db-admin.internal.example:5432 \
[email protected]
ExitOnForwardFailure=yes job को तब आगे बढ़ने से रोकता है जब SSH requested listener नहीं बना पाता। इसके बिना agent आगे चलता रह सकता है और tunnel setup failure के बजाय confusing application error report कर सकता है। Server alive settings missed replies के बाद SSH को exit कराती हैं, जो तब मदद करता है जब client host network connectivity चुपचाप खो दे। ये 20 minute ceiling का विकल्प नहीं हैं।
macOS में GNU timeout command default रूप से नहीं आती। Runner की timeout facility, deadline वाले supervised process या ऐसा छोटा wrapper इस्तेमाल करें जो TERM भेजे और फिर process के exit होने की पुष्टि करे। Missing deadline की जगह ऐसा cron job न लगाएँ जो «old SSH» को kill करे। इससे असंबंधित काम भी रुक सकता है और आप यह साबित नहीं कर पाएँगे कि कौन-सा connection बंद हुआ।
Job को अपने cleanup path में भी tunnel बंद करना चाहिए। जिस process को उसने शुरू किया है उसका PID रखें, task पूरी होने पर TERM भेजें, थोड़ी देर प्रतीक्षा करें और फिर lsof या ss से verify करें कि listener हट गया है। Deadline crashes पकड़ती है, cleanup path सामान्य completion संभालता है।
Connection multiplexing में विशेष सावधानी चाहिए। ControlMaster और shared ControlPath के साथ अलग SSH invocations एक master connection reuse कर सकती हैं। Human terminal session में इससे setup time बचता है। Agent work में ownership और expiry धुंधली हो जाती है: एक job किसी दूसरी job के लिए approved connection inherit कर सकती है और एक client बंद करने से master बंद नहीं हो सकता। Tunnel account के लिए multiplexing बंद करें या हर approved job के लिए unique control path बनाएँ।
अगर maintenance workflow को recurring access चाहिए, तो recurring लेकिन अलग-अलग सीमित sessions माँगें। केवल इसलिए tunnel खुला न छोड़ें कि उसे फिर बनाना असुविधाजनक लगता है। Setup में बचाए गए कुछ seconds हर investigation में ambiguity बन जाते हैं।
Approval में वह connection लिखा होना चाहिए जिसे reviewer फिर से बना सके
Approval record से reviewer को यह समझ आना चाहिए कि route किसने authorize किया, उसे किसने खोला और क्या वह बताई गई सीमा में रहा। «approved agent access» जैसा generic ticket comment evidence नहीं है। उसमें listener, destination या duration की जानकारी नहीं होती।
Tunnel शुरू होने से पहले approval रिकॉर्ड करें। Human approver की identity, timestamp, job या run identifier, agent process identity, source machine, dedicated SSH account और public key fingerprint दर्ज करें। फिर requested forward पूरी तरह दर्ज करें: direction, bind address, listener port, target host, target port, purpose और expiry।
Result record में अलग fields चाहिए। SSH ने forward बनाया या नहीं, client process identifier, start time, final exit status, close time और closure का कारण शामिल करें। Timeout, normal cleanup, operator revocation और network failure review में अलग अर्थ रखते हैं।
Prose के बजाय structured records इस्तेमाल करें, ताकि किसी को fields का अनुमान न लगाना पड़े। कई internal systems के लिए यह shape पर्याप्त है:
{
"run_id": "run-7c31",
"approved_by": "oncall-engineer",
"approved_at": "2025-04-12T14:03:00Z",
"ssh_account": "agent-db-tunnel",
"direction": "local",
"listen": "127.0.0.1:15432",
"destination": "db-admin.internal.example:5432",
"expires_at": "2025-04-12T14:23:00Z",
"purpose": "run migration compatibility check"
}
इस example के identifiers placeholders हैं, कोई अनिवार्य schema नहीं। Field names से अधिक महत्वपूर्ण discipline है: एक record में person, process, route और time window को एक साथ बाँधें।
उसी agent को approval generate करके उसे human authorization न मानने दें। Agent बता सकता है कि उसे connection क्यों चाहिए, लेकिन allow decision किसी human या अलग governed workflow को लेना चाहिए। अगर action इतना routine है कि automatic approval उचित है, तो उस decision को expiry वाले narrow job definition में लिखें और अनुमति देने वाले rule का version भी सुरक्षित रखें।
Approval fatigue design failure है। हर packet को approve करने को कहना meaningless clicks पैदा करता है। हर temporary और specific route के लिए एक approval माँगने से approver के पास ठोस निर्णय लेने के लिए कुछ होता है। Prompt छोटा रखें, लेकिन bind address और exact destination ज़रूर दें। ये दो strings कई गलत requests पकड़ लेती हैं।
Credentials agent से बाहर और authority उसके prompt से बाहर रखें
Autonomous agent को private key देने के बजाय connection request करने दें, ऐसी key नहीं जो बाद में arbitrary connections बना सके। Agent के process environment या workspace में broad SSH key पहुँचते ही वह key copy कर सकता है, दूसरा SSH client चला सकता है, approved job के बाद उसका इस्तेमाल कर सकता है या उसे किसी ऐसे tool में दे सकता है जिस पर आपने भरोसा करने की योजना नहीं बनाई थी। Prompt में «इसे केवल database के लिए इस्तेमाल करो» लिखने से इनमें से कोई action सीमित नहीं होता।
बेहतर design में SSH credentials अलग execution boundary में रहते हैं। Agent route fields के साथ requested action भेजता है। Boundary जाँचती है कि vault उपलब्ध है, session authorized है और requested credential के लिए आवश्यक approval मौजूद है। फिर वह SSH action करती है और private key agent को दिए बिना result लौटाती है।
Sallyport macOS पर इसी model का इस्तेमाल करता है: उसका bundled sp-ssh helper SSH actions करता है, जबकि SSH keys app के encrypted vault में रहती हैं और MCP agent तक नहीं पहुँचतीं।
Failure review करते समय यह अंतर महत्वपूर्ण है। Credential custody का सवाल है, «क्या agent secret को कहीं और reuse कर सकता था?» Route restriction का सवाल है, «क्या यह account unapproved destination तक पहुँच सकता था?» Approval का सवाल है, «इस खास use की अनुमति किसने दी?» Teams अक्सर इन तीनों को एक control में मिला देती हैं और फिर पाती हैं कि audit record में key के इस्तेमाल की जानकारी तो है, लेकिन key ने कौन-सा route सक्षम किया, यह नहीं।
Request interface को raw SSH arguments से संकीर्ण रखें। destination_host, destination_port, listen_address, listen_port और max_duration जैसे fields स्वीकार करें। Proxying, forwarding direction, remote command execution, identity files या control sockets बदलने वाले client-supplied options अस्वीकार करें। अगर arbitrary ssh command string स्वीकार की, तो policy interpretation string parsing को सौंप दी। कोई -R, -D, ProxyCommand या दूसरा forward जोड़ते ही यह तरीका विफल हो जाता है।
Tunnel workflow के escape hatch के रूप में general shell न दें। जब action में एक constrained channel बनाना ही शामिल है, तो agent को interactively ssh चलाने की ज़रूरत नहीं। Narrow actions को approve और revoke करना आसान होता है।
Audit evidence को hostile review में भी टिकना चाहिए
Tunnel logs तभी उपयोगी हैं जब compromised agent या local process बाद में उन्हें बदल न सके। Agent workspace के पास रखे plain text logs सुविधाजनक हैं, लेकिन जब वही principal tunnel command और history दोनों edit कर सकता हो, तो वे बहुत कम साबित करते हैं।
Approval event, request event, execution result और closure result को shared run identifier के साथ अलग events के रूप में log करें। केवल rendered command line के बजाय original request fields सुरक्षित रखें। Command line config file में छिपे values को छिपा सकती है या listener को प्रभावित करने वाले defaults छोड़ सकती है।
एक से अधिक जगहों से corroborating records लें। Bastion के SSH logs accepted authentication और forwarding failures दिखा सकते हैं। Job runner process creation और exit दिखा सकता है। Destination service bastion से आया connection दिखा सकती है। इनमें से कोई अकेला पूरी घटना नहीं समझाता, लेकिन साथ में contradictions दिखाई देती हैं।
उदाहरण के लिए, approval 20 minutes के लिए 127.0.0.1:15432 से एक database तक route authorize कर सकता है। अगर client log कहता है कि वह 14:23 पर बंद हुआ, लेकिन destination को 15:10 पर bastion से traffic दिखता है, तो तुरंत जाँच करें। Agent ने दूसरा connection खोला हो सकता है, shared master session reuse किया हो सकता है या कोई उसी account से किसी दूसरे path का इस्तेमाल कर रहा हो।
Sallyport encrypted और hash-chained audit log से session तथा individual call journals project करता है, और sp audit verify vault key की आवश्यकता के बिना offline उस chain की जाँच करता है। यह उस log file से मजबूत property है जिसे agent process बदल सकता है, हालांकि इससे कमजोर account restrictions सही नहीं हो जातीं।
Verification केवल incident के बाद नहीं, review के दौरान भी चलाएँ। Tamper-evident chain बताती है कि recorded history में continuity है। यह नहीं बताती कि शुरुआत में पर्याप्त fields रिकॉर्ड किए गए थे या नहीं। खराब दिन में आपको क्या जानना होगा, पहले तय करें और connection शुरू होने से पहले वे fields event में आना सुनिश्चित करें।
कहानी की जाँच से पहले path revoke करें
जब आपको किसी गलत या abused tunnel का संदेह हो, तो पहले connection path रोकें। Investigation कुछ मिनट प्रतीक्षा कर सकती है; exposed route उस दौरान data भेज सकता है या lateral access दे सकता है, जबकि लोग यह तय कर रहे हों कि कौन-सा log authoritative है।
Client process terminate करें और पुष्टि करें कि उसका listener गायब हो गया है। Dedicated SSH account disable करें या accepting server पर उसकी public key हटा दें। अगर tunnel के ज़रिए ऐसा credential गया हो जो untrusted process के सामने आ सकता था, तो service की अपनी प्रक्रिया के अनुसार उसे rotate करें। केवल tunnel मौजूद होने के कारण असंबंधित credentials rotate न करें।
फिर evidence सुरक्षित करें। Approval record, requested route, process logs, SSH server logs, destination service connection records और closure result बचाएँ। समय को एक ही timezone में दर्ज करें, बेहतर होगा UTC में। Incident review में लोग तब घंटों खो देते हैं जब job runner local time, bastion UTC और application बिना timezone के timestamps इस्तेमाल करती है।
Event को contained घोषित करने से पहले दूसरे listener की जाँच करें। Agent host पर requested port और आसपास चल रहे forwarding processes देखें। Bastion पर dedicated account के active SSH sessions और authentication logs देखें। Destination पर intended expiry के बाद शुरू हुए connections खोजें। लक्ष्य जल्दी से साफ narrative बनाना नहीं, बल्कि बचे हुए access paths ढूँढना है।
अगर human approval ने गलत route enable किया, तो पहले request surface ठीक करें। Arbitrary SSH flags स्वीकार करने वाली बेहतर review screen वही गलती दोहराएगी। अगर server restriction विफल रही, तो repair के बाद exact rejected command test करें और failure output रखें। Controls पर भरोसा तब बनता है जब आप पुष्टि करते हैं कि वे वही route deny करते हैं जिसे deny करना था।
Agent के tunnel पर निर्भर होने से पहले denial paths test करें
Tunnel design तभी तैयार है जब approved connection और forbidden variations दोनों test हो जाएँ। Happy path tests typos पकड़ते हैं। Denial tests बताते हैं कि boundary वास्तव में मौजूद है या नहीं।
Nonproduction account से ऐसा forward आज़माएँ जिसे काम करना चाहिए:
ssh -N -o ExitOnForwardFailure=yes \
-L 127.0.0.1:15432:db-admin.internal.example:5432 \
[email protected]
फिर ऐसी destination आज़माएँ जिसकी अनुमति PermitOpen नहीं देता:
ssh -N -o ExitOnForwardFailure=yes \
-L 127.0.0.1:15433:admin-api.internal.example:443 \
[email protected]
दूसरी command forwarding setup के दौरान fail होनी चाहिए। Client output और server log entry दोनों capture करें। इसके बाद -R और -D आज़माएँ। AllowTcpForwarding local वाले account के लिए दोनों fail होने चाहिए। अंत में 0.0.0.0 के साथ nonloopback listener माँगें और पुष्टि करें कि SSH चलने से पहले आपका request boundary उसे reject करती है, या local environment वह exposure रोकता है जिसे आप रोकना चाहते हैं।
Expiry को छोटी duration के साथ test करें। Approved tunnel शुरू करें, supervisor deadline आने दें और तीन चीज़ों की पुष्टि करें: SSH process exit हो, lsof listener न खोज पाए और closure record deadline का नाम दे, task के सामान्य रूप से समाप्त होने का झूठा दावा न करे। यह छोटा exercise production work के किसी ऐसे tunnel पर निर्भर होने से पहले orphaned process की समस्या पकड़ लेता है जो कभी बंद नहीं होता।
दबाव बढ़ने पर एक सरल rule रखें: autonomous agent को current job के लिए आवश्यक minimum route ही मिले, bounded time के लिए और named approval के तहत। अगर आपका setup उस route को एक line में बता और बाद में उसका closure prove नहीं कर सकता, तो agent के पास task से अधिक network authority है।
सामान्य प्रश्न
Local और remote SSH port forwarding में क्या अंतर है?
Local forward उस मशीन पर listener खोलता है जहाँ से SSH शुरू किया गया है और connections को SSH server के ज़रिए उस destination तक भेजता है जिसे server पहुँच सकता है। Remote forward इसका उल्टा करता है: SSH server listener खोलता है और traffic को client के ज़रिए वापस भेजता है। दोनों को network exposure में बदलाव मानें, क्योंकि कोई भी दिशा ऐसी सीमा पार कर सकती है जिसे आपका firewall पार करने के लिए बनाया नहीं गया था।
अगर मैं tunnel को 127.0.0.1 पर bind करूँ, तो क्या SSH tunnel सुरक्षित है?
नहीं। Loopback bind listening port से connect करने वालों को सीमित करता है, लेकिन यह सीमित नहीं करता कि दूसरी ओर SSH server किन destinations तक पहुँच सकता है। SSH account configuration में listener address और allowed destination दोनों को सीमित करें।
क्या autonomous agent को ssh -D इस्तेमाल करने देना चाहिए?
Dynamic forwarding SOCKS proxy बनाता है, इसलिए client किसी एक named service के बजाय कई destinations माँग सकता है। इससे review करना, उपयोगी logs बनाना और सामान्य SSH forwarding rules से इसे सीमित करना कठिन हो जाता है। Autonomous agent को यह सुविधा न दें, जब तक आपके पास इसके लिए अलग और कड़ाई से नियंत्रित gateway न हो।
मैं SSH account को एक internal service तक कैसे सीमित करूँ?
एक dedicated account इस्तेमाल करें, shell access बंद करें, PTY allocation बंद करें, agent forwarding बंद करें और PermitOpen के ज़रिए केवल नामित host और port pairs की अनुमति दें। SSH के बाहर session lifetime भी तय करें, क्योंकि केवल SSH configuration यह तय नहीं करती कि वैध tunnel कब बंद होना चाहिए।
SSH tunnel approval record में क्या शामिल होना चाहिए?
Human approver, शुरू करने वाली agent process या workload, source host, SSH account, tunnel direction, listener address, destination host और port, खुलने का समय, intended expiry और close result रिकॉर्ड करें। केवल «SSH approved» लिखने वाला record तब बेकार होगा जब incident reviewer को exposure समझना हो।
Temporary SSH tunnel कितनी देर खुला रहना चाहिए?
जब किसी job का उद्देश्य और lifetime छोटा हो, तो हर job के लिए अलग tunnel इस्तेमाल करें। लंबे समय तक खुले रहने वाले tunnels का attribution कठिन होता है, वे असंबंधित काम में दोबारा इस्तेमाल हो सकते हैं और अक्सर उस बदलाव के बाद भी खुले रहते हैं जिसने उन्हें सही ठहराया था। अगर किसी service को permanent connectivity चाहिए, तो permanent SSH session को temporary कहने के बजाय managed access path बनाएँ।
क्या AllowTcpForwarding local हर internal host तक पहुँच रोकता है?
AllowTcpForwarding local local forwarding की अनुमति देता है, लेकिन remote forwarding रोकता है। यह अपने आप destinations को सीमित नहीं करता, इसलिए इसे PermitOpen host:port entries के साथ इस्तेमाल करें। ये restrictions उस account पर लगाएँ जो connection स्वीकार करता है, केवल ऐसी client config में नहीं जिसे agent बदल सकता है।
क्या gateway के बजाय AI agent को SSH password दे सकता हूँ?
Password agent को सीमित और auditable action path नहीं देता। आम तौर पर इससे agent shell खोल सकता है, data copy कर सकता है, arbitrary forwards बना सकता है और उपयोगी approval record के बिना काम कर सकता है। ऐसे account का इस्तेमाल करें जिसकी server-side rules उस एक connection को व्यक्त करती हों जिसे आप अनुमति देना चाहते हैं।
मैं कैसे verify करूँ कि SSH port forward सच में बंद हो गया?
ss या lsof बताता है कि कोई process स्थानीय रूप से listen कर रहा है या नहीं, और SSH debug output requested forward की पुष्टि कर सकता है। इनमें से कोई भी यह साबित नहीं करता कि server ने केवल approved destination स्वीकार किया या tunnel बाद में बंद हुआ। Server configuration, session record और destination service logs भी जाँचें।
अगर agent गलत SSH tunnel खोल दे, तो मुझे क्या करना चाहिए?
SSH client process को kill करें, उसके dedicated account को revoke या disable करें और misuse की आशंका हो तो destination service पर भी access हटा दें। फिर अन्य settings बदलने से पहले approval और connection records सुरक्षित रखें। हर credential को अपने आप rotate न करें, जब तक tunnel के ज़रिए ऐसा credential न गया हो जिसे दूसरी ओर किसी untrusted process ने capture किया हो।