SSH-ის კლიენტის მხარის კონფიგურაციის ფაილია ~/.ssh/config (Windows-ზე - C:\Users\<you>\.ssh\config). თითოეული Host ბლოკი კავშირს მოკლე სახელს აძლევს და ინახავს ყველაფერს, რასაც სხვაგვარად ყოველ ჯერზე აკრეფდი: HostName - რეალური მისამართი, User, Port, IdentityFile - გასაღები, ProxyJump - შუალედური მანქანა. ამის შემდეგ ssh web ცვლის ბრძანებას ssh -i ~/.ssh/id_work -p 2222 deploy@203.0.113.10. იგივე ეხება scp-ს, sftp-ს, rsync-ს, Git-სა და ყველა რედაქტორს, რომელიც SSH-ს იყენებს, რადგან ყველა ერთსა და იმავე ფაილს კითხულობს.
ერთი წესი ხსნის თითქმის ყველა გაუგებრობას: თითოეული პარამეტრისთვის ssh პირველ ნაპოვნ მნიშვნელობას იღებს. კონკრეტული ბლოკები ზემოთ უნდა იყოს, საერთო Host * - ბოლოში, ხოლო ბრძანების ხაზზე მითითებული პარამეტრი ფაილში ჩაწერილს ჯაბნის. თუ ეს გახსოვს, დანარჩენი გზამკვლევი ისეთი ცნობარია, საიდანაც უბრალოდ დააკოპირებ.
ეს სტატია კლიენტის მხარეზეა. გასაღებების გენერაცია, agent და სერვერზე sshd_config-ის გამკაცრება განხილულია სტატიაში SSH გასაღებები და sshd_config-ის გამკაცრება; თუ გასაღები ჯერ არ გაქვს, ჯერ ის წაიკითხე.
სად არის config ფაილი#
ორი ფაილია, ისინი თანმიმდევრობით იკითხება: ჯერ შენი, შემდეგ მთელი სისტემის.
| სისტემა | მომხმარებლის ფაილი | სისტემის ფაილი |
|---|---|---|
| Linux, BSD | ~/.ssh/config | /etc/ssh/ssh_config |
| macOS | ~/.ssh/config | /etc/ssh/ssh_config |
| Windows OpenSSH | %USERPROFILE%\.ssh\config | %ProgramData%\ssh\ssh_config |
ფაილი თავისით არ არსებობს, უნდა შექმნა. Linux-სა და macOS-ზე მასზე ჩაწერის უფლება შენ გარდა არავის უნდა ჰქონდეს, წინააღმდეგ შემთხვევაში ssh მას არ გამოიყენებს და დაწერს Bad owner or permissions on /home/you/.ssh/config:
$ mkdir -p ~/.ssh && chmod 700 ~/.ssh$ touch ~/.ssh/config && chmod 600 ~/.ssh/configდააკვირდი სახელებს: ssh_config კლიენტისაა, sshd_config (d-ით, daemon-იდან) - სერვერის. არასწორი ფაილის გასწორებით ბევრს დაუკარგავს მთელი საღამო, თან სერვერის ფაილი იმავე /etc/ssh საქაღალდეშია.
ორი ფლაგი ფაილს გამჭვირვალეს ხდის. ssh -G name კავშირის გარეშე ბეჭდავს სახელის სრულ, გადათვლილ კონფიგურაციას - ყველა პარამეტრს, ყველა ბლოკისა და ნაგულისხმევი მნიშვნელობის გათვალისწინების შემდეგ. ssh -F /dev/null name ერთვება შენი config-ის იგნორირებით და ერთ ნაბიჯში გეტყვის, პრობლემა ფაილშია თუ არა. -G OpenSSH 6.8-ში გაჩნდა, ამიტომ ყველგან მოგეცემა, სადაც კი შეხვდები.
$ ssh -G web | grep -E '^(hostname|user|port|identityfile|proxyjump) 'hostname 203.0.113.10user deployport 2222identityfile ~/.ssh/id_workproxyjump noneHost ბლოკები და როგორ ირჩევს ssh მნიშვნელობას#
Host ხაზი ბლოკს იწყებს და ის გრძელდება შემდეგ Host ან Match ხაზამდე. შეწევა შენთვისაა და არა ssh-ისთვის. საკვანძო სიტყვებში რეგისტრი არ ითვლება, მნიშვნელობებში უმეტესად ითვლება, და შეგიძლია დაწერო Keyword value ან Keyword=value.
Host web HostName 203.0.113.10 User deploy Port 2222 IdentityFile ~/.ssh/id_work IdentitiesOnly yesHost *.lab User admin StrictHostKeyChecking accept-newHost * ServerAliveInterval 30 AddKeysToAgent yesროცა აკრიფებ ssh web, ssh ფაილს ზემოდან ქვემოთ გადის. თითოეული ბლოკი, რომლის ნიმუში ემთხვევა, ამატებს იმ პარამეტრებს, რომლებიც ჯერ არ უნახავს. ამიტომ web პორტს თავისი ბლოკიდან იღებს, ServerAliveInterval-ს კი - Host *-დან. თუ Host * ზემოთ იქნებოდა და მასში User root ეწერა, ყველა შემდგომი User ხაზი იგნორირებული იქნებოდა - ეს არის "ჩემი config იგნორირდება" პრობლემის კლასიკური ვარიანტი.
გამონაკლისია პარამეტრების მცირე ჯგუფი, რომლებიც პირველ მნიშვნელობას კი არ იღებენ, არამედ გროვდებიან: IdentityFile, CertificateFile, LocalForward, RemoteForward, DynamicForward და SendEnv. რამდენიმე შესაბამისი ბლოკიდან ჩაწერილი რამდენიმე IdentityFile სიას ქმნის და ისინი თანმიმდევრობით მოწმდება.
ნიმუშები შედარდება იმ სახელს, რომელიც შენ აკრიფე, და არა HostName-ს. მხარდაჭერილია * და ?, რამდენიმე ნიმუში ერთ ხაზზე და უარყოფა !-ით:
Host web db cache User deployHost 10.0.0.* !10.0.0.1 ProxyJump bastionHost * !github.com ForwardAgent noმარტო უარყოფილი ნიმუში არასდროს ემთხვევა არაფერს; ის მხოლოდ იმავე ხაზზე მყოფ სხვა ნიმუშებს გამორიცხავს. Host !github.com ცალკე ისეთი ბლოკია, რომელიც არაფერზე ვრცელდება.
Match იმ პირობებისთვის, რასაც Host ვერ გამოხატავს
Match ბლოკები სახელებს კი არა, პირობებს ამოწმებს. სასარგებლოებია host (სახელი HostName-ის გამოყენების შემდეგ), originalhost (რაც შენ აკრიფე), user, localuser, exec და all.
# Use the office jump host only when not on the office networkMatch host 10.20.* !exec "ip route | grep -q 10.20.0.0/16" ProxyJump gw.example.comexec shell ბრძანებას ასრულებს და ემთხვევა, თუ ის ნულოვანი სტატუსით დასრულდა. ის ყოველ კავშირზე გაიშვება, ამიტომ სწრაფი იყოს, და გახსოვდეს, რომ ეს შენს მანქანაზე შესრულებადი shell ბრძანებაა - არასდროს ჩასვა ისეთი, რომელიც არ გესმის.
პარამეტრები, რომლებიც ცოდნად ღირს#
ეს არის საკვანძო სიტყვები, რომლებიც რეალურ config-ში ადგილს იმსახურებს. ნაგულისხმევი მნიშვნელობები OpenSSH-ისაა.
| საკვანძო სიტყვა | ნაგულისხმევი | რას აკეთებს |
|---|---|---|
HostName | აკრეფილი სახელი | რეალური მისამართი ან DNS სახელი |
User | შენი ლოკალური მომხმარებელი | დისტანციური ანგარიში |
Port | 22 | დისტანციური SSH პორტი |
IdentityFile | სტანდარტული id_* ფაილები | გასაღები, რომელსაც შესთავაზებს |
IdentitiesOnly | no | შესთავაზოს მხოლოდ დასახელებული გასაღებები |
ProxyJump | არაფერი | ჯერ ამ hosts-ზე გაიაროს |
ServerAliveInterval | 0 (გამორთულია) | წამები keepalive-ებს შორის |
ServerAliveCountMax | 3 | გამოტოვებული keepalive-ები დანებებამდე |
ConnectTimeout | სისტემის TCP timeout | წამები დაკავშირების მოლოდინში |
StrictHostKeyChecking | ask | როგორ მოექცეს უცნობ host key-ებს |
HostName ტოკენებს იღებს, ამიტომ ერთი ბლოკი მანქანების მთელ ოჯახს ემსახურება. %h არის სახელი, რომელიც შენ აკრიფე:
Host *.prod HostName %h.example.comეს ზუსტად იმას არ აკეთებს, რასაც ხალხი მოელის: ssh api.prod უკავშირდება api.prod.example.com-ს. თუ შენი რეალური სახელები .prod-ს არ შეიცავს, თითოეულ host-ს ცალკე ბლოკი დაუწერე. ჭკვიანური ნიმუშები ხაზებს ზოგავს და სიცხადეს ხარჯავს, config კი ფაილია, რომელსაც ღამის ორზე წაიკითხავ.
User ყოველ ბლოკში ღირს მითითებად, რადგან ნაგულისხმევი შენი ლოკალური ლოგინია. Windows-ის ლეპტოპზე ის ხშირად დიდი ასოთი დაწყებული სახელია ან ელფოსტის მსგავსი, რომელიც არც ერთ Linux სერვერზე არ არსებობს, შეცდომა კი უბრალო Permission denied-ია, რომელიც მომხმარებლის სახელზე არაფერს გიჩვენებს.
Port მნიშვნელოვანია ძირითადად იმ მანქანებისთვის, რომლებმაც SSH 22-დან სხვა პორტზე გადაიტანეს ლოგების დასაწყნარებლად, და ყველაფერისთვის, რაც სხვა პორტზე საკუთარ SSH-ზე მომუშავე სერვისს ამუშავებს. ბრძანების ხაზზე ssh -p 2222 ფაილს ჯაბნის, როგორც ყველა ბრძანების ხაზის პარამეტრი.
IdentityFile და IdentitiesOnly
IdentityFile კერძო გასაღებს ასახელებს და მისამართი შეიძლება ~-ით დაიწყოს. მის გარეშე ssh ~/.ssh-ში სტანდარტულ სახელებს ცდის - id_rsa, id_ecdsa, id_ed25519 და მათი security-key ვარიანტები - და ასევე ყველაფერს, რაც agent-შია ჩატვირთული.
ერთი გასაღების შემთხვევაში ეს ნაგულისხმევი ქცევა კარგია. რამდენიმეს შემთხვევაში კი იწვევს მარცხს, რომელსაც ყველა შეხვდება, ვისაც სამუშაო და პირადი გასაღები აქვს: ssh agent-ის ყველა გასაღებს სათითაოდ სთავაზობს, თითოეული შეთავაზება ავტორიზაციის მცდელობად ითვლება, და სერვერი MaxAuthTries 3-ით გთიშავს შეტყობინებით Too many authentication failures, სანამ სწორ გასაღებამდე მივა. IdentitiesOnly yes ssh-ს ეუბნება, რომ შესთავაზოს მხოლოდ ამ host-ისთვის დასახელებული გასაღებები, თუნდაც agent-ში მეტი იყოს. ჩასვი ის Host *-ში, ბოლოსკენ, და გასაღები დაასახელე ყოველ ბლოკში, რომელსაც ის სჭირდება.
IdentityFile ასევე იღებს .pub ფაილს, როცა კერძო ნაწილი სადღაც სხვაგანაა, მაგალითად password manager-ში, რომელიც agent-ის როლს ასრულებს. ssh საჯარო გასაღებს იყენებს იმის ასარჩევად, agent-ის რომელი გასაღები შესთავაზოს - ეს IdentitiesOnly-ისა და ათეულობით გასაღების მქონე agent-ის შეხამების ყველაზე სუფთა გზაა.
Host key-ების შემოწმება "yes-yes-yes" ჩვევის გარეშე
StrictHostKeyChecking accept-new (OpenSSH 7.6 და ახალი) უკითხავად ამატებს key-ებს host-ებისთვის, რომლებიც არასდროს გინახავს, და მაინც ხმამაღლა უარს ამბობს, თუ ცნობილი host-ის key შეიცვალა. ეს გონივრული პარამეტრია ერთჯერადი მანქანების ლაბორატორიისთვის და ცუდი - პროდუქციულ სერვერზე პირველად შესვლისას, სადაც შეკითხვა ერთადერთი მომენტია fingerprint-ის შესადარებლად. შეზღუდე ის ნიმუშით და ნუ ჩასვამ Host *-ში. UserKnownHostsFile host-ების ჯგუფს ცალკე ფაილზე მიმართავს, რაც გამოსადეგია სატესტო ქსელისთვის, რომელიც ყოველ კვირას თავიდან შენდება:
Host *.lab StrictHostKeyChecking accept-new UserKnownHostsFile ~/.ssh/known_hosts_labProxyJump და jump host-ები#
jump host (ასევე bastion) არის ერთი მანქანა, რომელსაც ინტერნეტიდან უკავშირდები და რომელიც სხვების წინ დგას, მათთან კი პირდაპირ ვერ მიხვალ: ბაზა კერძო ქსელში, თამაშის სერვერი firewall-ის უკან, რომელიც SSH-ს მხოლოდ bastion-იდან უშვებს, ან პატარა კომპანიის ყველა შიდა მანქანა. ProxyJump ამ ნახტომს უხილავს ხდის.
Host bastion HostName 203.0.113.10 User jump IdentityFile ~/.ssh/id_ed25519Host db HostName 10.0.0.20 User deploy IdentityFile ~/.ssh/id_ed25519 ProxyJump bastionssh db ახლა უკავშირდება bastion-ს, სთხოვს მას TCP კავშირის გახსნას 10.0.0.20:22-ზე და ამ გვირაბში მეორე, სრულ SSH სესიას აწარმოებს. მთავარი თვისებაა ის, თუ სად ხდება ავტორიზაცია: შენს ლეპტოპზე, ბოლოდან ბოლომდე, ორივე ნახტომისთვის. bastion მხოლოდ დაშიფრულ ბაიტებს გადასცემს და არასდროს ხედავს შენს კერძო გასაღებს, agent-ს ან სესიას. სწორედ ამიტომ ჩაანაცვლა ProxyJump-მა agent forwarding მეორე მანქანასთან მისასვლელად.
რაც უნდა იცოდე:
- ის OpenSSH 7.3-ში გაჩნდა. უფრო ძველზე ექვივალენტია
ProxyCommand ssh -W %h:%p bastion, რომელიც იგივეს აკეთებს და 2017 წლამდე დაწერილ უმეტეს გაკვეთილში ჩანს. ერთ host-ზე ორივეს ნუ დააყენებ; რომელსაც ssh პირველად წაიკითხავს, ის იმოქმედებს. - ყოველი ნახტომი config-ში იძებნება.
ProxyJump bastionიყენებსbastionბლოკის მისამართს, მომხმარებელს, პორტსა და გასაღებს. ნახტომი inline-ადაც შეგიძლია დაწერო:user@host:port. - ჯაჭვები მძიმეებით იწერება.
ProxyJump bastion,innerორივეს გაივლის თანმიმდევრობით და თითოეული ნახტომი ისევ config-იდან გადაითვლება. - ბრძანების ხაზზე ის `-J`-ა.
ssh -J jump@203.0.113.10 deploy@10.0.0.20ერთჯერადი ფორმაა,scpდაsftp-იც იღებენ-J-ს. - `ProxyJump none` უფრო კონკრეტულ ბლოკში თიშავს jump-ს, რომელიც უფრო ქვემოთ მდებარე ფართო ნიმუშიდან მემკვიდრეობით მოდის.
სამიზნე ხედავს კავშირს, რომელიც bastion-ის კერძო მისამართიდან მოდის, ამიტომ შიდა მანქანის firewall-მა SSH უნდა დაუშვას მხოლოდ ამ მისამართიდან. თვით bastion-ზე sshd-მა TCP forwarding უნდა დაუშვას: AllowTcpForwarding no ან DisableForwarding yes მის sshd_config-ში ყველა jump-ს ამტვრევს შეტყობინებით channel 0: open failed: administratively prohibited.
bastion-ის ანგარიში, რომელსაც მხოლოდ გადაცემა შეუძლია
bastion უფრო სასარგებლოა, როცა მასზე ანგარიში forwarding-ის გარდა არაფერს აკეთებს. bastion-ზე jump მომხმარებლის authorized_keys-ში გამკაცრების გზამკვლევის გასაღების პარამეტრები ზუსტად ამას აკეთებს:
restrict,port-forwarding,permitopen="10.0.0.20:22",permitopen="10.0.0.21:22" ssh-ed25519 AAAAC3Nza... laptoprestrict ყველა არასავალდებულოს თიშავს, port-forwarding forwarding-ს ისევ ჩართავს, permitopen კი მას ჩამოთვლილი დანიშნულებებით ზღუდავს. ამ გასაღებით მარტო ssh bastion shell-ს არ იძლევა, ssh db კი მუშაობს. მოპარული გასაღები ორ კერძო მანქანაზე ორ SSH პორტს ხსნის, რომლებსაც მაინც თავიანთი გასაღებები სჭირდება.
Keepalive-ები და გაყინული კავშირები#
სესია, რომელიც რამდენიმე წუთის უმოქმედობის შემდეგ იკეტება კი არა, ჭედავს, თითქმის ყოველთვის სახლის როუტერის, მობილური ქსელის ან კორპორატიული firewall-ის NAT ცხრილის ჩანაწერია, რომელიც ჩუმად წაიშალა. გამოსწორება კლიენტის მხარეზეა:
Host * ServerAliveInterval 30 ServerAliveCountMax 3ყოველ 30 წამიან სიჩუმეში ssh დაშიფრულ არხში მოთხოვნას აგზავნის და პასუხს ელოდება. ეს ტრაფიკი შუალედურ მოწყობილობებს კავშირის დავიწყებას უშლის, ხოლო თუ ზედიზედ სამი პასუხი დაიკარგა, ssh სესიას დაახლოებით 90 წამში ხურავს და გაყინულ ტერმინალს არ ტოვებს. არ აურიო TCPKeepAlive-ში, რომელიც ნაგულისხმევად ჩართულია და TCP დონეზე მუშაობს; მისი გაყალბება უფრო ადვილია და დროის ათვლას ოპერაციული სისტემა განსაზღვრავს, ხშირად ორ საათს, რაც არაფერში გამოგადგება როუტერის წინააღმდეგ, რომელიც ხუთ წუთში ივიწყებს.
ConnectTimeout 10 სკრიპტების თანმხლები პარამეტრია. მის გარეშე გამორთულ მანქანასთან დაკავშირება ოპერაციული სისტემის TCP timeout-ს ელოდება, რაც შეიძლება წუთზე მეტი იყოს, და backup სკრიპტი, რომელიც host-ებს ციკლში გადის, პირველსავე მკვდარზე ჩერდება.
კავშირის ხელახლა გამოყენება ControlMaster-ით#
მულტიპლექსირება საშუალებას აძლევს იმავე host-თან შემდგომ სესიებს პირველის TCP კავშირზე იაროს. მეორე ssh web, ყოველი scp და Ansible-ის გაშვების ან git pull-ის ყოველი ნაბიჯი მყისიერად იწყება და თავიდან აღარ ავტორიზდება. ნელ არხზე ან jump host-ის გავლით სხვაობა ბრძანებაზე წამებია.
Host * ControlMaster auto ControlPath ~/.ssh/cm-%C ControlPersist 10mControlMaster auto პირველ კავშირს master-ად აქცევს და შემდგომებს მის გამოყენებას ანიჭებს. ControlPath ლოკალური socket ფაილია; %C კავშირის დეტალების (ლოკალური host, დისტანციური host, პორტი, მომხმარებელი) hash-ია, ამიტომ თითოეული დანიშნულებისთვის უნიკალურია და ყოველთვის მოკლე. ეს მნიშვნელოვანია: Unix socket-ების მისამართს დაახლოებით ასი სიმბოლოს ზღვარი აქვს, ძველი %r@%h:%p სტილი კი გრძელ hostname-ებზე ვარდება. ControlPersist 10m master-ს ბოლო სესიის დახურვის შემდეგ ათი წუთით ფონზე ღიად ტოვებს.
master-ს -O-თი მართავ:
$ ssh -O check web # is a master running for this host?Master running (pid=48213)$ ssh -O exit web # close it and every session on itნაკლოვანებები რეალურია და სწორედ ამიტომ ტოვებს ზოგი ამას გამორთულს:
- ყველაფერი ერთ კავშირს იზიარებს. თუ ქსელი გაითიშა, მასზე მყოფი ყველა სესია ერთდროულად კვდება.
- პარამეტრებს master განსაზღვრავს. ახალი სესია სხვა პარამეტრებით, მაგალითად port forward-ით, არსებულ კავშირს უერთდება, ხოლო კავშირის დონეზე მოქმედი პარამეტრები, მათ შორის მომხმარებელი და jump-ის გზა, master-ისაა. როცა config-ის ცვლილება არაფერს ცვლის, ჯერ გაუშვი
ssh -O exit. - socket რწმუნების საშუალებაა. ვისაც ფაილის გახსნა შეუძლია, შენს უკვე ავტორიზებულ კავშირს გამოიყენებს, ამიტომ ის საქაღალდეში უნდა იყოს, რომელსაც მხოლოდ შენ კითხულობ.
- Windows OpenSSH მას არ უჭერს მხარს. ჩაშენებულ კლიენტს Unix-socket მულტიპლექსირება არ აქვს და
ControlMasterხაზი სიჩქარეს კი არა, შეცდომებს იძლევა. გამოიყენეMatch execდამცავი, შეინახე ცალკე ფაილში Linux-ისა და macOS-ის მანქანებისთვის, ან გამოიყენე WSL.
Windows OpenSSH: მისამართები და ხაფანგები#
Windows 10 (1809 და ახალი) და Windows 11 OpenSSH კლიენტს აგზავნიან როგორც C:\Windows\System32\OpenSSH\ssh.exe და ის იმავე ფორმატის config-ს კითხულობს. მომხმარებლის ფაილია C:\Users\<you>\.ssh\config, და ~ IdentityFile-ში მუშაობს. ინტერვალის შემცველ მისამართებს ორმაგი ბრჭყალები სჭირდება; წინა დახრილი ხაზები (/) escape-ის საკითხს სრულად გვერდს უვლის:
Host web HostName 203.0.113.10 User deploy IdentityFile ~/.ssh/id_ed25519 IdentitiesOnly yesHost db HostName 10.0.0.20 User deploy IdentityFile "C:/Users/you/Key Store/id_db" ProxyJump webყველა ხაფანგი სინტაქსის გარეთაა.
კოდირება. Windows PowerShell 5.1-ში echo "Host web" > config UTF-16-ს წერს და ssh ფაილს უარყოფს გაურკვეველი Bad configuration option შეცდომით პირველ ხაზზე. შექმენი ფაილი New-Item -ItemType File $HOME\.ssh\config-ით და შეცვალე რედაქტორში, რომელიც ჩვეულებრივ UTF-8-ში ინახავს. PowerShell 7 ნაგულისხმევად UTF-8-ს წერს და ამ პრობლემას არ აქვს.
გასაღებების უფლებები. Windows-ზე ssh კერძო გასაღებების ACL-ს ამოწმებს და უარყოფს იმას, რომლის წაკითხვაც სხვა ანგარიშებს შეუძლიათ, შეტყობინებით UNPROTECTED PRIVATE KEY FILE. ეს ჩვეულებრივ სხვაგან დაკოპირებულ გასაღებს ემართება. მოხსენი მემკვიდრეობით მიღებული უფლებები და მხოლოდ საკუთარ თავს მიანიჭე:
icacls "$HOME\.ssh\id_ed25519" /inheritance:ricacls "$HOME\.ssh\id_ed25519" /grant:r "$($env:USERNAME):(R)"agent სერვისია. AddKeysToAgent yes არაფერს აკეთებს, სანამ OpenSSH Authentication Agent არ გაეშვება. ამაღლებული PowerShell-იდან:
Get-Service ssh-agent | Set-Service -StartupType AutomaticStart-Service ssh-agentორი ssh პროგრამა. Git for Windows საკუთარ ssh-ს აგზავნის C:\Program Files\Git\usr\bin-ში. ის იმავე ~/.ssh/config-ს კითხულობს, მაგრამ საკუთარ agent-ს იყენებს, ამიტომ Windows-ის ssh-add-ით დამატებული გასაღებები Git-ისთვის უხილავია. Git-ის სისტემურ კლიენტზე მიმართვა ამას ასწორებს: git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe". VS Code-ის Remote-SSH გაფართოებაც იმავე config ფაილს კითხულობს, ამიტომ ყველა Host სახელი, რომელსაც განსაზღვრავ, მის სიაში ჩნდება.
რეცეპტები, რომლებიც მუდმივად გჭირდება#
ორი GitHub ანგარიში ერთ მანქანაზე
GitHub გიცნობს გასაღებით, ყველა ანგარიში კი git@github.com-ად უკავშირდება, ამიტომ მეორე ანგარიშს მეორე გასაღები და alias სჭირდება:
Host github-work HostName github.com User git IdentityFile ~/.ssh/id_work IdentitiesOnly yesდაკლონე hostname-ის ნაცვლად alias-ით - git clone git@github-work:company/app.git - და შეამოწმე ssh -T github-work-ით. IdentitiesOnly-ის გარეშე agent შეიძლება პირადი გასაღები შესთავაზოს პირველად, GitHub მიიღებს და არასწორი ადამიანის სახელით გააგზავნი ცვლილებებს.
ბაზასთან მისვლა SSH-ით
ბაზა, რომელიც სერვერზე მხოლოდ 127.0.0.1-ზე უსმენს, შენი ლეპტოპიდან forward-ით მიიღწევა, რომელიც config-ში ინახება:
Host web-pg HostName 203.0.113.10 User deploy LocalForward 15432 127.0.0.1:5432 SessionType nonessh web-pg შემდეგ გვირაბს shell-ის გარეშე ღიად აჭერს (SessionType none OpenSSH 8.7-ს მოითხოვს; ძველ კლიენტებზე გამოიყენე ssh -N web-pg), და შენს მანქანაზე კლიენტი უკავშირდება localhost:15432-ს. ეს ხშირად უკეთესი პასუხია, ვიდრე ბაზის პორტის ინტერნეტისთვის გახსნა, რასაც PostgreSQL-ის დისტანციური კავშირები სათანადოდ განიხილავს.
ფაილის დაყოფა Include-ით
Include (OpenSSH 7.3 და ახალი) სხვა ფაილებს კითხულობს, wildcard-ებით, ფარდობითი მისამართები კი ~/.ssh-იდან აითვლება. ჩასვი ის ყველაზე ზემოთ, ბლოკების გარეთ, თორემ ის მხოლოდ იმ ბლოკზე იმოქმედებს, რომელშიც დგას:
Include config.d/*Host * IdentitiesOnly yes ServerAliveInterval 30თითო ფაილი კლიენტზე ან პროექტზე ~/.ssh/config.d/-ში გრძელ config-ს კითხვადს ხდის და საშუალებას გაძლევს პროექტის ყველა host ერთ ნაბიჯში წაშალო.
მართული სერვერები SFTP-ით
თამაშის, აპლიკაციის ან ვებ სერვერს hosting panel-ზე ჩვეულებრივ shell არ აქვს, მაგრამ მისი SFTP წვდომაც ბლოკით უკეთესდება. RE:NODE-ზე SFTP ყველა სერვერზეა ხელმისაწვდომი, მონაცემებით, რომლებიც ანგარიშზე კი არა, თითო სერვერზე გაიცემა, ამიტომ panel-ში ნაჩვენები host-ით, პორტითა და მომხმარებლის სახელით დაწერილი თითო ბლოკი sftp mc-world-ს გრძელი სტრიქონის ნაცვლად აქცევს, და config-ის მკითხველი რედაქტორები მას სახელით აჩვენებენ. პაროლი მაინც ყოველ ჯერზე მოითხოვება; ასეთ ბლოკზე გასაღების IdentitiesOnly-ით იძულებას ნუ სცდი. SFTP და ფაილ მენეჯერი კლიენტებსა და panel-ის მხარეს განიხილავს.
სრული config, საიდანაც დაიწყებ#
ყველაფერი ერთად, config ერთი VDS-ისთვის, მის უკან მყოფი კერძო მანქანისთვის და GitHub-ისთვის ასე გამოიყურება:
Include config.d/*Host vds HostName 203.0.113.10 User deploy IdentityFile ~/.ssh/id_ed25519Host db HostName 10.0.0.20 User deploy IdentityFile ~/.ssh/id_ed25519 ProxyJump vdsHost github.com User git IdentityFile ~/.ssh/id_ed25519Host * IdentitiesOnly yes AddKeysToAgent yes ServerAliveInterval 30 ServerAliveCountMax 3 ConnectTimeout 10 ControlMaster auto ControlPath ~/.ssh/cm-%C ControlPersist 10mWindows-ზე სამი Control ხაზი წაშალე. თუ სერვერი ახალია, ახალ VDS-ზე პირველი საათი მეორე მხარეს ანგარიშსა და firewall-ს განიხილავს, ufw-ის გზამკვლევი კი გაჩვენებს, როგორ დაუშვა SSH მხოლოდ bastion-იდან, როცა jump host უკვე მზადაა.
config-ის პრობლემების აღმოფხვრა#
| სიმპტომი | ჩვეული მიზეზი |
|---|---|
| პარამეტრები იგნორირდება | ისინი ადრინდელმა ბლოკმა პირველმა დააყენა |
Too many authentication failures | agent ყველა გასაღებს სთავაზობს; დაამატე IdentitiesOnly yes |
Bad owner or permissions | config ან გასაღები სხვებისთვისაც ჩაწერადია |
Bad configuration option პირველ ხაზზე | PowerShell 5.1-ის UTF-16 ფაილი |
administratively prohibited jump-ზე | bastion-ზე forwarding გამორთულია |
| config-ის ცვლილება არაფერს ცვლის | ControlMaster კავშირი ისევ ღიაა |
Could not resolve hostname | სახელს Host ბლოკი არ აქვს, ან მასში შეცდომაა |
დანარჩენი ყველაფრისთვის მეთოდი იგივე სამი ნაბიჯია. ssh -G name გიჩვენებს, ssh რა პარამეტრებად თვლის. ssh -v name გიჩვენებს, config-ის რომელი ხაზები გამოიყენა, რომელი გასაღებები შესთავაზა და სად გაჩერდა კავშირი; ProxyJump-ის შემთხვევაში გამოტანა ორივე ნახტომს მოიცავს, ამიტომ წაიკითხე, რომელმა ვერ მოახერხა. ssh -F /dev/null user@address ფაილს სრულად გამორიცხავს ან დაადასტურებს.
FAQ#
იყენებს თუ არა scp, rsync და Git ჩემს SSH config-ს?
დიახ. ყველა სისტემურ ssh კლიენტს უშვებს, ის კი ~/.ssh/config-ს კითხულობს, ამიტომ Host alias მუშაობს ყველგან, სადაც hostname-ს დაწერდი: scp file web:/tmp/, rsync -a dir/ web:/srv/, git@github-work:org/repo.git. ხელსაწყოებმა, რომლებსაც საკუთარი SSH იმპლემენტაცია აქვთ, მაგალითად ზოგიერთმა GUI SFTP კლიენტმა, ფაილი შეიძლება იგნორირება გაუკეთონ ან მხოლოდ ნაწილი წაიკითხონ.
რა განსხვავებაა ProxyJump-სა და agent forwarding-ს შორის?
ProxyJump-ის დროს ორივე ავტორიზაცია შენს მანქანაზე ხდება და შუა host მხოლოდ ბაიტებს გადასცემს. agent forwarding-ის (ssh -A) დროს შუა host-ზე შედიხარ და შემდეგ იქიდან იყენებ შენს agent-ს, ამიტომ იმ მანქანაზე root-ის მქონე ნებისმიერს შეუძლია შენი გასაღებები ისესხოს, სანამ დაკავშირებული ხარ. გამოიყენე ProxyJump ყოველთვის, როცა მიზანი სხვა მანქანასთან მისვლაა.
შემიძლია ერთდროულად სხვა პორტიც გამოვიყენო და jump host-იც?
დიახ. ბლოკში Port ამ ბლოკის host-ზე ვრცელდება და თითოეული ნახტომი ცალკე გადაითვლება, ამიტომ 2222-ზე მყოფ bastion-სა და 22-ზე მყოფ სამიზნეს მხოლოდ თავისი Port ხაზები სჭირდება. inline-ად ProxyJump jump@203.0.113.10:2222 იგივეს აკეთებს.
უსაფრთხოა თუ არა ControlMaster-ის Host star-ში ჩასმა?
Linux-სა და macOS-ზე ინტერაქტიული გამოყენებისთვის უსაფრთხოა, თუ ControlPath შენს საკუთარ ~/.ssh საქაღალდეში მიუთითებს. ზოგი გრძელი ფაილების გადაცემისთვის გამოყენებულ host-ებს გამორიცხავს, რადგან ერთი გაჭედილი master მასზე მყოფ ყველა სესიას ჭედავს. Windows-ზე სრულად გამოტოვე.
რატომ მეკითხება ssh მაინც რომელი გასაღები, ან რატომ იყენებს არასწორს?
ჩვეულებრივ agent-ს რამდენიმე გასაღები უჭირავს და IdentitiesOnly არ არის დაყენებული, ან IdentityFile-ის მისამართში შეცდომაა და ssh ჩუმად ნაგულისხმევებზე გადადის. ssh -v თანმიმდევრობით ჩამოთვლის ყველა შეთავაზებულ გასაღებს, ssh -G კი აჩვენებს, რომელი identityfile ხაზები გადათვალა სინამდვილეში.


