RE:NODE

Permission denied (publickey): როგორ ვიპოვოთ რეალური მიზეზი

ავტორი RE:NODE-ის გუნდი
17 წუთის საკითხავი


Permission denied (publickey) ზუსტად ერთ რამეს ნიშნავს: სერვერი მხოლოდ გასაღებით ავტორიზაციას იღებს, კლიენტმა ის გასაღებები შესთავაზა, რაც ჰქონდა, და არც ერთი არ მიიღეს. რატომ - ამას არ გეუბნება და ეს განზრახ ასეა: სერვერი უარის მიზეზს არ აუხსნის ადამიანს, რომელიც შეიძლება თავდამსხმელი იყოს. ახსნა მაინც არსებობს. ის ორ ადგილასაა გაყოფილი: შენს მხარეს ssh -v აჩვენებს, რომელი გასაღებები შეთავაზდა და სერვერმა რა უპასუხა, ხოლო სერვერზე authentication log ამბობს, რატომ იგნორირდა გასაღები, რომელიც უნდა მუშაობდეს.

წაიკითხე ეს ორი სწორედ ამ თანმიმდევრობით და თითქმის ყველა შემთხვევა ექვსიდან ერთ ჯგუფში ჯდება: სწორი გასაღები საერთოდ არ შეთავაზებულა, არასწორი მომხმარებელი მოითხოვე, სერვერს არ შეუძლია ენდოს ფაილებს, რომლებშიც შენი გასაღები ინახება, გასაღები ან მისი ხელმოწერის ალგორითმი უარყოფილია, agent გიშლის ხელს, ან უსაფრთხოების რომელიმე ფენა, მაგალითად SELinux ან AllowUsers ხაზი, შესვლას მაშინ კრძალავს, როცა გასაღებებს საქმე ჯერ არ აქვს. ეს პოსტი თითოეულს გადადის და გაჩვენებს ზუსტ ხაზებს, რომლებიც მას ამოიცნობს.

თუ გასაღებებს პირველად აყენებ და არა დებაგავ, SSH keys and sshd_config hardening გასაღების გენერირებას, დაყენებას და დაცვის გამკაცრებას აღწერს. ეს პოსტი იმ მომენტიდან იწყება, როცა კარი არ იღება.

პირველ რიგში: დატოვე შესასვლელი#

თუ სერვერამდე რაიმე გზით მაინც აღწევ - ღია სესია, მეორე ანგარიში, პაროლი, რომელიც ჯერ მუშაობს, ან პროვაიდერის console - დებაგის დროს ის ღია დატოვე. ქვემოთ მოცემული რამდენიმე გამოსწორება sshd_config-ის ან სერვერზე ფაილების უფლებების შეცვლას მოითხოვს და იქ შეცდომა ერთ დაბლოკილ ანგარიშს მთელ დაბლოკილ მანქანად აქცევს.

თუ შესვლის საერთოდ არანაირი გზა არ გაქვს, ყველა სერვერული გამოსწორება პროვაიდერის console-იდან ან rescue სისტემიდან უნდა გააკეთო. ეს უფრო ნელია, მაგრამ დიაგნოზი იგივეა: ქვემოთ მოცემული კლიენტის გამოტანა მაინც გეტყვის, რა არის არასწორი, ხოლო ლოგები დისკზე დარჩება, როცა იქამდე მიხვალ.

ssh -v-ის კითხვა: ამბავი კლიენტის მხრიდან#

კავშირი ხელახლა გაუშვი ერთი -v-ით. ორი ან სამი (-vvv) ამ შეცდომისთვის იშვიათად საჭირო დეტალებს ამატებს და გამოტანას კითხვას ართულებს.

bash
$ ssh -v deploy@203.0.113.10

წარუმატებელი მცდელობიდან მნიშვნელოვანი ხაზები ასე გამოიყურება:

code
debug1: Authenticating to 203.0.113.10:22 as 'deploy'debug1: identity file /home/alex/.ssh/id_rsa type -1debug1: identity file /home/alex/.ssh/id_ed25519 type 3debug1: Authentications that can continue: publickeydebug1: Next authentication method: publickeydebug1: Offering public key: /home/alex/.ssh/id_ed25519 ED25519 SHA256:5xM8n... agentdebug1: Authentications that can continue: publickeydebug1: No more authentication methods to try.deploy@203.0.113.10: Permission denied (publickey).

