آموزش مدیریت و استفاده از SSH key
نحوه کارکرد SSH key، تنظیم file permissions برای sshd، استفاده از Host در فایل config و روش لغو دسترسی کلیدهای گم شده را در Ubuntu 24.04 بیاموزید.
نحوه عملکرد کلیدهای SSH
یک کلید SSH شامل دو فایل است: یک private key که در دستگاه شما باقی میماند و یک public key که آن را در تمام سرورهایی که میخواهید به آنها متصل شوید، کپی میکنید. هنگام اتصال، سرور از public key برای ارسال یک challenge استفاده میکند که فقط private key متناظر میتواند به آن پاسخ دهد. private key هرگز از دستگاه شما خارج نمیشود، بنابراین هیچ اطلاعات محرمانهای در شبکه جابهجا نمیشود و اگر سروری هک شود، چیزی برای سرقت ندارد. به همین دلیل است که کلیدها از password بهتر هستند. مدیریت صحیح کلیدهای SSH شامل چهار عادت است: یک کلید برای هر دستگاه، رعایت دسترسیهای فایل (file permissions) مورد نیاز sshd، استفاده از یک فایل ~/.ssh/config برای جلوگیری از تایپ مکرر گزینهها، و دانستن نحوه حذف یک کلید در روزی که لپتاپ مفقود میشود.
این راهنما هر عادت را در Ubuntu 24.04 پوشش میدهد، هرچند تقریباً تمام موارد در اینجا برای هر سرور Linux و هر نسخه جدید OpenSSH کاربرد دارد.
قبل از شروع، یک نکته واژهشناسی را بیان میکنیم تا از اشتباهات جدی جلوگیری شود. public key محرمانه نیست. شما میتوانید آن را در یک ticket کپی کنید، با ایمیل ارسال کنید یا منتشر کنید، و هیچکس نمیتواند با آن وارد شود. private key همان بخش محرمانه است. از نظر سرورهای شما، هر کسی که آن فایل را کپی کند و passphrase آن را (در صورت وجود) بداند، همان شما هستید.
ایجاد یک کلید: ed25519 گزینه پیشفرض مناسب است
در کامپیوتر شخصی خود و نه در سرور، دستور زیر را اجرا کنید:
ssh-keygen -t ed25519 -C "laptop"گزینه -t ed25519 نوع کلید را انتخاب میکند. Ed25519 پیشفرض مدرن است: این کلیدها کوتاه و سریع هستند و تمام نسخههای OpenSSH از سال 2014 از آنها پشتیبانی میکنند. تنها زمانی از ssh-keygen -t rsa -b 4096 استفاده کنید که مجبور باشید با دستگاه قدیمی که ed25519 را نمیشناسد، ارتباط برقرار کنید. گزینه -C "laptop" یک کامنت (توضیحات) تعیین میکند. این کامنت عمل رمزنگاری انجام نمیدهد، اما روشی است که دو سال دیگر با آن این کلید را در فایل authorized_keys سرور شناسایی میکنید؛ بنابراین نام دستگاهی که کلید روی آن قرار دارد را بنویسید.
گزینه ssh-keygen مسیر ذخیرهسازی کلید را میپرسد. مقدار پیشفرض یعنی ~/.ssh/id_ed25519 را تایید کنید. سپس از شما یک passphrase (عبارت عبور) میخواهد. حتماً یک عبارت تعیین کنید؛ بخش passphrase در ادامه توضیح میدهد که چرا استفاده از آن در استفادههای روزمره هزینهای برای شما ندارد. در نهایت دو فایل خواهید داشت: ~/.ssh/id_ed25519 کلید خصوصی است و ~/.ssh/id_ed25519.pub کلید عمومی است. نیمه عمومی را مشاهده کنید:
cat ~/.ssh/id_ed25519.pubssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF3k2s0vQx7GdKQhX1yBz... laptopاین یک خط است: نوع کلید، محتوای کلید و کامنت شما. این همان خطی است که در سرورهای شما قرار میگیرد.
یک کلید برای هر دستگاه، نه یک کلید برای هر سرور
اولین سوالی که همه میپرسند این است: آیا برای هر سرور به یک کلید جدید نیاز دارم؟ خیر. برای هر دستگاهی که با آن تایپ میکنید، یک کلید بسازید و آن کلید عمومی را در تمام سرورهایی که آن دستگاه به آنها نیاز دارد، قرار دهید. این کلید، دستگاه را شناسایی میکند. فایل authorized_keys در هر سرور، شامل لیست دستگاههای مجاز است.
این مدلی است که قابلیت مقیاسپذیری دارد؛ روشهای جایگزین به شکلی قابل پیشبینی شکست میخورند. استفاده از یک کلید برای هر سرور به این معناست که یک لپتاپ با 20 سرور، 20 کلید خصوصی حمل میکند و شما مشخصات هر کدام را گم خواهید کرد. استفاده از یک کلید مشترک برای تمام دستگاهها بدتر است: اگر لپتاپ سرقت شود، نمیتوانید دسترسی لپتاپ را لغو کنید بدون اینکه دسترسی دسکتاپ را نیز قطع کنید؛ زیرا هر دو دارای یک کلید خصوصی یکسان هستند. در این حالت، مجبورید کلید را در همه جا جایگزین کرده و همزمان آن را در تمام دستگاهها بازنشر کنید.
با استفاده از یک کلید برای هر دستگاه، هزینه از دست رفتن لپتاپ فقط یک خط در هر سرور است: خط مربوط به لپتاپ را از authorized_keys حذف کنید و سایر دستگاهها همچنان به کار خود ادامه میدهند. کامنتی که با استفاده از -C تنظیم میکنید، باعث میشود پیدا کردن آن خط آسان باشد.
قانون اصلی این مدل: یک کلید خصوصی روی یک دستگاه ساخته میشود و با همان دستگاه از بین میرود. هرگز یک کلید خصوصی را در دستگاه دوم کپی نکنید و هرگز آن را روی سرور آپلود نکنید. وقتی دستگاه جدیدی به دسترسی نیاز داشت، یک کلید جدید روی آن بسازید.
قرار دادن کلید عمومی در سرور
روش ساده استفاده از ssh-copy-id است که همراه با OpenSSH ارائه میشود:
ssh-copy-id matt@10.0.0.10این دستور با استفاده از روشی که هنوز فعال است (معمولاً رمز عبور) وارد میشود، کلید عمومی شما را به فایل ~/.ssh/authorized_keys در سرور اضافه میکند، و در صورت عدم وجود، پوشه و فایل را با دسترسیهای (permissions) صحیح ایجاد میکند. با باز کردن یک نشست SSH جدید، آن را تست کنید: سرور باید بدون درخواست رمز عبور حساب کاربری، اجازه ورود به شما بدهد. اگر کلید شما دارای passphrase باشد، سیستم شما ممکن است آن را درخواست کند؛ آن درخواست مربوط به سیستم محلی است و رمز عبور سرور نیست.
زمانی که ورود با رمز عبور از قبل غیرفعال شده باشد، ssh-copy-id نمیتواند وارد شود، بنابراین باید خط مورد نظر را به صورت دستی اضافه کنید. از طریق یک نشست فعال یا کنسول وب ارائهدهنده خود وارد شوید و این دستور را در سرور اجرا کنید:
mkdir -p ~/.ssh && chmod 700 ~/.ssh
echo "ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIF3k2s0vQx7GdKQhX1yBz... laptop" >> ~/.ssh/authorized_keys
chmod 600 ~/.ssh/authorized_keysکلید عمومی واقعی خود را که یک خط کامل از خروجی id_ed25519.pub است، داخل علامتهای نقلقول قرار دهید. در فایل authorized_keys، هر خط شامل یک کلید عمومی است و کل پایگاه داده دسترسیها همین است: اضافه کردن یک دستگاه یعنی اضافه کردن یک خط، و لغو دسترسی یک دستگاه یعنی حذف یک خط. در یک سرور تازه، این مرحله باید در 10 دقیقه اول در یک VPS جدید، دقیقاً قبل از اینکه ورود با رمز عبور را غیرفعال کنید، انجام شود.
مجوزهایی که باعث شکست ورود با کلید میشوند
این رایجترین دلیل شکست خوردن ورود با کلید است و در سمت کلاینت بدون هیچ پیامی رخ میدهد. در Ubuntu 24.04، سرویس sshd به صورت پیشفرض با StrictModes yes اجرا میشود؛ این یعنی اگر فایل authorized_keys توسط کاربران دیگر قابل ویرایش باشد، sshd از استفاده از آن خودداری میکند. اگر فایل، دایرکتوری ~/.ssh یا دایرکتوری home شما توسط شخصی غیر از خودتان قابل نوشتن باشد، sshd کلید شما را نادیده میگیرد و بدون هیچ توضیحی در کلاینت، به درخواست رمز عبور بازمیگردد. (OpenSSH در Ubuntu تنها یک حالت استثنا را میپذیرد: فایلی که توسط گروه اختصاصی خودتان قابل نوشتن باشد و هیچ فرد دیگری در آن گروه نباشد. به این استثنا تکیه نکنید؛ از تنظیمات زیر استفاده کنید.) دلیل این اتفاق فقط در لاگ سرور ظاهر میشود:
sudo grep 'Authentication refused' /var/log/auth.logدر یک ایمج مینیمال که rsyslog ندارد، auth.log وجود ندارد؛ همان خط در journal موجود است: sudo journalctl -u ssh | grep 'Authentication refused'.
Authentication refused: bad ownership or modes for file /home/matt/.ssh/authorized_keysراه حل شامل دو تغییر در مجوزها و یک بررسی مالکیت است که باید در سرور و توسط کاربر آسیبدیده اجرا شود:
chmod 700 ~/.ssh
chmod 600 ~/.ssh/authorized_keys
chown -R matt:matt ~/.sshقاعدهای که باید به خاطر بسپارید: 700 برای دایرکتوری .ssh و 600 برای تمام محتویات داخل آن. همین اعداد در کامپیوتر خودتان نیز صدق میکنند، زیرا کلاینت نیز بررسی میکند. یک کلید خصوصی که توسط کاربران دیگر قابل خواندن باشد، باعث میشود ssh کلید را مستقیماً رد کند و این بار خطا به وضوح نمایش داده میشود:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: UNPROTECTED PRIVATE KEY FILE! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions 0644 for '/home/matt/.ssh/id_ed25519' are too open.chmod 600 ~/.ssh/id_ed25519 آن را اصلاح میکند.
~/.ssh/config: توقف تایپ گزینهها
یک فایل ~/.ssh/config در کامپیوتر شخصی شما، به هر سرور یک نام کوتاه اختصاص میدهد و گزینههایی را که مدام تایپ میکنید، به خاطر میسپارد. این فایل را با دسترسیهای 600 ایجاد کنید و برای هر سرور یک بلوک Host اضافه کنید:
Host web1
HostName 10.0.0.10
User matt
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Host db1
HostName 10.0.0.11
User matt
Port 2222
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yesحالا ssh web1 جایگزین ssh -p 22 matt@10.0.0.10 میشود و همان نام کوتاه در scp، rsync و git نیز کار میکند، زیرا همه آنها این فایل را میخوانند. HostName آدرس واقعی است، User از تایپ نام کاربری جلوگیری میکند و IdentityFile مشخص میکند که کدام کلید ارائه شود.
IdentitiesOnly yes نیاز به توضیح دارد، زیرا یک خطای گیجکننده را برطرف میکند. وقتی agent شما چندین کلید دارد، client آنها را یکی پس از دیگری ارائه میدهد و سرور هر ارائه را به عنوان یک تلاش ناموفق محاسبه میکند. اگر کلیدهای زیادی بارگذاری شده باشد، قبل از اینکه کلید درست امتحان شود، با Received disconnect: Too many authentication failures مواجه میشوید. IdentitiesOnly yes باعث میشود client فقط کلیدی را که در IdentityFile نام برده شده ارائه دهد، بنابراین آن خطا رخ نمیدهد.
Passphrases and ssh-agent
یک passphrase فایل کلید خصوصی را روی دیسک رمزگذاری میکند. بدون آن، هر کسی که فایل را کپی کند میتواند بلافاصله از آن استفاده کند؛ با داشتن passphrase، فایل سرقت شده تا زمانی که رمز حدس زده نشود، بیاستفاده است. برای کلیدی که روی یک لپتاپ قرار دارد، این دقیقاً همان حفاظتی است که نیاز دارید، زیرا لپتاپها سرقت میشوند و از بکآپهای آنها نیز نشت اطلاعات رخ میدهد.
دلیل اینکه استفاده از passphrase در عمل هزینهای ندارد، ssh-agent است. agent کلید رمزگشایی شده شما را در حافظه نگه میدارد، بنابراین شما فقط یک بار در هر نشست (session) ورود، passphrase را تایپ میکنید و تمام اتصالات بعدی آنی خواهند بود. اکثر توزیعهای دسکتاپ Linux و macOS از قبل یک agent را برای شما اجرا میکنند. کلید خود را با دستور زیر در آن بارگذاری کنید:
ssh-add ~/.ssh/id_ed25519دستور ssh-add -l کلیدهایی که agent در حال حاضر نگه میدارد را لیست میکند. یک هشدار: agent forwarding (ssh -A) اجازه میدهد سرور راه دور در حین اتصال شما، از agent شما برای احراز هویت در مراحل بعدی استفاده کند؛ بنابراین این قابلیت را فقط برای سرورهایی که کاملاً به آنها اعتماد دارید فعال کنید و در حالت پیشفرض آن را خاموش بگذارید.
چرخش و ابطال: تمرین لپتاپ گمشده
ابطال یک SSH key معمولی، چیزی جز حذف خط مربوط به آن از authorized_keys در تمام سرورهایی که آن را دارند نیست. هیچ مرجع صدور گواهی (Certificate Authority) برای اطلاعرسانی وجود ندارد و نیازی به انتظار برای تاریخ انقضا نیست. به محض حذف آن خط، ورودهای جدید با آن کلید با شکست مواجه میشوند.
این تمرین را همین حالا، در زمانی که وضعیت اضطراری نیست، انجام دهید. یک سرور را انتخاب کنید، ~/.ssh/authorized_keys را باز کنید و کلید را از طریق comment آن پیدا کنید. خط مربوطه را با یک editor حذف کنید یا با استفاده از comment آن، آن را فیلتر کنید:
grep -v ' laptop$' ~/.ssh/authorized_keys > ~/.ssh/authorized_keys.tmp
mv ~/.ssh/authorized_keys.tmp ~/.ssh/authorized_keysسپس از دستگاهی که کلید آن را باطل کردهاید، تایید کنید که ورود اکنون با شکست مواجه میشود، و از دستگاهی دیگر تایید کنید که ورود همچنان برقرار است. به این نکته توجه کنید: حذف یک کلید، نشستهای (sessions) باز را نمیبندد، زیرا کلید فقط هنگام ورود بررسی میشود. اگر در حال ابطال یک دستگاه سرقتشده هستید، who را نیز در سرور بررسی کنید و هر نشست ناشناسی را خاتمه دهید.
چرخش (Rotation) همان عملیات است اما با ترتیبی متفاوت: یک کلید جدید در دستگاه ایجاد کنید، آن را با ssh-copy-id نصب کنید، ورود با کلید جدید را تایید کنید و سپس خط قدیمی را حذف کنید. این کار را زمانی انجام دهید که مالکیت دستگاه تغییر میکند، زمانی که احتمال افشای کلید وجود دارد، یا زمانی که فردی از تیم جدا میشود. انجام این کار به صورت دستی برای دو سرور مناسب است؛ اما برای بیست سرور، این کار نیاز به اتوماسیون دارد و مدیریت چندین سرور Linux نشان میدهد که چگونه یک وضعیت authorized_keys یکسان را به کل یک مجموعه (fleet) اعمال کنید.
کارهایی که نباید انجام دهید
- از به کارگیری یک private key واحد در تمام دستگاههای خود خودداری کنید. در این صورت، با سرقت یکی از دستگاهها، امکان لغو دسترسی آن بدون تعویض کلید در تمامی دستگاهها وجود نخواهد داشت.
- private key را در یک git repository کامیت نکنید، حتی اگر آن مخزن private باشد. اسکنرهای خودکار مخازن public را زیر نظر دارند و در عرض چند دقیقه پس از push، کلیدهای لو رفته را شناسایی میکنند؛ همچنین اگر یک مخزن بعداً public شود، تمام تاریخچه آن لو میرود.
- برای برقراری ارتباط بین دو سرور، private key لپتاپ خود را روی سرور آپلود نکنید. روی خودِ سرور یک کلید مجزا تولید کنید و آن کلید را دقیقاً در جایی که نیاز است، مجاز (authorise) کنید.
- private key را در چت، ایمیل یا تیکت کپی نکنید. کلید public یا همان فایل
.pub، تنها بخشی است که باید به اشتراک گذاشته شود.
زمانی که ورود با کلید برای شما با موفقیت انجام شد، مرحله بعد را اجرا کنید و authentication مبتنی بر password را غیرفعال کنید تا حملات guessing مداوم علیه سرور شما با شکست مواجه شوند. تنظیمات آماده برای این کار در SSH hardening on a VPS موجود است.
FAQ
کلیدهای SSH بدون ارسال رمز عبور چگونه کار میکنند؟
سرور کلید عمومی شما را در ~/.ssh/authorized_keys نگه میدارد. هنگام ورود، سرور یک چالش (challenge) ارسال میکند، کلاینت شما آن چالش را با کلید خصوصی امضا میکند، و سپس سرور امضا را با کلید عمومی تایید میکند. کلید خصوصی هرگز از دستگاه شما خارج نمیشود، بنابراین چیزی برای شنود در مسیر وجود ندارد و چیزی برای سرقت از سرور که قابل استفاده مجدد باشد، وجود ندارد. در صورت هک شدن سرور، فقط کلیدهای عمومی لو میروند که نمیتوان با آنها به هیچ جای دیگری وارد شد.
آیا باید از یک کلید SSH یکسان برای تمام سرورهایم استفاده کنم؟
استفاده از یک کلید برای سرورهای متعدد درست است، تا زمانی که آن کلید فقط روی یک دستگاه باقی بماند. قانون این است: یک کلید برای هر دستگاه، نه یک کلید برای هر سرور. کلید عمومی لپتاپ شما باید در تمام سرورهایی که لپتاپ به آنها نیاز دارد قرار بگیرد، و کامپیوتر رومیزی شما باید کلید مخصوص به خود را داشته باشد. این روش لغو دسترسی (revocation) را ساده میکند؛ زیرا از دست دادن یک دستگاه به معنای حذف تنها یک خط مشخص از هر سرور است و سایر دستگاهها همچنان کار میکنند.
پوشه .ssh و فایل authorized_keys چه دسترسیهایی (permissions) باید داشته باشند؟
دسترسی 700 را برای ~/.ssh و دسترسی 600 را برای authorized_keys و تمام کلیدهای خصوصی تنظیم کنید؛ مالکیت این فایلها باید متعلق به همان کاربری باشد که از آنها استفاده میکند. سرویس sshd به صورت پیشفرض با StrictModes yes اجرا میشود، بنابراین اگر هر کسی به جز شما بتواند در یک فایل یا پوشه home نوشتن داشته باشد، sshd کلید شما را نادیده میگیرد و تنها اثر آن Authentication refused: bad ownership or modes در log یا journal مربوط به auth سرور خواهد بود.
چگونه یک کلید SSH را از یک سرور حذف کنم؟
خط مربوط به آن کلید را از فایل ~/.ssh/authorized_keys در کاربری که اجازه دسترسی داشته، حذف کنید. خط مورد نظر را از طریق کامنت (توضیحات) آن، یعنی برچسب بعد از محتوای کلید، پیدا کنید. ورودهای جدید با آن کلید بلافاصله با شکست مواجه میشوند، اما نشستهای (sessions) باز، باز میمانند؛ بنابراین اگر دستگاه سرقت شده است، نشستهای فعال آن دستگاه را نیز قطع کنید. این کار را در تمام سرورهایی که کلید در آنها کپی شده بود، تکرار کنید.
آیا کلید SSH من به یک passphrase نیاز دارد؟
برای کلیدی که روی لپتاپ یا کامپیوتر رومیزی است، بله. passphrase فایل کلید را رمزگذاری میکند، بنابراین یک نسخه سرقت شده یا لو رفته به تنهایی بیفایده است. همچنین استفاده از ssh-agent به این معناست که شما آن را فقط یک بار در هر نشست تایپ میکنید، نه برای هر اتصال. کلیدهایی که توسط اتوماسیون بدون نظارت (unattended automation) در یک سرور استفاده میشوند، معمولاً passphrase ندارند، زیرا انسانی برای تایپ آن حضور ندارد؛ برای محافظت از این کلیدها، محدود کنید که آن حساب کاربری چه کارهایی میتواند انجام دهد.