წაიკითხე ზემოდან ქვემოთ ამ კითხვებით.

  1. რომელი მომხმარებელი? as 'deploy' არის ანგარიში, რომელსაც სერვერისგან ითხოვენ. თუ აქ სერვერის ანგარიშის ნაცვლად შენი ლეპტოპის მომხმარებლის სახელია, user@ დაგავიწყდა ან ~/.ssh/config-ში ამ host-ისთვის User ხაზი არ არის.
  2. რომელი გასაღების ფაილები არსებობს? type -1 ნიშნავს, რომ ფაილი ვერ მოიძებნა ან ვერ წაიკითხა. ნებისმიერი სხვა რიცხვი ნიშნავს, რომ კლიენტმა ის ჩატვირთა. თუ გასაღები, რომელსაც ელოდები, type -1-ით ჩანს, კლიენტს ის არასდროს ჰქონია.
  3. რომელი გასაღებები შეთავაზდა? თითოეული Offering public key: ხაზი ერთი მცდელობაა, ფაილის გზითა და fingerprint-ით. თუ სერვერზე დაყენებული გასაღები ამ სიაში არ არის, სერვერზე არაფერს ჯერ მნიშვნელობა არ აქვს - ჯერ კლიენტი გამოასწორე.
  4. სერვერმა როგორ უპასუხა? შეთავაზების შემდეგ Server accepts key: ნიშნავს, რომ სერვერმა ეს public key authorized_keys-ში იპოვა და დარჩენილია ხელმოწერის ეტაპი. შეთავაზებისთანავე კიდევ ერთი Authentications that can continue: publickey ნიშნავს, რომ სერვერმა ნახა და ვერ იპოვა, ან იპოვა და არ ენდო.

ეს ბოლო განსხვავება პრობლემას შუაზე ყოფს. „შეთავაზებულია, მაგრამ არ მიიღეს" სერვერის მხარის საკითხია: არასწორი ფაილი, არასწორი უფლებები, არასწორი მომხმარებელი, ან პოლიტიკა, რომელიც გასაღებს უარყოფს. „მიიღეს, შემდეგ უარყვეს" თითქმის ყოველთვის ხელმოწერის ეტაპია: agent, რომელსაც ხელმოწერა არ შეუძლია, ან ალგორითმი, რომელზეც ორი მხარე ვერ თანხმდება.

Fingerprint-ები საშუალებას გაძლევს დარწმუნდე, რომ იმ გასაღებს სთავაზობ, რომელიც, შენი აზრით, დააყენე. შეადარე, რას სთავაზობს კლიენტი და რა აქვს სერვერს:

bash
$ ssh-keygen -lf ~/.ssh/id_ed25519.pub              # on your machine$ ssh-keygen -lf /home/deploy/.ssh/authorized_keys  # on the server, one line per key

თუ სერვერზე არც ერთი fingerprint არ ემთხვევა კლიენტის შეთავაზებულს, პრობლემა ლოგის გახსნის გარეშე იპოვე.

გასაღები, რომელიც არასდროს შეთავაზებულა#

ყველაზე ხშირი მიზეზი და ის, რასაც ადამიანები ყველაზე ნაკლებად ელიან: კლიენტმა უბრალოდ სწორი გასაღები არ სცადა.

OpenSSH კლიენტი ნაგულისხმევ ფაილის სახელებს ეძებს: id_rsa, id_ecdsa, id_ecdsa_sk, id_ed25519, id_ed25519_sk, და იმას, რაც agent-ს უჭირავს. გასაღები, რომელიც ~/.ssh/work_server ან ~/.ssh/github სახელით შეინახე, უხილავია, სანამ სახელით არ მიუთითებ. ტესტისთვის ბრძანების ხაზში მიუთითე, შემდეგ კი config-ში, რომ აღარასოდეს დაგჭირდეს:

bash
$ ssh -i ~/.ssh/work_server -o IdentitiesOnly=yes deploy@203.0.113.10
~/.ssh/config
Host web-01    HostName 203.0.113.10    User deploy    IdentityFile ~/.ssh/work_server    IdentitiesOnly yes

IdentitiesOnly yes საპირისპირო მიმართულებითაც მნიშვნელოვანია. მის გარეშე კლიენტი agent-ის ყველა გასაღებს სთავაზობს მანამ, სანამ შენ მითითებულ ფაილამდე მივა, და თითოეული ითვლება სერვერის MaxAuthTries-ში (ნაგულისხმევად 6). საკმარისად ბევრი ჩატვირთული გასაღებით კავშირი გეწყვიტება Too many authentication failures-ით, მაშინაც კი, როცა სწორი გასაღები გაქვს. ეს იგივე პრობლემას ჰგავს, მაგრამ ის არ არის.

სწორი გასაღების დაკარგვის კიდევ სამი გზა:

  • `sudo ssh` root-ის სახელით მუშაობს და კითხულობს /root/.ssh-ს და არა შენსას. სკრიპტები, რომლებიც ssh-ს sudo-ით იძახებენ, სხვა მომხმარებლით გაშვებული cron სამუშაოები და CI runner-ები თითოეულს თავისი საკუთარი home დირექტორია და საკუთარი გასაღებები აქვს.
  • პირადი გასაღები, რომელსაც კლიენტი არ იტვირთავს. თუ ფაილი სხვა მომხმარებლებისთვისაც იკითხება, კლიენტი debug ხაზებზე ზემოთ დაბეჭდავს WARNING: UNPROTECTED PRIVATE KEY FILE!-ს და This private key will be ignored.-ს. ამას chmod 600 ~/.ssh/id_ed25519 ასწორებს.
  • არასწორი ნახევარი. -i ~/.ssh/id_ed25519.pub public key-ზე მიუთითებს. ახალი კლიენტები ამას უმკლავდებიან და შესაბამის private ფაილს ეძებენ, ძველი კი Load key: invalid format-ით მარცხდება. -i მიუთითე .pub-ის გარეშე ფაილზე.

PuTTY-ს მომხმარებლებს კიდევ ერთი აქვთ: .ppk ფაილი OpenSSH გასაღები არ არის. PuTTYgen-ის Conversions მენიუდან OpenSSH-ის პირადი გასაღები ექსპორტდება, ხოლო authorized_keys-ისთვის საჭირო public key არის ერთი ხაზი, რომელიც მის ფანჯარაშია ნაჩვენები და არა მრავალხაზიანი ---- BEGIN SSH2 PUBLIC KEY ---- ბლოკი. ის ბლოკი RFC 4716 ფორმატია და sshd მას უგულებელყოფს; თუ მხოლოდ ის გაქვს, ssh-keygen -i -f key.pub მას ერთხაზიან გასაღებად გადაიყვანს.

არასწორი მომხმარებელი, არასწორი ანგარიში, არასწორი ფაილი#

გასაღები მომხმარებლისთვის ინსტალირდება, ამ მომხმარებლის home დირექტორიაში. სხვა მომხმარებელს თუ ითხოვ, სხვა authorized_keys მოგეცემა, ან არავითარი.

რა აკრიფერას კითხულობს სერვერი
ssh root@host/root/.ssh/authorized_keys
ssh deploy@host/home/deploy/.ssh/authorized_keys
ssh hostანგარიში, რომლის სახელიც შენი ლოკალური მომხმარებლის სახელს ემთხვევა

ამ ცხრილიდან გამომდინარე, ტიპური შეცდომები ასეთია:

  • Cloud image-ები ქმნიან ნაგულისხმევ მომხმარებელს (ubuntu, debian, admin, ec2-user და სხვა, დისტრიბუტივის მიხედვით) და გასაღებს იქ ათავსებენ, ხშირად root-ით შესვლა გამორთულია ან root-ის authorized_keys ისეა მოწყობილი, რომ დაბეჭდოს „please log in as ubuntu" და გათიშოს.
  • გასაღები შენს საკუთარ ანგარიშში მოხვდა და არა service ანგარიშში. ssh-copy-id გასაღებს იმ ანგარიშში აინსტალირებს, რომლითაც დაუკავშირდი. deploy-ისთვის გასაღების დამატება, როცა alex-ით ხარ შესული, ნიშნავს /home/deploy/.ssh/authorized_keys-ში ჩაწერას და შემდეგ მისი მფლობელის გასწორებას, რაც შემდეგ თავშია აღწერილი.
  • `AuthorizedKeysFile` შეცვლილია. ნაგულისხმევია .ssh/authorized_keys .ssh/authorized_keys2, home დირექტორიის მიმართ. ზოგიერთი გამკაცრებული კონფიგურაცია მას /etc/ssh/authorized_keys/%u-ში გადააქვს. შეამოწმე, რას იყენებს გაშვებული daemon და არა ის, რასაც ივარაუდებ:
bash
$ sudo sshd -T | grep -Ei 'authorizedkeysfile|pubkeyauthentication|allowusers|allowgroups'

sshd -T ბეჭდავს ეფექტურ კონფიგურაციას ყველა Include-ისა და ნაგულისხმევი მნიშვნელობის გამოყენების შემდეგ, და მხოლოდ ეს ვერსიაა მნიშვნელოვანი. Debian-სა და Ubuntu-ზე /etc/ssh/sshd_config.d/-ში მდებარე ფაილს შეუძლია მთავარი ფაილი ჩუმად გადაფაროს, რადგან sshd საკვანძო სიტყვის პირველ წაკითხულ მნიშვნელობას ინარჩუნებს. რომ ნახო, რას აკეთებს Match ბლოკი კონკრეტული შესვლისთვის, დაამატე კავშირის დეტალები: sshd -T -C user=deploy,host=laptop,addr=198.51.100.7.

ბოლოს, თვითონ გასაღების ხაზი შეამოწმე. ერთი public key ზუსტად ერთი ხაზია: ტიპი, base64 ბლოკი, არასავალდებულო კომენტარი. ტერმინალის ან რედაქტორის გავლით ჩასმისას, რომელიც გრძელ ხაზებს ახვევს, ის ორად იყოფა, და sshd გატეხილ ხაზს ჩუმად გამოტოვებს. ერთი გასაღების მქონე ფაილზე wc -l-მა 1 უნდა თქვას, ხოლო ssh-keygen -lf-მა შეცდომის ნაცვლად ერთი fingerprint უნდა დაბეჭდოს.

ფაილის უფლებები და მფლობელობა#

ეს სერვერის მხარის კლასიკური მიზეზია და ისეთი, რომელსაც კლიენტი საერთოდ ვერ ხედავს. StrictModes yes-ის (ნაგულისხმევი) დროს sshd უარს ამბობს authorized_keys ფაილის გამოყენებაზე, თუ ამ ფაილს, მის დირექტორიას ან მის ზემოთ მდებარე home დირექტორიას მომხმარებლისა და root-ის გარდა სხვას შეუძლია შეცვლა. ფაილი, რომლის რედაქტირებაც ყველას შეუძლია, ფაილია, სადაც ყველას შეუძლია საკუთარი გასაღები დაამატოს, ამიტომ daemon მას კომპრომეტირებულად თვლის.

გზაModeმფლობელი
/home/deploy755, 750 ან 700deploy
/home/deploy/.ssh700deploy
.ssh/authorized_keys600 (ან 644)deploy

წესი ასეთია: ამ გზაზე არსად არ უნდა იყოს group-ის ან ყველასთვის ჩაწერის უფლება. ყველაზე ვერაგი group-ისთვის ჩაწერადი home დირექტორიებია: პროექტის საქაღალდის გასაზიარებლად home დირექტორიაზე chmod -R 775 ამ მომხმარებლის გასაღებით შესვლას გააფუჭებს და კლიენტის მხარეს ამაზე მინიშნებაც კი არ იქნება.

მფლობელობა მეორე ნახევარია. ფაილის root-ის სახელით ჩაწერა, sudo nano-თი ან sudo cp-ით, მას root-ის საკუთრებად ტოვებს. ყველაფერი ერთად აღადგინე:

bash
$ sudo chown -R deploy:deploy /home/deploy/.ssh$ sudo chmod 700 /home/deploy/.ssh$ sudo chmod 600 /home/deploy/.ssh/authorized_keys$ sudo chmod go-w /home/deploy

როცა ეს არის მიზეზი, სერვერის ლოგი ამას პირდაპირ ამბობს - Authentication refused: bad ownership or modes for directory /home/deploy ან იგივე .ssh-ისთვის ან ფაილისთვის. StrictModes-ის გამორთვა შეცდომას აქრობს, მაგრამ რეალურ სისუსტეს ადგილზე ტოვებს; სანაცვლოდ უფლებები გამოასწორე. თუ სხვა სახის სერვერებზე უფლებებთან გიწვალია, file permissions and ownership რვაობით ჩანაწერს უფრო დეტალურად განმარტავს.

გასაღების ტიპები და ssh-rsa SHA-1-ის ცვლილება#

OpenSSH 8.8-იდან (2021) ssh-rsa ხელმოწერის ალგორითმი, რომელიც SHA-1-ით აწერს ხელს, ნაგულისხმევად გამორთულია როგორც კლიენტზე, ისე სერვერზე. ეს ამ შეცდომის ყველაზე დამაბნეველი მიზეზია, რადგან გასაღების ტიპსა და ხელმოწერის ალგორითმს ერთი სახელი აქვთ. RSA გასაღები კვლავ შესანიშნავად მუშაობს; მას სანაცვლოდ rsa-sha2-256 ან rsa-sha2-512 აწერს ხელს. პრობლემა მხოლოდ მაშინ იწყება, როცა ერთი მხარე იმდენად ძველია, რომ SHA-2 ვარიანტებს არ იცნობს.

ორი მიმართულებაა და ისინი სხვადასხვანაირად გამოიყურება.

ახალი კლიენტი ძველ სერვერთან. ტიპური სამიზნეებია ძველი მოწყობილობები, NAS-ები, როუტერები და დისტრიბუტივები, რომელთა OpenSSH 7.2-ზე ძველია. -v-ით ხედავ, რომ გასაღები განიხილეს და შემდეგ გამოტოვეს:

code
debug1: Offering public key: /home/alex/.ssh/id_rsa RSA SHA256:Qk2... explicitdebug1: send_pubkey_test: no mutual signature algorithm

no mutual signature algorithm არის გამცემი ნიშანი. ყველაზე სუფთა გამოსწორებაა ed25519 გასაღები, თუ სერვერი საკმარისად ახალია, რომ მიიღოს (OpenSSH 6.5 ან უფრო ახალი). თუ არ არის, SHA-1 ჩართე მხოლოდ ამ ერთი host-ისთვის და არასდროს გლობალურად:

~/.ssh/config
Host old-nas    HostName 192.168.1.20    HostKeyAlgorithms +ssh-rsa    PubkeyAcceptedAlgorithms +ssh-rsa

OpenSSH 8.5-ზე ძველ კლიენტებზე მეორე საკვანძო სიტყვა იწერება როგორც PubkeyAcceptedKeyTypes; მიმდინარე ვერსიები ორივეს იღებენ. HostKeyAlgorithms საჭიროა მხოლოდ მაშინ, თუ თვით სერვერის host key RSA-ა და მხოლოდ SHA-1-ს იყენებს, რაც ასეთ ძველ ტექნიკაზე, როგორც წესი, ასეა.

ძველი კლიენტი ახალ სერვერთან. აქ კლიენტის გამოტანა მხოლოდ შეთავაზებას და უარს აჩვენებს, ხოლო მიზეზი სერვერის ლოგშია: ხაზი, რომელიც ამბობს, რომ ხელმოწერის ალგორითმი, ან ზოგიერთ ვერსიაზე გასაღების ტიპი, ssh-rsa არის not in PubkeyAcceptedAlgorithms. ფორმულირება გამოშვებებს შორის იცვლება, მაგრამ მასში საკვანძო სიტყვა არა. გამოსწორება კლიენტზეა: განაახლე ან ed25519 გასაღებზე გადაერთე. ჩვეულებრივი ეჭვმიტანილებია ძველი Windows ხელსაწყოები, deploy-სა და backup პროგრამების მიერ გამოყენებული ძველი Java SSH ბიბლიოთეკები და ჩაშენებული კლიენტები. სერვერზე +ssh-rsa-ის დამატება SHA-1-ს ყველასთვის ხელახლა რთავს და ხანმოკლე დროებითი გამოსავალი უნდა იყოს და არა პასუხი.

ასევე ღირს იცოდე: DSA გასაღებები (ssh-dss) ნაგულისხმევად OpenSSH 7.0-იდან გამორთულია, ხოლო მათი მხარდაჭერა მოგვიანებით გამოშვებებში სრულად ამოიღეს. id_dsa გასაღები მიმდინარე სერვერთან არცერთი პარამეტრით არ იმუშავებს და ერთადერთი გამოსავალი ახალი გასაღებია. იგივე ეხება 1024 ბიტზე მოკლე RSA გასაღებებს, რომლებსაც მიმდინარე OpenSSH სრულად უარყოფს.

როცა agent ხელს გიშლის#

Agent გეხმარება, სანამ არ ხელს გიშლის. სამი გაუმართაობა ცნობის ღირსია.

Agent-ს არასწორი გასაღებები უჭირავს, ან არაფერი. ssh-add -l აჩვენებს, რა უჭირავს. The agent has no identities. ნიშნავს, რომ ის გაშვებულია და ცარიელია; Could not open a connection to your authentication agent. ნიშნავს, რომ SSH_AUTH_SOCK ამ shell-ში დაყენებული არ არის, ამიტომ კლიენტი მას საერთოდ ვერ წვდება. ჩვეულებრივი მიზეზებია ახალი ტერმინალის სესიები, tmux, რომელიც agent-მდე გაეშვა, და su სხვა მომხმარებელზე.

bash
$ ssh-add -l$ eval "$(ssh-agent -s)"$ ssh-add ~/.ssh/id_ed25519

სერვერი გასაღებს იღებს, agent კი ხელს არ აწერს. ეს ჩანს როგორც Server accepts key:, რასაც მოსდევს sign_and_send_pubkey: signing failed ... agent refused operation. ჩვეულებრივი მიზეზებია hardware გასაღები, რომელსაც შეხება სჭირდება და არავის შეუხებია, desktop keyring agent, რომელსაც დადასტურების ფანჯარა უნდა და ის არ გამოჩნდა, ან გასაღები, რომელიც ვადით დაემატა (ssh-add -t) და ვადა გაუვიდა. გასაღების ამოღება და ხელახლა დამატება (ssh-add -d, შემდეგ ssh-add) შემთხვევათა უმეტესობას აგვარებს; Linux desktop-ებზე იმის შემოწმება, რომ პირადი გასაღების ფაილი 600-ია, გასაკვირად დიდ წილს კიდევ ასწორებს.

ზედმეტად ბევრი გასაღები. ზემოთ უკვე იყო და ხელახლა ღირს ხსენება, რადგან ძალიან ხშირია: agent, რომელსაც ექვსი გასაღები უჭირავს, MaxAuthTries-ს ამოწურავს სანამ სწორ გასაღებამდე მივა. მუდმივი გამოსწორებაა IdentitiesOnly yes თითოეული host-ისთვის ცალკე IdentityFile-ით.

Windows-ზე ჩაშენებული OpenSSH კლიენტი ssh-agent სერვისს იყენებს, რომელიც ნაგულისხმევად გამორთულია. მისი გაშვების ტიპი Services-ში (ან Set-Service ssh-agent -StartupType Automatic-ით) ავტომატურზე უნდა შეიცვალოს, სანამ ssh-add საერთოდ იმუშავებს. Git for Windows საკუთარ, ცალკე OpenSSH-ს აწვდის, ამიტომ ერთ agent-ში დამატებული გასაღები მეორისთვის უხილავია; თუ git ვერ მუშაობს, ssh კი მუშაობს, პირველ რიგში ეს შეუსაბამობა შეამოწმე.

SELinux, AllowUsers და სხვა მცველები#

ზოგი უარი გასაღების შედარებამდეც ხდება, ზოგი კი მაშინ, როცა ყველა ფაილი სწორად გამოიყურება.

SELinux Fedora-ზე, RHEL-ზე, Rocky-ზე, Alma-სა და CentOS Stream-ზე ფაილებს ლეიბლებს აძლევს, და sshd-ს მხოლოდ ssh_home_t ლეიბლის მქონე authorized_keys-ის წაკითხვა შეუძლია. .ssh დირექტორია, რომელიც სხვაგანიდან mv-ით შეიქმნა, არქივიდან აღდგა ან ადგილზე დაკოპირდა, ძველ ლეიბლს ინარჩუნებს და უფლებები იდეალურად გამოიყურება, მაშინ როცა daemon-ს წვდომა უარყოფილი აქვს.

bash
$ ls -Z ~/.ssh/authorized_keysunconfined_u:object_r:user_home_t:s0 /home/deploy/.ssh/authorized_keys$ restorecon -Rv ~/.ssh$ sudo ausearch -m avc -ts recent

user_home_t იქ, სადაც ssh_home_t უნდა იყოს, არის პრობლემა; restorecon ლეიბლებს პოლიტიკის ნაგულისხმევზე აბრუნებს. თუ თვით home დირექტორია უჩვეულო ადგილასაა, მაგალითად /data/home, პოლიტიკას მისთვის წესი არ აქვს და SELinux-ს ჯერ უნდა უთხრა, რომ ის /home-ის ექვივალენტია: semanage fcontext -a -e /home /data/home, შემდეგ გაუშვი restorecon. ausearch კითხულობს /var/log/audit/audit.log-ს და თვით უარს აჩვენებს, რასაც sshd-ის საკუთარი ლოგი არ აკეთებს.

`AllowUsers`, `AllowGroups`, `DenyUsers`, `DenyGroups`. თუ ამათგან რომელიმე არსებობს, მომხმარებელი, რომელიც არ ემთხვევა, გასაღების მიუხედავად უარყოფილია. ლოგი ამბობს User deploy from 198.51.100.7 not allowed because not listed in AllowUsers, ხოლო კლიენტი იგივე Permission denied (publickey)-ს ხედავს, რასაც გასაღების არარსებობისას. ახალი ანგარიშის დამატება და ამ ხაზის დავიწყება ერთი საათის დაკარგვის ძალიან ხშირი გზაა.

`PermitRootLogin`, რომელიც no-ზეა დაყენებული, root-ს ვალიდური გასაღების მიუხედავადაც უარყოფს. prohibit-password (OpenSSH 7.0-იდან ნაგულისხმევი) root-ს მხოლოდ გასაღებით უშვებს.

Shell-ისა და ანგარიშის მდგომარეობა. მომხმარებელი, რომლის shell-იც /usr/sbin/nologin-ია, ავტორიზდება და შემდეგ გამოაგდებენ, რაც სხვანაირად გამოიყურება (This account is currently not available). UsePAM no-ს დროს ანგარიში, რომლის პაროლიც /etc/shadow-ში დაბლოკილია, შეიძლება გასაღებით შესვლისასაც უარყონ; Linux დისტრიბუტივების უმეტესობა UsePAM yes-ით მუშაობს, სადაც ეს არ მოქმედებს.

Windows OpenSSH Server-ს საკუთარი წესი აქვს, რომელსაც ყველა ერთხელ გადაეყრება. Administrators ჯგუფის მომხმარებლისთვის sshd მომხმარებლის საკუთარ .ssh\authorized_keys-ს უგულებელყოფს და სანაცვლოდ C:\ProgramData\ssh\administrators_authorized_keys-ს კითხულობს, ეს ფაილი კი მხოლოდ Administrators-სა და SYSTEM-ს უნდა შეეძლოს ჩაწერა:

code
icacls.exe "C:\ProgramData\ssh\administrators_authorized_keys" /inheritance:r /grant "Administrators:F" /grant "SYSTEM:F"

სერვერის ლოგების კითხვა#

როცა კლიენტის გამოტანა საკითხს ვერ წყვეტს, სერვერის ლოგი წყვეტს. სად მდებარეობს, დისტრიბუტივზეა დამოკიდებული:

სისტემასად ვეძებოთ
Debian, Ubuntu/var/log/auth.log ან journalctl -u ssh
Fedora, RHEL, Rocky, Alma/var/log/secure ან journalctl -u sshd
ნებისმიერი systemd სისტემაjournalctl -t sshd (syslog identifier-ით)

თვალი ადევნე ლოგს ცოცხლად, სანამ სხვა ტერმინალიდან უკავშირდები; დროის ნიშნულის შესატყვისება მცდელობასთან გაცილებით ადვილია, ვიდრე მოვლენის შემდეგ ძებნა.

bash
$ sudo journalctl -u ssh -f$ sudo tail -f /var/log/auth.log

ხაზები, რომლებიც კითხვას პასუხობენ:

ლოგის ხაზი შეიცავსრას ნიშნავს
Invalid userასეთი ანგარიში არ არსებობს
bad ownership or modesStrictModes-მა ფაილი უარყო
not listed in AllowUsersპოლიტიკაა და არა გასაღები
not in PubkeyAcceptedAlgorithmsSHA-1 ssh-rsa უარყოფილია
Connection closed by authenticating userკლიენტმა თავი დაანება, არაფერი დაემთხვა
Accepted publickey forიმუშავა - პრობლემა სხვაგანაა

Connection closed by authenticating user deploy ... [preauth] მის წინ არაფრით ყველაზე გამაღიზიანებელია: ანგარიში არსებობს, ფაილი იკითხებოდა და შეთავაზებულ გასაღებთაგან არც ერთი მასში არ იყო. ეს ისევ fingerprint-ებთან გაბრუნებს. sshd_config-ში LogLevel VERBOSE-ის დაყენება daemon-ს აიძულებს, თითოეული განხილული გასაღების fingerprint ჩაწეროს, რაც ამას ვარაუდიდან შედარებად აქცევს. Logs worth keeping აღწერს, როგორ შეინახო ეს ლოგები მას შემდეგ, რაც მიმდინარე პრობლემა გადაიჭრება.

როცა ესეც არ კმარა, გაუშვი მეორე daemon debug რეჟიმში თავისუფალ პორტზე. ის ერთ კავშირს ამუშავებს, ყველა გადაწყვეტილებას შენს ტერმინალში ბეჭდავს და თავს ასრულებს, ამიტომ რეალურ სერვისს არ აბრკოლებს:

bash
$ sudo /usr/sbin/sshd -d -p 2222$ ssh -v -p 2222 deploy@203.0.113.10        # from your machine

პორტი 2222 firewall-ში ამ დროის განმავლობაში ღია უნდა იყოს - the ufw guide-ში ერთხაზიანი წესი წერია - და შემდეგ ისევ დაიკეტოს. debug გამოტანა გეუბნება, რომელი ფაილის გახსნა სცადა, რომელი უფლება არ მოეწონა და რომელ გასაღებს ადარებდა, რაც დარჩენილი საიდუმლოებების თითქმის ყველა დასასრულს უდებს.

შენიშვნა ხმაურზე: საჯარო სერვერის auth log სავსეა Invalid user ხაზებით სკანერებისგან, რომლებიც admin-ს, test-სა და oracle-ს ცდიან. ეს ფონია და არა შენი პრობლემა, თუმცა კარგი მიზეზია, fail2ban იმის წინ დააყენო, რაც ჯერ კიდევ პაროლს იღებს.

Git host-ები და SFTP: იგივე შეცდომა სხვაგან#

ადგილი, სადაც ადამიანები ამ შეცდომას ყველაზე ხშირად ხვდებიან, საერთოდ სერვერი არ არის, არამედ git push. git@github.com: Permission denied (publickey). იგივე მექანიზმია ორი ნიუანსით: მომხმარებელი ყოველთვის git-ია და არასდროს შენი ანგარიშის სახელი, ხოლო გასაღები Git host-ზე შენს ანგარიშს უნდა დაემატოს და არა სერვერზე რომელიმე ფაილს. შეამოწმე Git-ის გარეშე:

bash
$ ssh -T git@github.com

მუშა გასაღები პასუხობს მისალმებით, რომელიც შენს მომხმარებლის სახელს შეიცავს, და შენიშვნით, რომ shell წვდომა არ გეძლევა. წარუმატებელი იგივე უარს აჩვენებს, ხოლო ssh -vT git@github.com გაძლევს შეთავაზებული გასაღებების სიას, რომელიც ზემოთ იყო. თუ repository-ის URL https://-ით იწყება, SSH გასაღებები საერთოდ არ მონაწილეობს; ეს token-ის პრობლემაა და არა ეს.

მართულ game, app და web სერვერებს, როგორც წესი, საკუთარი SSH daemon არ აქვთ, რომლამდეც მიხვალ. RE:NODE-ზე ფაილებთან წვდომა SFTP-ით ხდება, პანელში თითოეული სერვერისთვის გაცემული მონაცემებით, ამიტომ იქ უარყოფილი SFTP შესვლის გამოსწორება არის host, პორტი და მომხმარებლის სახელი, რომლებიც ამ სერვერის გვერდზეა ნაჩვენები, და არა გასაღების ფაილი - SFTP and the file manager შეიცავს კავშირის დეტალებს. ამ პოსტის ყველა თავი სრულად ვრცელდება VDS-ზე, სადაც sshd-ის კონფიგურაცია შენზეა.

ჩეკლისტი სწორი თანმიმდევრობით#

როცა უბრალოდ მოქმედებათა რიგი გინდა:

  1. ssh -v user@host - დარწმუნდი მომხმარებლის სახელში და იმაში, რომ შენი გასაღები Offering public key ხაზებშია.
  2. თუ არ არის შეთავაზებული, კლიენტი გამოასწორე: IdentityFile, IdentitiesOnly yes, პირადი გასაღების mode 600, agent.
  3. თუ შეთავაზებულია და უარყოფილი, შეადარე fingerprint-ები ორივე მხარეს ssh-keygen -lf-ით.
  4. შეამოწმე მფლობელობა და mode-ები home დირექტორიაზე, .ssh-ზე და authorized_keys-ზე.
  5. sshd -T-ში შეამოწმე AuthorizedKeysFile, AllowUsers და PermitRootLogin.
  6. თვალი ადევნე auth log-ს დაკავშირებისას; SELinux სისტემებზე შეამოწმე ls -Z და ausearch.
  7. თუ კლიენტი ამბობს no mutual signature algorithm ან სერვერი PubkeyAcceptedAlgorithms-ს ახსენებს, ეს SHA-1-ის ცვლილებაა - გადადი ed25519-ზე.
  8. კვლავ გაჭედილი ხარ: sshd -d -p 2222 და წაიკითხე ყველა ხაზი.

როცა იმუშავებს, გამოსწორება მუდმივად ~/.ssh/config-ში ჩაწერე, რომ მომავალ თვეს იგივე არ დებაგავდე, და დანარჩენი კონფიგურაცია გადახედე the first hour on a new VDS-ით.

FAQ#

რატომ მუშაობს ssh-copy-id, მაგრამ გასაღები მაინც უარყოფილია?

ssh-copy-id გასაღებს სწორად აინსტალირებს იმ ანგარიშში, რომლითაც დაუკავშირდი, მაგრამ ვერ ასწორებს group-ისთვის ჩაწერად home დირექტორიას ან SELinux ლეიბლს, რომელიც მის გაშვებამდე უკვე არასწორი იყო. სერვერის ლოგში მოძებნე bad ownership or modes, ხოლო Fedora-ზე ან RHEL-ის ოჯახის სისტემებზე ამ მომხმარებლისთვის გაუშვი restorecon -Rv ~/.ssh.

უსაფრთხოა StrictModes-ის გამორთვა, რომ შეცდომა გაქრეს?

არა. StrictModes იმიტომ არსებობს, რომ ჩაწერადი authorized_keys ნებისმიერ სხვა ლოკალურ მომხმარებელს აძლევს საკუთარი გასაღების დამატებისა და შენი სახელით შესვლის საშუალებას. უფლებების გასწორებას ოთხი ბრძანება სჭირდება და დაცვას ადგილზე ტოვებს; მისი გამორთვა რეალურ სისუსტეს მალავს.

ჩემი გასაღები წლების განმავლობაში მუშაობდა და განახლების შემდეგ შეწყვიტა. რატომ?

თითქმის ყოველთვის ეს არის OpenSSH 8.8-ში ssh-rsa SHA-1-ის ცვლილება ან DSA გასაღებების ამოღება. ერთი მხარე განახლდა და ორივე ვეღარ თანხმდება ხელმოწერის ალგორითმზე. შექმენი ed25519 გასაღები და ძველის გვერდით დააყენე; ssh-rsa ხელახლა ჩართე მხოლოდ თითო host-ისთვის, ტექნიკისთვის, რომლის განახლებაც შეუძლებელია.

შემიძლია ვნახო, რატომ უარმყო სერვერმა, root წვდომის გარეშე?

სერვერის მხრიდან არა - authentication log უმეტეს სისტემაზე მხოლოდ root-ს ან adm ჯგუფს იკითხება. მაინც შეგიძლია საკმაოდ შორს წახვიდე ssh -v-ით და fingerprint-ების შედარებით, შემდეგ კი შენი მცდელობის ზუსტი დროის ნიშნული გაუგზავნე ვინც სერვერს ადმინისტრირებს, რომ შესაბამისი ლოგის ხაზი სწრაფად იპოვოს.

ნიშნავს თუ არა Permission denied (publickey), რომ ჩემი გასაღები მოიპარეს ან სერვერი გატეხეს?

თითქმის არასდროს. ეს სერვერი თავის საქმეს აკეთებს: უარყოფს გასაღებს, რომელსაც არ ცნობს. შეშფოთება host key-ის შეცვლის გაფრთხილებამ უნდა გამოიწვიოს და არა ამან. თუ authorized_keys-ში გასაღებები გამოჩნდა, რომლებიც შენ არ დაგიმატებია, ეს სრულიად სხვა სიტუაციაა და what to do when your server is hacked შემდეგი წასაკითხია.