SSH安全加固與免密登錄
一、概述
1.1 背景介紹
線上服務(wù)器被暴力破解SSH密碼的事每個(gè)月都在發(fā)生。我們團(tuán)隊(duì)去年處理過(guò)一起安全事件,一臺(tái)測(cè)試機(jī)用了默認(rèn)22端口加弱密碼,48小時(shí)內(nèi)被植入挖礦程序,CPU跑滿導(dǎo)致同網(wǎng)段業(yè)務(wù)受影響。事后復(fù)盤發(fā)現(xiàn)/var/log/secure里有超過(guò)20萬(wàn)次失敗登錄記錄,全是字典攻擊。
SSH是Linux服務(wù)器遠(yuǎn)程管理的核心通道,OpenSSH默認(rèn)配置偏向兼容性而非安全性——允許root登錄、允許密碼認(rèn)證、監(jiān)聽(tīng)22端口。這些默認(rèn)值在公網(wǎng)環(huán)境下等于敞開(kāi)大門。生產(chǎn)環(huán)境必須做SSH加固,這不是可選項(xiàng),是基線要求。
本篇覆蓋端口修改、認(rèn)證方式切換、密鑰管理、fail2ban防護(hù)、證書(shū)認(rèn)證等完整加固鏈路,所有配置均在CentOS 7/8/9和Ubuntu 20.04/22.04上線上驗(yàn)證過(guò)。
1.2 技術(shù)特點(diǎn)
基于非對(duì)稱加密的身份認(rèn)證:SSH密鑰登錄使用公私鑰對(duì),私鑰不離開(kāi)客戶端,服務(wù)端只存公鑰。即使服務(wù)端被入侵,攻擊者拿到的公鑰無(wú)法反推私鑰。ed25519算法密鑰長(zhǎng)度僅68字節(jié),比RSA-4096的800+字節(jié)短得多,簽名驗(yàn)證速度快約30%。
支持多種認(rèn)證方式靈活組合:密碼認(rèn)證、公鑰認(rèn)證、證書(shū)認(rèn)證、GSSAPI認(rèn)證、鍵盤交互認(rèn)證,可以通過(guò)AuthenticationMethods指令組合使用。比如要求"公鑰+密碼"雙因素,配置為AuthenticationMethods publickey,password。
細(xì)粒度訪問(wèn)控制:通過(guò)AllowUsers、AllowGroups、DenyUsers、DenyGroups四個(gè)指令控制誰(shuí)能登錄,配合Match塊可以針對(duì)特定用戶、IP、端口設(shè)置不同策略。比如允許運(yùn)維組從跳板機(jī)登錄,禁止其他所有來(lái)源。
1.3 適用場(chǎng)景
場(chǎng)景一:公網(wǎng)服務(wù)器加固。云主機(jī)直接暴露在公網(wǎng),每天承受大量掃描和暴力破解。實(shí)測(cè)一臺(tái)新開(kāi)的阿里云ECS,開(kāi)機(jī)2小時(shí)內(nèi)就有來(lái)自全球的SSH登錄嘗試。必須改端口+禁密碼+上fail2ban三件套。
場(chǎng)景二:多人運(yùn)維團(tuán)隊(duì)密鑰管理。團(tuán)隊(duì)10+人需要登錄上百臺(tái)服務(wù)器,用密碼管理不現(xiàn)實(shí)。通過(guò)SSH密鑰+跳板機(jī)+ProxyJump實(shí)現(xiàn)統(tǒng)一入口管理,人員離職時(shí)只需在跳板機(jī)刪除公鑰。
場(chǎng)景三:自動(dòng)化運(yùn)維免密通道。Ansible、SaltStack等自動(dòng)化工具依賴SSH免密登錄批量執(zhí)行命令。CI/CD流水線部署也需要SSH免密推送代碼到目標(biāo)機(jī)器。密鑰認(rèn)證是自動(dòng)化的基礎(chǔ)。
1.4 環(huán)境要求
| 組件 | 版本要求 | 說(shuō)明 |
|---|---|---|
| 操作系統(tǒng) | CentOS 7+/Ubuntu 20.04+ | RHEL系和Debian系均適用,配置路徑一致 |
| OpenSSH | 7.4+ | 7.4開(kāi)始支持ed25519密鑰,8.0+支持證書(shū)認(rèn)證增強(qiáng) |
| fail2ban | 0.10+ | 用于防暴力破解,EPEL源或apt直接安裝 |
| firewalld/iptables | 系統(tǒng)自帶 | 用于限制SSH訪問(wèn)來(lái)源IP |
| Python | 3.6+ | fail2ban依賴,CentOS 7需手動(dòng)安裝python3 |
二、詳細(xì)步驟
2.1 準(zhǔn)備工作
2.1.1 系統(tǒng)檢查
# 檢查系統(tǒng)版本 cat /etc/os-release # 檢查當(dāng)前SSH版本,低于7.4的建議升級(jí) ssh -V # 檢查SSH服務(wù)狀態(tài) systemctl status sshd # 檢查當(dāng)前SSH監(jiān)聽(tīng)端口和連接數(shù) ss -tlnp | grep ssh # 檢查當(dāng)前登錄的SSH會(huì)話,確認(rèn)自己的連接信息 who -u # 查看最近的SSH登錄失敗記錄,評(píng)估當(dāng)前風(fēng)險(xiǎn) # CentOS/RHEL grep"Failed password"/var/log/secure | tail -20 # Ubuntu/Debian grep"Failed password"/var/log/auth.log | tail -20
重要提醒:修改SSH配置前,務(wù)必保持當(dāng)前SSH會(huì)話不斷開(kāi),同時(shí)開(kāi)一個(gè)新終端測(cè)試。配置改錯(cuò)了當(dāng)前會(huì)話還能用來(lái)恢復(fù),斷開(kāi)就只能去機(jī)房或用VNC了。我們團(tuán)隊(duì)的規(guī)矩是改SSH配置必須兩人操作,一人改一人保持連接。
2.1.2 安裝依賴
# CentOS/RHEL 安裝 sudo yum install -y epel-release sudo yum install -y fail2ban fail2ban-systemd openssh-server openssh-clients # Ubuntu/Debian 安裝 sudo apt update sudo apt install -y fail2ban openssh-server openssh-client # 確認(rèn)fail2ban版本 fail2ban-client --version
2.1.3 備份原始配置
# 備份SSH配置,帶日期方便回溯 sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d) # 備份PAM相關(guān)SSH配置 sudo cp /etc/pam.d/sshd /etc/pam.d/sshd.bak.$(date +%Y%m%d) # 驗(yàn)證備份 ls -la /etc/ssh/sshd_config.bak.*
2.2 核心配置
2.2.1 修改SSH監(jiān)聽(tīng)端口
默認(rèn)22端口是所有掃描器的第一目標(biāo)。改成高位端口不能防住定向攻擊,但能過(guò)濾掉99%的自動(dòng)化掃描。實(shí)測(cè)改端口后,/var/log/secure里的失敗登錄記錄從每天幾萬(wàn)條降到個(gè)位數(shù)。
# 編輯SSH配置文件 sudo vim /etc/ssh/sshd_config # 找到#Port22,改為: Port 52222
SELinux環(huán)境額外操作(CentOS/RHEL默認(rèn)開(kāi)啟SELinux):
# 檢查SELinux狀態(tài) getenforce # 如果是Enforcing,需要添加端口到SELinux策略 sudo semanage port -a -t ssh_port_t -p tcp 52222 # 驗(yàn)證端口已添加 sudo semanage port -l | grep ssh # 輸出應(yīng)包含:ssh_port_t tcp 52222, 22
防火墻放行新端口:
# firewalld(CentOS 7+) sudo firewall-cmd --permanent --add-port=52222/tcp sudo firewall-cmd --reload sudo firewall-cmd --list-ports # 或者iptables(舊系統(tǒng)) sudo iptables -A INPUT -p tcp --dport 52222 -j ACCEPT sudo iptables -D INPUT -p tcp --dport 22 -j ACCEPT sudo service iptables save # Ubuntu UFW sudo ufw allow 52222/tcp sudo ufw status
這個(gè)地方有個(gè)坑:先放行新端口再改配置重啟sshd,順序反了會(huì)把自己鎖在外面。
2.2.2 禁用Root直接登錄
root賬戶是暴力破解的首要目標(biāo),因?yàn)楣粽咧烂颗_(tái)Linux都有root用戶,只需要猜密碼。禁用root登錄后,攻擊者還得猜用戶名,難度指數(shù)級(jí)上升。
# /etc/ssh/sshd_config 中修改 PermitRootLogin no
配套操作:確保有一個(gè)sudo權(quán)限的普通用戶可用。
# 創(chuàng)建運(yùn)維用戶 sudo useradd -m -s /bin/bash opsadmin sudo passwd opsadmin # 加入wheel組(CentOS)或sudo組(Ubuntu) # CentOS sudo usermod -aG wheel opsadmin # Ubuntu sudo usermod -aG sudo opsadmin # 驗(yàn)證sudo權(quán)限 su - opsadmin sudo whoami # 輸出應(yīng)為 root
2.2.3 禁用密碼認(rèn)證,僅允許密鑰登錄
密碼認(rèn)證的問(wèn)題:再?gòu)?fù)雜的密碼也可能被社工、釣魚(yú)、撞庫(kù)搞到。密鑰認(rèn)證從原理上杜絕了暴力破解——私鑰文件不在網(wǎng)絡(luò)上傳輸,服務(wù)端只做簽名驗(yàn)證。
# /etc/ssh/sshd_config 中修改 PasswordAuthentication no ChallengeResponseAuthentication no UsePAM yes PubkeyAuthentication yes
這個(gè)參數(shù)改錯(cuò)了會(huì)導(dǎo)致所有用密碼登錄的人立刻無(wú)法連接,改之前確認(rèn)密鑰登錄已經(jīng)配好并測(cè)試通過(guò)。我見(jiàn)過(guò)不止一次有人先禁密碼后配密鑰,結(jié)果把自己鎖在外面。
2.2.4 配置訪問(wèn)白名單
# /etc/ssh/sshd_config 中添加 # 只允許特定用戶登錄 AllowUsers opsadmin deployer monitor # 或者只允許特定組登錄(二選一,不要同時(shí)配) # AllowGroups sshusers ops-team
說(shuō)明:AllowUsers和AllowGroups是白名單機(jī)制,配置后不在名單里的用戶全部拒絕。如果用AllowUsers,新增運(yùn)維人員時(shí)記得加到這個(gè)列表里,否則加了賬號(hào)也登不上。我們團(tuán)隊(duì)的做法是用AllowGroups sshusers,新人加入sshusers組就行,不用每次改sshd_config。
# 創(chuàng)建SSH用戶組 sudo groupadd sshusers # 將允許登錄的用戶加入組 sudo usermod -aG sshusers opsadmin sudo usermod -aG sshusers deployer
2.2.5 設(shè)置登錄超時(shí)和重試限制
# /etc/ssh/sshd_config 中修改 LoginGraceTime 30 MaxAuthTries 3 MaxSessions 5 MaxStartups 1060 ClientAliveInterval 300 ClientAliveCountMax 3
參數(shù)說(shuō)明:
LoginGraceTime 30:用戶30秒內(nèi)必須完成認(rèn)證,否則斷開(kāi)。默認(rèn)120秒太長(zhǎng)了。
MaxAuthTries 3:?jiǎn)未芜B接最多嘗試3次認(rèn)證。超過(guò)后斷開(kāi)連接,配合fail2ban效果更好。
MaxSessions 5:?jiǎn)蝹€(gè)連接最多5個(gè)會(huì)話復(fù)用。
MaxStartups 1060:當(dāng)未認(rèn)證連接數(shù)達(dá)到10個(gè)時(shí),以30%概率拒絕新連接;達(dá)到60個(gè)時(shí)100%拒絕。防止連接洪水攻擊。
ClientAliveInterval 300:每300秒(5分鐘)發(fā)一次心跳探測(cè)。
ClientAliveCountMax 3:連續(xù)3次心跳無(wú)響應(yīng)則斷開(kāi),即15分鐘無(wú)響應(yīng)自動(dòng)斷開(kāi)。
2.2.6 SSH密鑰對(duì)生成
# 推薦使用ed25519算法 # ed25519比RSA-4096更安全,密鑰更短,簽名更快 ssh-keygen -t ed25519 -C"opsadmin@company.com"-f ~/.ssh/id_ed25519 # 如果目標(biāo)系統(tǒng)OpenSSH版本低于6.5,不支持ed25519,退而求其次用RSA-4096 ssh-keygen -t rsa -b 4096 -C"opsadmin@company.com"-f ~/.ssh/id_rsa # 查看生成的密鑰 ls -la ~/.ssh/ # id_ed25519 私鑰文件,權(quán)限必須是600 # id_ed25519.pub 公鑰文件,權(quán)限644即可
關(guān)于密鑰密碼(passphrase):
生產(chǎn)環(huán)境的個(gè)人密鑰建議設(shè)置passphrase,防止私鑰文件泄露后被直接使用
自動(dòng)化場(chǎng)景(Ansible、CI/CD)的密鑰不設(shè)passphrase,否則每次執(zhí)行都要輸密碼
設(shè)了passphrase的密鑰可以用ssh-agent緩存,避免反復(fù)輸入
# 啟動(dòng)ssh-agent并添加密鑰 eval$(ssh-agent -s) ssh-add ~/.ssh/id_ed25519 # 輸入passphrase后,當(dāng)前會(huì)話內(nèi)不再需要重復(fù)輸入 # 查看已加載的密鑰 ssh-add -l
2.2.7 免密登錄配置
# 方法一:ssh-copy-id(推薦,自動(dòng)處理權(quán)限) ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 52222 opsadmin@192.168.1.100 # 方法二:手動(dòng)復(fù)制(ssh-copy-id不可用時(shí)) cat ~/.ssh/id_ed25519.pub | ssh -p 52222 opsadmin@192.168.1.100"mkdir -p ~/.ssh && chmod 700 ~/.ssh && cat >> ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys" # 測(cè)試免密登錄 ssh -p 52222 opsadmin@192.168.1.100 # 如果登錄失敗,用verbose模式排查 ssh -vvv -p 52222 opsadmin@192.168.1.100
權(quán)限要求(這個(gè)是最常見(jiàn)的坑):
# 服務(wù)端權(quán)限必須嚴(yán)格設(shè)置,多一個(gè)權(quán)限都不行 chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys chmod 600 ~/.ssh/id_ed25519 chmod 644 ~/.ssh/id_ed25519.pub # 家目錄權(quán)限不能大于755 chmod 755 ~ # 檢查文件屬主 ls -la ~/.ssh/ # 所有文件的owner必須是當(dāng)前用戶,不能是root
StrictModes yes(默認(rèn)開(kāi)啟)會(huì)檢查這些權(quán)限,權(quán)限不對(duì)直接拒絕密鑰認(rèn)證,而且日志里只寫(xiě)Authentication refused: bad ownership or modes,不告訴你具體哪個(gè)文件有問(wèn)題。
2.2.8 SSH Config配置多主機(jī)管理
管理幾十上百臺(tái)服務(wù)器時(shí),記IP和端口不現(xiàn)實(shí)。SSH Config文件可以給每臺(tái)機(jī)器起別名,配置不同的連接參數(shù)。
# 編輯客戶端配置文件 vim ~/.ssh/config
# 全局默認(rèn)配置 Host * ServerAliveInterval 60 ServerAliveCountMax 3 AddKeysToAgent yes IdentitiesOnly yes Compression yes # 跳板機(jī) Host jump HostName 203.0.113.10 Port 52222 User opsadmin IdentityFile ~/.ssh/id_ed25519 # 通過(guò)跳板機(jī)訪問(wèn)內(nèi)網(wǎng)Web服務(wù)器 Host web-prod-01 HostName 10.0.1.11 Port 22 User deployer IdentityFile ~/.ssh/id_ed25519 ProxyJump jump Host web-prod-02 HostName 10.0.1.12 Port 22 User deployer IdentityFile ~/.ssh/id_ed25519 ProxyJump jump # 數(shù)據(jù)庫(kù)服務(wù)器,限制只用特定密鑰 Host db-prod-* Port 22 User dbadmin IdentityFile ~/.ssh/id_ed25519_db ProxyJump jump Host db-prod-01 HostName 10.0.2.21 Host db-prod-02 HostName 10.0.2.22 # 測(cè)試環(huán)境,直連 Hosttest-* Port 52222 User opsadmin IdentityFile ~/.ssh/id_ed25519 Hosttest-web-01 HostName 192.168.100.11 Hosttest-db-01 HostName 192.168.100.21
# 配置好后直接用別名連接 ssh web-prod-01 ssh db-prod-01 # scp也能用別名 scp app.jar web-prod-01:/opt/app/ # rsync同樣支持 rsync -avz ./dist/ web-prod-01:/var/www/html/
說(shuō)明:IdentitiesOnly yes這個(gè)參數(shù)很關(guān)鍵。不加的話ssh會(huì)把~/.ssh/下所有密鑰都試一遍,如果密鑰多了,試到第3個(gè)還沒(méi)成功就會(huì)被MaxAuthTries 3攔住,報(bào)Too many authentication failures。加了這個(gè)參數(shù)后只用指定的密鑰文件。
2.2.9 配置fail2ban防暴力破解
fail2ban監(jiān)控SSH日志,發(fā)現(xiàn)短時(shí)間內(nèi)多次登錄失敗就自動(dòng)封禁IP。實(shí)測(cè)效果:部署后暴力破解嘗試從每天5萬(wàn)+降到0(因?yàn)楣鬒P在第5次嘗試后就被ban了)。
# 創(chuàng)建SSH專用的fail2ban配置 sudo vim /etc/fail2ban/jail.local
[DEFAULT] # 封禁時(shí)間3600秒(1小時(shí)),慣犯會(huì)遞增 bantime = 3600 # 在600秒(10分鐘)內(nèi) findtime = 600 # 失敗5次就封禁 maxretry = 5 # 封禁動(dòng)作:firewalld或iptables banaction = firewallcmd-ipset # 如果用iptables,改為: # banaction = iptables-multiport # 忽略的IP(運(yùn)維跳板機(jī)IP,防止把自己封了) ignoreip = 127.0.0.1/8 10.0.0.0/8 192.168.1.0/24 [sshd] enabled = true port = 52222 filter = sshd logpath = /var/log/secure # Ubuntu用這個(gè)路徑: # logpath = /var/log/auth.log maxretry = 3 bantime = 7200 findtime = 300
# 啟動(dòng)fail2ban sudo systemctl start fail2ban sudo systemctlenablefail2ban # 查看SSH jail狀態(tài) sudo fail2ban-client status sshd # 輸出示例: # Status for the jail: sshd # |- Filter # | |- Currently failed: 2 # | |- Total failed: 156 # | `- File list: /var/log/secure # `- Actions # |- Currently banned: 3 # |- Total banned: 47 # `- Banned IP list: 185.234.xx.xx 103.145.xx.xx 45.148.xx.xx # 手動(dòng)解封某個(gè)IP(比如同事輸錯(cuò)密碼被封了) sudo fail2ban-clientsetsshd unbanip 192.168.1.50 # 手動(dòng)封禁某個(gè)IP sudo fail2ban-clientsetsshd banip 1.2.3.4
2.2.10 SSH證書(shū)認(rèn)證(CA簽發(fā)方式)
密鑰認(rèn)證的問(wèn)題:每臺(tái)服務(wù)器的authorized_keys都要維護(hù),100臺(tái)服務(wù)器就是100份。人員變動(dòng)時(shí)要逐臺(tái)刪除。SSH證書(shū)認(rèn)證用CA統(tǒng)一簽發(fā),服務(wù)端只信任CA,不需要維護(hù)每臺(tái)機(jī)器的authorized_keys。
# 1. 生成CA密鑰對(duì)(在CA服務(wù)器上操作,通常是跳板機(jī)) ssh-keygen -t ed25519 -f /etc/ssh/ca_user_key -C"SSH User CA" # 2. 將CA公鑰分發(fā)到所有服務(wù)器 # 在每臺(tái)服務(wù)器的 /etc/ssh/sshd_config 中添加: TrustedUserCAKeys /etc/ssh/ca_user_key.pub # 3. 把CA公鑰復(fù)制到服務(wù)器 sudo scp /etc/ssh/ca_user_key.pub target-server:/etc/ssh/ca_user_key.pub # 4. 為用戶簽發(fā)證書(shū) # -s 簽發(fā)者標(biāo)識(shí) # -I 證書(shū)ID(用于審計(jì)日志) # -n 允許登錄的用戶名列表 # -V 有效期(+52w表示52周) ssh-keygen -s /etc/ssh/ca_user_key -I"opsadmin-cert-20250101" -n opsadmin,deployer -V +52w /home/opsadmin/.ssh/id_ed25519.pub # 生成的證書(shū)文件:/home/opsadmin/.ssh/id_ed25519-cert.pub # 5. 查看證書(shū)信息 ssh-keygen -L -f /home/opsadmin/.ssh/id_ed25519-cert.pub # 6. 用戶使用證書(shū)登錄(自動(dòng)識(shí)別,無(wú)需額外配置) ssh -p 52222 opsadmin@192.168.1.100
證書(shū)吊銷:
# 生成吊銷列表 ssh-keygen -k -f /etc/ssh/revoked_keys -s /etc/ssh/ca_user_key /path/to/revoked_cert.pub # 在sshd_config中配置吊銷列表 RevokedKeys /etc/ssh/revoked_keys # 重載配置 sudo systemctl reload sshd
2.3 啟動(dòng)和驗(yàn)證
2.3.1 配置檢查和重載
# 檢查配置文件語(yǔ)法(改完必做,語(yǔ)法錯(cuò)誤會(huì)導(dǎo)致sshd無(wú)法啟動(dòng)) sudo sshd -t # 沒(méi)有輸出表示語(yǔ)法正確,有錯(cuò)誤會(huì)顯示具體行號(hào) # 用調(diào)試模式檢查配置 sudo sshd -T | head -50 # 重載配置(不斷開(kāi)現(xiàn)有連接) sudo systemctl reload sshd # 如果reload不生效,再restart(會(huì)斷開(kāi)所有連接) # sudo systemctl restart sshd # 確認(rèn)服務(wù)狀態(tài) sudo systemctl status sshd
2.3.2 功能驗(yàn)證
# 1. 驗(yàn)證端口變更(新開(kāi)終端測(cè)試,不要斷開(kāi)當(dāng)前連接)
ssh -p 52222 opsadmin@服務(wù)器IP
# 2. 驗(yàn)證root登錄已禁用
ssh -p 52222 root@服務(wù)器IP
# 預(yù)期輸出:Permission denied (publickey).
# 3. 驗(yàn)證密碼登錄已禁用
ssh -p 52222 -o PubkeyAuthentication=no opsadmin@服務(wù)器IP
# 預(yù)期輸出:Permission denied (publickey).
# 4. 驗(yàn)證密鑰登錄正常
ssh -p 52222 -i ~/.ssh/id_ed25519 opsadmin@服務(wù)器IP
# 預(yù)期:直接登錄成功
# 5. 驗(yàn)證fail2ban工作
# 故意用錯(cuò)誤密碼嘗試幾次(在測(cè)試環(huán)境操作)
sudo fail2ban-client status sshd
# 6. 驗(yàn)證端口監(jiān)聽(tīng)
ss -tlnp | grep 52222
# 預(yù)期輸出:LISTEN 0 128 *:52222 *:* users:(("sshd",pid=xxxx,fd=3))
2.3.3 回滾方案
如果加固后出現(xiàn)問(wèn)題,按以下步驟回滾:
# 恢復(fù)備份的配置 sudo cp /etc/ssh/sshd_config.bak.$(date +%Y%m%d) /etc/ssh/sshd_config # 重啟SSH服務(wù) sudo systemctl restart sshd # 如果SSH完全無(wú)法連接,通過(guò)以下方式恢復(fù): # 1. 云服務(wù)器:通過(guò)控制臺(tái)VNC登錄 # 2. 物理機(jī):接顯示器鍵盤直接操作 # 3. 如果有IPMI/iLO/iDRAC遠(yuǎn)程管理卡,通過(guò)帶外管理登錄
三、示例代碼和配置
3.1 完整配置示例
3.1.1 生產(chǎn)級(jí)sshd_config完整配置
這份配置在我們團(tuán)隊(duì)管理的300+臺(tái)CentOS 7/8和Ubuntu 20.04/22.04服務(wù)器上跑了兩年多,沒(méi)出過(guò)認(rèn)證相關(guān)的事故。每一行都有注釋說(shuō)明為什么這么配。
# 文件路徑:/etc/ssh/sshd_config # 最后修改:2025-01-15 # 說(shuō)明:生產(chǎn)環(huán)境SSH加固配置 # ============================================ # 網(wǎng)絡(luò)和協(xié)議 # ============================================ # 監(jiān)聽(tīng)端口,改掉默認(rèn)22 Port 52222 # 只監(jiān)聽(tīng)I(yíng)Pv4,如果不用IPv6就關(guān)掉,減少攻擊面 AddressFamily inet # 綁定特定IP(多網(wǎng)卡服務(wù)器建議綁內(nèi)網(wǎng)IP) # 如果只允許從內(nèi)網(wǎng)跳板機(jī)連接: # ListenAddress 10.0.0.100 # 如果需要公網(wǎng)訪問(wèn): ListenAddress 0.0.0.0 # 協(xié)議版本,只用2(OpenSSH 7.4+已經(jīng)默認(rèn)只支持2) Protocol 2 # ============================================ # 主機(jī)密鑰 # ============================================ HostKey /etc/ssh/ssh_host_ed25519_key HostKey /etc/ssh/ssh_host_rsa_key # 不用DSA和ECDSA # HostKey /etc/ssh/ssh_host_dsa_key # HostKey /etc/ssh/ssh_host_ecdsa_key # ============================================ # 加密算法(只保留安全的算法) # ============================================ # 密鑰交換算法 KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512 # 對(duì)稱加密算法 Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr # MAC算法 MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com # ============================================ # 認(rèn)證配置 # ============================================ # 禁止root登錄 PermitRootLogin no # 啟用公鑰認(rèn)證 PubkeyAuthentication yes AuthorizedKeysFile .ssh/authorized_keys # 禁用密碼認(rèn)證 PasswordAuthentication no PermitEmptyPasswords no # 禁用質(zhì)詢響應(yīng)認(rèn)證 ChallengeResponseAuthentication no # 禁用基于主機(jī)的認(rèn)證 HostbasedAuthentication no IgnoreRhosts yes # 禁用GSSAPI(不用Kerberos就關(guān)掉,開(kāi)著會(huì)導(dǎo)致連接慢) GSSAPIAuthentication no GSSAPICleanupCredentials no # 禁用X11轉(zhuǎn)發(fā)(服務(wù)器不需要圖形界面) X11Forwarding no # 禁用TCP轉(zhuǎn)發(fā)(如果不需要SSH隧道) # AllowTcpForwarding no # 如果需要SSH隧道做端口轉(zhuǎn)發(fā),保持默認(rèn)yes AllowTcpForwarding yes # 禁用Agent轉(zhuǎn)發(fā)(除非明確需要) AllowAgentForwarding no # 關(guān)閉DNS反向解析(開(kāi)著會(huì)導(dǎo)致連接慢2-5秒) UseDNS no # 使用PAM UsePAM yes # ============================================ # 訪問(wèn)控制 # ============================================ # 只允許sshusers組的用戶登錄 AllowGroups sshusers # 或者指定用戶白名單(和AllowGroups二選一) # AllowUsers opsadmin deployer monitor # ============================================ # 會(huì)話控制 # ============================================ # 認(rèn)證超時(shí)30秒 LoginGraceTime 30 # 最大認(rèn)證嘗試次數(shù) MaxAuthTries 3 # 最大會(huì)話數(shù) MaxSessions 5 # 未認(rèn)證連接限制 MaxStartups 1060 # 客戶端存活檢測(cè) ClientAliveInterval 300 ClientAliveCountMax 3 # ============================================ # 日志 # ============================================ SyslogFacility AUTH LogLevel VERBOSE # ============================================ # 登錄Banner # ============================================ Banner /etc/ssh/banner.txt PrintMotd no PrintLastLog yes # ============================================ # SFTP配置 # ============================================ Subsystem sftp /usr/libexec/openssh/sftp-server -l INFO -f AUTH # ============================================ # 證書(shū)認(rèn)證(可選) # ============================================ # TrustedUserCAKeys /etc/ssh/ca_user_key.pub # RevokedKeys /etc/ssh/revoked_keys # ============================================ # Match塊:針對(duì)特定用戶/組的特殊配置 # ============================================ # SFTP專用用戶,限制在家目錄 Match Group sftponly ChrootDirectory /data/sftp/%u ForceCommand internal-sftp AllowTcpForwarding no X11Forwarding no PermitTunnel no # 部署用戶,只允許從CI/CD服務(wù)器連接 Match User deployer Address 10.0.0.50 AllowTcpForwarding no PermitOpen none
登錄Banner文件:
# 文件路徑:/etc/ssh/banner.txt cat > /etc/ssh/banner.txt <'EOF' ********************************************************************* * ?WARNING: This system is?for?authorized users only. ? ? ? ? ? ? ? * * ?All activities on this system are logged and monitored. ? ? ? ? ?* * ?Unauthorized access will be prosecuted to the full extent of law.* ********************************************************************* EOF
3.1.2 批量分發(fā)SSH密鑰腳本
管理幾十臺(tái)服務(wù)器時(shí),手動(dòng)一臺(tái)臺(tái)ssh-copy-id太慢。這個(gè)腳本批量分發(fā)公鑰,支持密碼認(rèn)證(首次部署時(shí)用)和已有密鑰認(rèn)證兩種模式。
#!/bin/bash
# 文件名:distribute_ssh_keys.sh
# 功能:批量分發(fā)SSH公鑰到多臺(tái)服務(wù)器
# 依賴:sshpass(首次用密碼分發(fā)時(shí)需要)
# 用法:./distribute_ssh_keys.sh hosts.txt
set-euo pipefail
# ========== 配置區(qū) ==========
SSH_PORT=52222
SSH_USER="opsadmin"
PUB_KEY_FILE="$HOME/.ssh/id_ed25519.pub"
LOG_FILE="/tmp/ssh_key_distribute_$(date +%Y%m%d_%H%M%S).log"
TIMEOUT=10
# =============================
# 顏色輸出
RED='?33[0;31m'
GREEN='?33[0;32m'
YELLOW='?33[1;33m'
NC='?33[0m'
log() {
locallevel=$1
shift
localmsg="[$(date '+%Y-%m-%d %H:%M:%S')] [$level] $*"
echo-e"$msg"| tee -a"$LOG_FILE"
}
usage() {
echo"用法:$0<主機(jī)列表文件>"
echo""
echo"主機(jī)列表文件格式(每行一個(gè)IP):"
echo"192.168.1.101"
echo"192.168.1.102"
echo"10.0.1.11"
exit1
}
# 參數(shù)檢查
if[[$#-ne 1 ]];then
usage
fi
HOST_FILE=$1
if[[ ! -f"$HOST_FILE"]];then
log"ERROR""主機(jī)列表文件不存在:$HOST_FILE"
exit1
fi
if[[ ! -f"$PUB_KEY_FILE"]];then
log"ERROR""公鑰文件不存在:$PUB_KEY_FILE"
log"INFO""請(qǐng)先生成密鑰: ssh-keygen -t ed25519"
exit1
fi
# 檢查sshpass是否安裝
USE_PASSWORD=false
ifcommand-v sshpass &>/dev/null;then
read-sp"輸入SSH密碼(如果目標(biāo)機(jī)器已配置密鑰登錄,直接回車跳過(guò)): "SSH_PASS
echo
if[[ -n"$SSH_PASS"]];then
USE_PASSWORD=true
fi
fi
# 統(tǒng)計(jì)
TOTAL=0
SUCCESS=0
FAILED=0
log"INFO""開(kāi)始分發(fā)SSH公鑰"
log"INFO""公鑰文件:$PUB_KEY_FILE"
log"INFO""目標(biāo)用戶:$SSH_USER"
log"INFO""SSH端口:$SSH_PORT"
whileIFS=read-r host;do
# 跳過(guò)空行和注釋
[[ -z"$host"||"$host"=~ ^# ]] && continue
TOTAL=$((TOTAL + 1))
log"INFO""[$TOTAL] 正在處理:$host"
if$USE_PASSWORD;then
# 使用密碼分發(fā)
ifsshpass -p"$SSH_PASS"ssh-copy-id
-i"$PUB_KEY_FILE"
-p"$SSH_PORT"
-o StrictHostKeyChecking=no
-o ConnectTimeout=$TIMEOUT
"${SSH_USER}@${host}"2>>"$LOG_FILE";then
log"INFO""${GREEN}成功${NC}:$host"
SUCCESS=$((SUCCESS + 1))
else
log"ERROR""${RED}失敗${NC}:$host"
FAILED=$((FAILED + 1))
fi
else
# 使用已有密鑰分發(fā)新密鑰
ifssh-copy-id
-i"$PUB_KEY_FILE"
-p"$SSH_PORT"
-o StrictHostKeyChecking=no
-o ConnectTimeout=$TIMEOUT
"${SSH_USER}@${host}"2>>"$LOG_FILE";then
log"INFO""${GREEN}成功${NC}:$host"
SUCCESS=$((SUCCESS + 1))
else
log"ERROR""${RED}失敗${NC}:$host"
FAILED=$((FAILED + 1))
fi
fi
done"$HOST_FILE"
log"INFO""========== 分發(fā)完成 =========="
log"INFO""總計(jì):?$TOTAL? 成功:?$SUCCESS? 失敗:?$FAILED"
log"INFO""詳細(xì)日志:?$LOG_FILE"
if?[[?$FAILED?-gt 0 ]];?then
? ??log"WARN""有?$FAILED?臺(tái)服務(wù)器分發(fā)失敗,請(qǐng)檢查日志"
? ??exit?1
fi
# 使用方法 chmod +x distribute_ssh_keys.sh # 準(zhǔn)備主機(jī)列表 cat > hosts.txt <'EOF' 192.168.1.101 192.168.1.102 192.168.1.103 10.0.1.11 10.0.1.12 EOF # 執(zhí)行分發(fā) ./distribute_ssh_keys.sh hosts.txt
3.2 實(shí)際應(yīng)用案例
案例一:基于跳板機(jī)的SSH ProxyJump多層跳轉(zhuǎn)
場(chǎng)景描述:生產(chǎn)環(huán)境網(wǎng)絡(luò)架構(gòu)分三層——公網(wǎng)跳板機(jī)、DMZ區(qū)應(yīng)用服務(wù)器、內(nèi)網(wǎng)數(shù)據(jù)庫(kù)服務(wù)器。運(yùn)維人員從辦公網(wǎng)絡(luò)連接跳板機(jī),再跳轉(zhuǎn)到內(nèi)網(wǎng)服務(wù)器。數(shù)據(jù)庫(kù)服務(wù)器只允許從應(yīng)用服務(wù)器網(wǎng)段訪問(wèn)。
網(wǎng)絡(luò)拓?fù)?/strong>:
辦公網(wǎng)絡(luò)(172.16.0.0/16) | v 跳板機(jī)(公網(wǎng): 203.0.113.10, 內(nèi)網(wǎng): 10.0.0.1) | v 應(yīng)用服務(wù)器(10.0.1.0/24) | v 數(shù)據(jù)庫(kù)服務(wù)器(10.0.2.0/24)
SSH Config配置:
# ~/.ssh/config # 跳板機(jī)(一跳) Host jump HostName 203.0.113.10 Port 52222 User opsadmin IdentityFile ~/.ssh/id_ed25519 # 跳板機(jī)上開(kāi)啟Agent轉(zhuǎn)發(fā),用于二次跳轉(zhuǎn) ForwardAgent yes # 應(yīng)用服務(wù)器(二跳,通過(guò)跳板機(jī)) Host app-01 HostName 10.0.1.11 User deployer IdentityFile ~/.ssh/id_ed25519 ProxyJump jump Host app-02 HostName 10.0.1.12 User deployer IdentityFile ~/.ssh/id_ed25519 ProxyJump jump # 數(shù)據(jù)庫(kù)服務(wù)器(三跳,通過(guò)應(yīng)用服務(wù)器) Host db-master HostName 10.0.2.21 User dbadmin IdentityFile ~/.ssh/id_ed25519_db ProxyJump app-01 Host db-slave HostName 10.0.2.22 User dbadmin IdentityFile ~/.ssh/id_ed25519_db ProxyJump app-01
使用效果:
# 直接連接數(shù)據(jù)庫(kù)服務(wù)器,SSH自動(dòng)完成兩次跳轉(zhuǎn) ssh db-master # 實(shí)際路徑:本機(jī) -> jump(203.0.113.10) -> app-01(10.0.1.11) -> db-master(10.0.2.21) # 通過(guò)跳板機(jī)做端口轉(zhuǎn)發(fā),本地訪問(wèn)遠(yuǎn)程數(shù)據(jù)庫(kù) ssh -L 33073306 app-01 # 然后本地用 mysql -h 127.0.0.1 -P 3307 連接 # 通過(guò)跳板機(jī)傳文件到內(nèi)網(wǎng)服務(wù)器 scp backup.sql db-master:/tmp/
案例二:多環(huán)境SSH Config管理與自動(dòng)切換
場(chǎng)景描述:團(tuán)隊(duì)管理開(kāi)發(fā)、測(cè)試、預(yù)發(fā)布、生產(chǎn)四套環(huán)境,共200+臺(tái)服務(wù)器。不同環(huán)境用不同的密鑰和用戶,需要一套清晰的管理方案。
目錄結(jié)構(gòu):
~/.ssh/ ├── config # 主配置文件,include其他配置 ├── config.d/ │ ├── 00-defaults.conf # 全局默認(rèn)配置 │ ├── 10-dev.conf # 開(kāi)發(fā)環(huán)境 │ ├── 20-test.conf # 測(cè)試環(huán)境 │ ├── 30-staging.conf # 預(yù)發(fā)布環(huán)境 │ └── 40-prod.conf # 生產(chǎn)環(huán)境 ├── id_ed25519 # 默認(rèn)密鑰 ├── id_ed25519_prod # 生產(chǎn)環(huán)境專用密鑰 ├── id_ed25519_db # 數(shù)據(jù)庫(kù)專用密鑰 └── known_hosts
主配置文件:
# ~/.ssh/config # 使用Include指令加載分環(huán)境配置(OpenSSH 7.3+支持) Include config.d/*.conf
全局默認(rèn)配置:
# ~/.ssh/config.d/00-defaults.conf Host * ServerAliveInterval 60 ServerAliveCountMax 3 AddKeysToAgent yes IdentitiesOnly yes Compression yes # 連接復(fù)用,同一臺(tái)服務(wù)器的多個(gè)SSH會(huì)話共用一個(gè)TCP連接 ControlMaster auto ControlPath ~/.ssh/sockets/%r@%h-%p ControlPersist 600 # 首次連接自動(dòng)接受主機(jī)密鑰(僅限內(nèi)網(wǎng)環(huán)境,公網(wǎng)建議去掉) # StrictHostKeyChecking accept-new
生產(chǎn)環(huán)境配置:
# ~/.ssh/config.d/40-prod.conf # 生產(chǎn)環(huán)境 - 通過(guò)跳板機(jī)訪問(wèn) Host prod-jump HostName 203.0.113.10 Port 52222 User opsadmin IdentityFile ~/.ssh/id_ed25519_prod Host prod-web-* User deployer IdentityFile ~/.ssh/id_ed25519_prod ProxyJump prod-jump Host prod-web-01 HostName 10.0.1.11 Host prod-web-02 HostName 10.0.1.12 Host prod-web-03 HostName 10.0.1.13 Host prod-db-* User dbadmin IdentityFile ~/.ssh/id_ed25519_db ProxyJump prod-jump Host prod-db-master HostName 10.0.2.21 Host prod-db-slave-01 HostName 10.0.2.22 Host prod-db-slave-02 HostName 10.0.2.23
# 創(chuàng)建socket目錄(連接復(fù)用需要) mkdir -p ~/.ssh/sockets # 使用效果 ssh prod-web-01 # 連接生產(chǎn)Web服務(wù)器 ssh prod-db-master # 連接生產(chǎn)數(shù)據(jù)庫(kù)主庫(kù) # 查看當(dāng)前活躍的連接復(fù)用 ls ~/.ssh/sockets/ # 手動(dòng)關(guān)閉某個(gè)復(fù)用連接 ssh -Oexitprod-web-01
案例三:SSH密鑰自動(dòng)輪換腳本
場(chǎng)景描述:安全合規(guī)要求SSH密鑰每90天輪換一次。手動(dòng)操作容易遺漏,寫(xiě)個(gè)腳本自動(dòng)化處理。
#!/bin/bash
# 文件名:rotate_ssh_keys.sh
# 功能:自動(dòng)輪換SSH密鑰并分發(fā)到目標(biāo)服務(wù)器
# 建議配合crontab每季度執(zhí)行一次
set-euo pipefail
KEY_DIR="$HOME/.ssh"
KEY_TYPE="ed25519"
KEY_COMMENT="$(whoami)@$(hostname)-$(date +%Y%m%d)"
BACKUP_DIR="$KEY_DIR/archived_keys"
HOST_FILE="$HOME/.ssh/managed_hosts.txt"
LOG_FILE="/var/log/ssh_key_rotation_$(date +%Y%m%d).log"
log() {
echo"[$(date '+%Y-%m-%d %H:%M:%S')] $*"| tee -a"$LOG_FILE"
}
# 創(chuàng)建備份目錄
mkdir -p"$BACKUP_DIR"
# 1. 備份舊密鑰
if[[ -f"$KEY_DIR/id_${KEY_TYPE}"]];then
BACKUP_NAME="id_${KEY_TYPE}_$(date +%Y%m%d_%H%M%S)"
cp"$KEY_DIR/id_${KEY_TYPE}""$BACKUP_DIR/$BACKUP_NAME"
cp"$KEY_DIR/id_${KEY_TYPE}.pub""$BACKUP_DIR/${BACKUP_NAME}.pub"
log"舊密鑰已備份到:$BACKUP_DIR/$BACKUP_NAME"
fi
# 2. 生成新密鑰(不設(shè)passphrase,自動(dòng)化場(chǎng)景用)
ssh-keygen -t"$KEY_TYPE"-C"$KEY_COMMENT"-f"$KEY_DIR/id_${KEY_TYPE}"-N""-q
log"新密鑰已生成:$KEY_DIR/id_${KEY_TYPE}"
# 3. 分發(fā)新公鑰到所有服務(wù)器(用舊密鑰認(rèn)證)
if[[ -f"$HOST_FILE"]];then
whileIFS=:read-r host port user;do
port=${port:-52222}
user=${user:-opsadmin}
log"分發(fā)到:${user}@${host}:${port}"
ifssh-copy-id -i"$KEY_DIR/id_${KEY_TYPE}.pub"
-p"$port"
-o ConnectTimeout=10
-o IdentityFile="$BACKUP_DIR/$(ls -t $BACKUP_DIR/id_${KEY_TYPE}_* 2>/dev/null | head -1)"
"${user}@${host}"2>>"$LOG_FILE";then
log"成功:${host}"
else
log"失敗:${host}- 需要手動(dòng)處理"
fi
done"$HOST_FILE"
fi
# 4. 驗(yàn)證新密鑰可用
log"驗(yàn)證新密鑰..."
if?[[ -f?"$HOST_FILE"?]];?then
? ??while?IFS=:?read?-r host port user;?do
? ? ? ? port=${port:-52222}
? ? ? ? user=${user:-opsadmin}
? ? ? ??if?ssh -p?"$port"?-o ConnectTimeout=5 -o BatchMode=yes
? ? ? ? ? ??"${user}@${host}""echo ok"?&>/dev/null;then
log"驗(yàn)證通過(guò):${host}"
else
log"驗(yàn)證失敗:${host}- 緊急!請(qǐng)檢查"
fi
done"$HOST_FILE"
fi
log"密鑰輪換完成"
# managed_hosts.txt 格式:主機(jī):端口:用戶 cat > ~/.ssh/managed_hosts.txt <'EOF' 192.168.1.101opsadmin 192.168.1.102opsadmin 10.0.1.11deployer 10.0.1.12deployer EOF
四、最佳實(shí)踐和注意事項(xiàng)
4.1 最佳實(shí)踐
4.1.1 性能優(yōu)化
使用ed25519替代RSA密鑰:ed25519密鑰長(zhǎng)度只有68字節(jié),RSA-4096是800+字節(jié)。實(shí)測(cè)簽名速度ed25519比RSA-4096快約30%,在批量SSH操作(Ansible管理500臺(tái)機(jī)器)時(shí)差異明顯。Ansible playbook跑完全量主機(jī),ed25519密鑰比RSA-4096快了約12秒(總耗時(shí)從98秒降到86秒)。
# 生成ed25519密鑰 ssh-keygen -t ed25519 -C"ops@company.com" # 如果已有RSA密鑰,生成新的ed25519密鑰后逐步替換 ssh-keygen -t ed25519 -f ~/.ssh/id_ed25519 -C"ops@company.com"
開(kāi)啟連接復(fù)用(ControlMaster):同一臺(tái)服務(wù)器的多個(gè)SSH會(huì)話共用一個(gè)TCP連接,省去重復(fù)的TCP握手和密鑰交換。實(shí)測(cè)第二次連接耗時(shí)從1.2秒降到0.1秒。對(duì)于頻繁ssh/scp操作的場(chǎng)景提升巨大。
# ~/.ssh/config 中配置 Host * ControlMaster auto ControlPath ~/.ssh/sockets/%r@%h-%p ControlPersist 600 # 創(chuàng)建socket目錄 mkdir -p ~/.ssh/sockets chmod 700 ~/.ssh/sockets
關(guān)閉DNS反向解析和GSSAPI:sshd默認(rèn)會(huì)對(duì)客戶端IP做DNS反向解析,如果DNS服務(wù)器響應(yīng)慢或不可達(dá),每次連接會(huì)卡5-30秒。GSSAPI認(rèn)證同理,不用Kerberos就關(guān)掉。
# 服務(wù)端 /etc/ssh/sshd_config UseDNS no GSSAPIAuthentication no # 客戶端 ~/.ssh/config(雙向都關(guān)) Host * GSSAPIAuthentication no
啟用壓縮傳輸:在帶寬有限的網(wǎng)絡(luò)環(huán)境下(比如跨地域機(jī)房),開(kāi)啟壓縮可以減少傳輸數(shù)據(jù)量。實(shí)測(cè)傳輸日志文件(文本類數(shù)據(jù)壓縮率高)速度提升40-60%。但在局域網(wǎng)高帶寬環(huán)境下,壓縮反而增加CPU開(kāi)銷,建議關(guān)閉。
# 低帶寬環(huán)境開(kāi)啟 Host slow-network-* Compression yes # 局域網(wǎng)環(huán)境關(guān)閉 Host lan-* Compression no
4.1.2 安全加固
限制SSH訪問(wèn)來(lái)源IP:即使改了端口、禁了密碼,也建議在防火墻層面限制只允許特定IP段訪問(wèn)SSH端口。縱深防御,多一層保護(hù)。
# firewalld:只允許辦公網(wǎng)絡(luò)和跳板機(jī)IP訪問(wèn)SSH sudo firewall-cmd --permanent --zone=public --remove-service=ssh sudo firewall-cmd --permanent --new-zone=ssh-restricted 2>/dev/null ||true sudo firewall-cmd --permanent --zone=ssh-restricted --add-source=172.16.0.0/16 sudo firewall-cmd --permanent --zone=ssh-restricted --add-source=203.0.113.10/32 sudo firewall-cmd --permanent --zone=ssh-restricted --add-port=52222/tcp sudo firewall-cmd --reload # iptables方式 sudo iptables -A INPUT -p tcp --dport 52222 -s 172.16.0.0/16 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 52222 -s 203.0.113.10/32 -j ACCEPT sudo iptables -A INPUT -p tcp --dport 52222 -j DROP sudo service iptables save
定期審計(jì)SSH登錄日志:每周檢查一次異常登錄記錄,關(guān)注非工作時(shí)間登錄、陌生IP登錄、頻繁失敗嘗試。
# 查看成功登錄記錄
grep"Accepted"/var/log/secure | awk'{print $1,$2,$3,$9,$11}'| sort | uniq -c | sort -rn | head -20
# 查看失敗登錄統(tǒng)計(jì)(按IP排序)
grep"Failed password"/var/log/secure | awk'{print $(NF-3)}'| sort | uniq -c | sort -rn | head -20
# 查看非工作時(shí)間(2200)的登錄
grep"Accepted"/var/log/secure | awk'{split($3,t,":"); if(t[1]>=22 || t[1]<8) print}'
SSH密鑰指紋驗(yàn)證:首次連接新服務(wù)器時(shí),SSH會(huì)提示確認(rèn)主機(jī)指紋。生產(chǎn)環(huán)境不要無(wú)腦yes,應(yīng)該提前通過(guò)安全渠道獲取服務(wù)器指紋并核對(duì)。
# 在服務(wù)器上查看主機(jī)密鑰指紋 ssh-keygen -lf /etc/ssh/ssh_host_ed25519_key.pub # 客戶端連接時(shí)核對(duì)指紋 # The authenticity of host '192.168.1.100 (192.168.1.100)' can't be established. # ED25519 key fingerprint is SHA256:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx. # 核對(duì)一致后輸入yes
禁用弱加密算法:默認(rèn)配置包含一些老舊的加密算法(如arcfour、3des-cbc),存在已知漏洞。只保留安全的算法。
# /etc/ssh/sshd_config KexAlgorithms curve25519-sha256,curve25519-sha256@libssh.org,diffie-hellman-group16-sha512,diffie-hellman-group18-sha512 Ciphers chacha20-poly1305@openssh.com,aes256-gcm@openssh.com,aes128-gcm@openssh.com,aes256-ctr,aes192-ctr,aes128-ctr MACs hmac-sha2-512-etm@openssh.com,hmac-sha2-256-etm@openssh.com,umac-128-etm@openssh.com # 驗(yàn)證當(dāng)前使用的算法 ssh -vv -p 52222 opsadmin@192.168.1.100 2>&1 | grep"kex:"
4.1.3 高可用配置
跳板機(jī)高可用:跳板機(jī)是單點(diǎn),掛了所有人都連不上內(nèi)網(wǎng)服務(wù)器。生產(chǎn)環(huán)境至少部署兩臺(tái)跳板機(jī),用DNS輪詢或keepalived做VIP漂移。
# SSH Config中配置備用跳板機(jī) Host jump HostName jump-vip.company.com Port 52222 User opsadmin IdentityFile ~/.ssh/id_ed25519 # 連接超時(shí)后自動(dòng)嘗試備用 ConnectTimeout 5 # 或者用Match塊配置fallback # 主跳板機(jī) Host jump-primary HostName 203.0.113.10 Port 52222 # 備用跳板機(jī) Host jump-backup HostName 203.0.113.11 Port 52222
SSH服務(wù)端口探活:用監(jiān)控系統(tǒng)定期檢測(cè)SSH端口是否可達(dá),sshd進(jìn)程是否存活。
# 簡(jiǎn)單的SSH端口探活腳本 nc -z -w 3 192.168.1.100 52222 &&echo"SSH OK"||echo"SSH DOWN" # 或者用ssh命令探活(更準(zhǔn)確,驗(yàn)證到協(xié)議層) ssh -o ConnectTimeout=3 -o BatchMode=yes -p 52222 opsadmin@192.168.1.100"echo ok"2>/dev/null
備份策略:SSH配置文件和密鑰是關(guān)鍵資產(chǎn),必須納入備份。
/etc/ssh/sshd_config和/etc/ssh/ssh_host_*主機(jī)密鑰:納入系統(tǒng)配置備份
用戶~(yú)/.ssh/目錄:納入用戶數(shù)據(jù)備份
CA密鑰(如果用證書(shū)認(rèn)證):離線備份,存放在保險(xiǎn)柜級(jí)別的安全位置
4.2 注意事項(xiàng)
4.2.1 配置注意事項(xiàng)
改SSH配置前必須保持一個(gè)活躍會(huì)話不斷開(kāi)。這是鐵律,違反一次就可能要跑機(jī)房。我親眼見(jiàn)過(guò)同事改錯(cuò)sshd_config后restart,所有SSH連接斷開(kāi),最后開(kāi)車去機(jī)房用顯示器鍵盤恢復(fù)的。
修改sshd_config后先用sshd -t檢查語(yǔ)法,再reload而不是restart
改端口時(shí)先在防火墻放行新端口,再改配置重啟,順序不能反
禁用密碼認(rèn)證前,必須確認(rèn)密鑰登錄已經(jīng)配好并測(cè)試通過(guò)
AllowUsers和AllowGroups是白名單,配了之后不在名單里的用戶全部被拒絕,包括root
Match塊必須放在sshd_config文件末尾,Match塊之后的配置都屬于這個(gè)Match塊的作用域
4.2.2 常見(jiàn)錯(cuò)誤
| 錯(cuò)誤現(xiàn)象 | 原因分析 | 解決方案 |
|---|---|---|
| Permission denied (publickey) | 公鑰未添加到authorized_keys,或文件權(quán)限不對(duì) | 檢查~/.ssh/目錄700、authorized_keys文件600、家目錄不超過(guò)755 |
| Connection refused | sshd未啟動(dòng)或端口不對(duì) | systemctl status sshd 檢查服務(wù)狀態(tài),ss -tlnp檢查端口 |
| Connection timed out | 防火墻未放行端口或網(wǎng)絡(luò)不通 | telnet IP PORT 測(cè)試端口連通性,檢查firewalld/iptables規(guī)則 |
| Too many authentication failures | 客戶端嘗試了太多密鑰,超過(guò)MaxAuthTries | 在~/.ssh/config中加IdentitiesOnly yes指定密鑰 |
| SSH連接后卡住5-10秒 | DNS反向解析超時(shí)或GSSAPI認(rèn)證超時(shí) | 服務(wù)端設(shè)UseDNS no,客戶端設(shè)GSSAPIAuthentication no |
| Host key verification failed | 服務(wù)器重裝后主機(jī)密鑰變了 | ssh-keygen -R 主機(jī)IP 刪除舊指紋,重新確認(rèn) |
| Bad owner or modes | .ssh目錄或文件權(quán)限過(guò)大 | chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys |
4.2.3 兼容性問(wèn)題
版本兼容:ed25519密鑰需要OpenSSH 6.5+,ProxyJump指令需要7.3+,Include指令需要7.3+。CentOS 6自帶的OpenSSH 5.3不支持這些特性,需要升級(jí)或用ProxyCommand替代ProxyJump。
# CentOS 6上用ProxyCommand替代ProxyJump Host internal-server HostName 10.0.1.11 ProxyCommand ssh -W %h:%p jump
平臺(tái)兼容:macOS自帶的OpenSSH版本通常較新(Ventura自帶8.6),但ssh-copy-id需要額外安裝(brew install ssh-copy-id)。Windows 10/11自帶OpenSSH客戶端,但版本可能較舊,建議用Git Bash或WSL。
組件依賴:fail2ban在CentOS 7上依賴EPEL源;CentOS 8/9的fail2ban需要python3-systemd包;Ubuntu直接apt安裝即可。semanage命令需要安裝policycoreutils-python-utils包。
五、故障排查和監(jiān)控
5.1 故障排查
5.1.1 日志查看
# CentOS/RHEL 查看SSH認(rèn)證日志 sudo tail -f /var/log/secure # Ubuntu/Debian 查看SSH認(rèn)證日志 sudo tail -f /var/log/auth.log # 用journalctl查看sshd日志(systemd系統(tǒng)通用) sudo journalctl -u sshd -f # 只看最近1小時(shí)的SSH日志 sudo journalctl -u sshd --since"1 hour ago" # 過(guò)濾失敗登錄 sudo journalctl -u sshd | grep -i"failed|error|denied" # 查看fail2ban日志 sudo tail -f /var/log/fail2ban.log
日志級(jí)別調(diào)整:排查問(wèn)題時(shí)臨時(shí)調(diào)高日志級(jí)別,排查完改回來(lái)。
# /etc/ssh/sshd_config # 正常運(yùn)行用VERBOSE,排查問(wèn)題臨時(shí)改為DEBUG3 LogLevel VERBOSE # LogLevel DEBUG3 # 改完reload sudo systemctl reload sshd
DEBUG3級(jí)別會(huì)記錄每一步認(rèn)證細(xì)節(jié),包括嘗試了哪些密鑰、為什么拒絕等。日志量很大,排查完務(wù)必改回VERBOSE,否則磁盤會(huì)被撐滿。
5.1.2 常見(jiàn)問(wèn)題排查
問(wèn)題一:Permission denied (publickey) —— 密鑰認(rèn)證失敗
這是最常見(jiàn)的SSH問(wèn)題,原因有很多種,按排查優(yōu)先級(jí)列出:
# 1. 客戶端用verbose模式連接,看具體卡在哪一步 ssh -vvv -p 52222 -i ~/.ssh/id_ed25519 opsadmin@192.168.1.100 # 關(guān)注這些關(guān)鍵行: # "Offering public key: /home/user/.ssh/id_ed25519 ED25519" -> 客戶端發(fā)送了密鑰 # "Server accepts key: /home/user/.ssh/id_ed25519 ED25519" -> 服務(wù)端接受了密鑰 # "Authentication succeeded (publickey)" -> 認(rèn)證成功 # 如果看到 "No more authentication methods to try" 說(shuō)明服務(wù)端拒絕了所有密鑰
# 2. 檢查服務(wù)端權(quán)限(最常見(jiàn)的原因) ls -la ~/ # 家目錄權(quán)限不能大于755,如果是777就會(huì)被拒絕 ls -la ~/.ssh/ # .ssh目錄必須是700 ls -la ~/.ssh/authorized_keys # authorized_keys必須是600 # 修復(fù)權(quán)限 chmod 755 ~ chmod 700 ~/.ssh chmod 600 ~/.ssh/authorized_keys # 3. 檢查authorized_keys內(nèi)容 cat ~/.ssh/authorized_keys # 確認(rèn)公鑰完整,沒(méi)有換行符截?cái)?# 每個(gè)公鑰必須是一行,不能有折行 # 4. 檢查文件屬主 ls -la ~/.ssh/authorized_keys # owner必須是當(dāng)前用戶,不能是root chown $(whoami):$(whoami) ~/.ssh/authorized_keys # 5. 檢查SELinux上下文(CentOS/RHEL) ls -Z ~/.ssh/authorized_keys # 應(yīng)該是 unconfined_ussh_home_t:s0 # 如果不對(duì),恢復(fù)上下文: restorecon -Rv ~/.ssh/
問(wèn)題二:SSH連接慢,登錄要等5-30秒
# 原因1:DNS反向解析(最常見(jiàn)) # 服務(wù)端對(duì)客戶端IP做反向DNS查詢,DNS服務(wù)器不可達(dá)時(shí)會(huì)等到超時(shí) # 解決: sudo grep"UseDNS"/etc/ssh/sshd_config # 如果是yes或者沒(méi)配(默認(rèn)yes),改為no # UseDNS no # 原因2:GSSAPI認(rèn)證超時(shí) # 客戶端嘗試GSSAPI認(rèn)證,沒(méi)有Kerberos環(huán)境時(shí)會(huì)超時(shí) # 解決(客戶端): ssh -o GSSAPIAuthentication=no -p 52222 opsadmin@192.168.1.100 # 或者在~/.ssh/config中全局關(guān)閉 # Host * # GSSAPIAuthentication no # 原因3:systemd-logind響應(yīng)慢 # CentOS 7上偶發(fā),dbus通信超時(shí) # 診斷: sudo journalctl -u systemd-logind --since"10 minutes ago" # 解決: sudo systemctl restart systemd-logind # 用time命令量化連接耗時(shí) time ssh -p 52222 opsadmin@192.168.1.100"exit" # 正常應(yīng)該在1秒以內(nèi)
問(wèn)題三:Connection refused —— 連接被拒絕
# 1. 檢查sshd是否在運(yùn)行 sudo systemctl status sshd # 如果是dead/failed狀態(tài),查看原因 sudo journalctl -u sshd --no-pager | tail -30 # 2. 檢查監(jiān)聽(tīng)端口 ss -tlnp | grep sshd # 確認(rèn)sshd在監(jiān)聽(tīng)正確的端口 # 3. 檢查配置文件語(yǔ)法 sudo sshd -t # 如果有語(yǔ)法錯(cuò)誤,sshd可能啟動(dòng)失敗 # 4. 檢查防火墻 sudo firewall-cmd --list-all # 或 sudo iptables -L -n | grep 52222 # 5. 檢查SELinux是否阻止了非標(biāo)準(zhǔn)端口 sudo semanage port -l | grep ssh # 如果新端口不在列表里: sudo semanage port -a -t ssh_port_t -p tcp 52222 # 6. 檢查TCP Wrappers(/etc/hosts.allow 和 /etc/hosts.deny) cat /etc/hosts.deny # 如果有 sshd: ALL 會(huì)拒絕所有SSH連接
問(wèn)題四:fail2ban誤封了合法IP
# 查看當(dāng)前被封禁的IP列表 sudo fail2ban-client status sshd # 解封特定IP sudo fail2ban-clientsetsshd unbanip 172.16.1.50 # 查看封禁原因(在fail2ban日志中搜索) sudo grep"172.16.1.50"/var/log/fail2ban.log # 將合法IP加入白名單(永久生效) # 編輯 /etc/fail2ban/jail.local # ignoreip = 127.0.0.1/8 10.0.0.0/8 172.16.0.0/16 # 重啟fail2ban使白名單生效 sudo systemctl restart fail2ban
5.1.3 調(diào)試模式
# 在前臺(tái)以調(diào)試模式啟動(dòng)sshd(不影響正在運(yùn)行的sshd) # 監(jiān)聽(tīng)在不同端口避免沖突 sudo /usr/sbin/sshd -d -p 52223 # 客戶端連接調(diào)試端口 ssh -vvv -p 52223 opsadmin@192.168.1.100 # 兩邊的輸出對(duì)照看,能精確定位認(rèn)證失敗的原因 # 檢查sshd加載的完整配置(排查配置覆蓋問(wèn)題) sudo sshd -T # 檢查特定用戶從特定IP連接時(shí)的有效配置(Match塊生效情況) sudo sshd -T -C user=deployer,host=10.0.0.50,addr=10.0.0.50
5.2 性能監(jiān)控
5.2.1 關(guān)鍵指標(biāo)監(jiān)控
# SSH連接數(shù)監(jiān)控
ss -tnp | grep":52222"| wc -l
# 當(dāng)前活躍SSH會(huì)話數(shù)
who | wc -l
# sshd進(jìn)程資源占用
ps aux | grep sshd | grep -v grep
# SSH認(rèn)證失敗頻率(最近1小時(shí))
sudo journalctl -u sshd --since"1 hour ago"| grep -c"Failed"
# fail2ban封禁統(tǒng)計(jì)
sudo fail2ban-client status sshd | grep"Currently banned"
# SSH端口連接狀態(tài)分布
ss -tn | grep":52222"| awk'{print $1}'| sort | uniq -c
5.2.2 監(jiān)控指標(biāo)說(shuō)明
| 指標(biāo)名稱 | 正常范圍 | 告警閾值 | 說(shuō)明 |
|---|---|---|---|
| SSH活躍連接數(shù) | 0-50 | >100 | 超過(guò)100可能是暴力破解或連接泄漏 |
| 認(rèn)證失敗次數(shù)/小時(shí) | 0-10 | >50 | 大量失敗說(shuō)明有暴力破解行為 |
| fail2ban封禁IP數(shù) | 0-5 | >20 | 大量封禁說(shuō)明正在遭受攻擊 |
| SSH連接延遲 | <1s | >5s | 延遲高需要排查DNS/GSSAPI/網(wǎng)絡(luò)問(wèn)題 |
| sshd進(jìn)程CPU使用率 | <5% | >30% | CPU高可能是密鑰交換風(fēng)暴或DDoS |
| sshd進(jìn)程內(nèi)存使用 | <50MB | >200MB | 內(nèi)存異常增長(zhǎng)需要排查連接泄漏 |
5.2.3 Prometheus監(jiān)控規(guī)則
# prometheus_ssh_rules.yml
# 文件路徑:/etc/prometheus/rules/ssh_rules.yml
groups:
-name:ssh_security
interval:30s
rules:
# SSH認(rèn)證失敗率告警
-alert:SSHAuthFailureHigh
expr:rate(ssh_auth_failures_total[5m])>10
for:5m
labels:
severity:warning
annotations:
summary:"SSH認(rèn)證失敗率過(guò)高 ({{ $labels.instance }})"
description:"5分鐘內(nèi)SSH認(rèn)證失敗率超過(guò)10次/秒,可能遭受暴力破解"
# SSH活躍連接數(shù)告警
-alert:SSHConnectionsHigh
expr:ssh_active_connections>100
for:2m
labels:
severity:warning
annotations:
summary:"SSH連接數(shù)過(guò)高 ({{ $labels.instance }})"
description:"SSH活躍連接數(shù){{ $value }},超過(guò)閾值100"
# fail2ban封禁數(shù)告警
-alert:Fail2banBannedIPsHigh
expr:fail2ban_banned_ips{jail="sshd"}>20
for:5m
labels:
severity:critical
annotations:
summary:"fail2ban封禁IP數(shù)過(guò)多 ({{ $labels.instance }})"
description:"SSH jail當(dāng)前封禁{{ $value }}個(gè)IP,可能正在遭受大規(guī)模攻擊"
# sshd進(jìn)程存活檢測(cè)
-alert:SSHDProcessDown
expr:node_systemd_unit_state{name="sshd.service",state="active"}!=1
for:1m
labels:
severity:critical
annotations:
summary:"sshd服務(wù)異常 ({{ $labels.instance }})"
description:"sshd服務(wù)未在運(yùn)行狀態(tài),遠(yuǎn)程管理通道中斷"
配合node_exporter的textfile collector采集SSH指標(biāo):
#!/bin/bash
# 文件名:ssh_metrics.sh
# 功能:采集SSH相關(guān)指標(biāo),輸出為Prometheus格式
# 配合crontab每分鐘執(zhí)行:* * * * * /opt/scripts/ssh_metrics.sh
METRICS_DIR="/var/lib/node_exporter/textfile_collector"
METRICS_FILE="$METRICS_DIR/ssh_metrics.prom"
mkdir -p"$METRICS_DIR"
# 活躍SSH連接數(shù)
ACTIVE_CONN=$(ss -tnp | grep -c":52222"2>/dev/null ||echo0)
# 當(dāng)前登錄用戶數(shù)
LOGGED_USERS=$(who | wc -l)
# 最近5分鐘認(rèn)證失敗次數(shù)
FAIL_COUNT=$(sudo journalctl -u sshd --since"5 minutes ago"2>/dev/null | grep -c"Failed"||echo0)
# fail2ban封禁IP數(shù)
BANNED_IPS=$(sudo fail2ban-client status sshd 2>/dev/null | grep"Currently banned"| awk'{print $NF}'||echo0)
cat >"$METRICS_FILE.tmp"<< EOF
# HELP ssh_active_connections Current number of SSH connections
# TYPE ssh_active_connections gauge
ssh_active_connections?$ACTIVE_CONN
# HELP ssh_logged_users Current number of logged in users
# TYPE ssh_logged_users gauge
ssh_logged_users?$LOGGED_USERS
# HELP ssh_auth_failures_5m SSH authentication failures in last 5 minutes
# TYPE ssh_auth_failures_5m gauge
ssh_auth_failures_5m?$FAIL_COUNT
# HELP fail2ban_banned_ips Number of IPs banned by fail2ban
# TYPE fail2ban_banned_ips gauge
fail2ban_banned_ips{jail="sshd"}?$BANNED_IPS
EOF
mv?"$METRICS_FILE.tmp""$METRICS_FILE"
5.3 備份與恢復(fù)
5.3.1 備份策略
#!/bin/bash # 文件名:backup_ssh_config.sh # 功能:備份SSH服務(wù)端和客戶端配置 # 建議每周執(zhí)行一次,保留最近12周的備份 BACKUP_BASE="/data/backup/ssh" DATE=$(date +%Y%m%d_%H%M%S) BACKUP_DIR="$BACKUP_BASE/$DATE" KEEP_WEEKS=12 mkdir -p"$BACKUP_DIR" # 備份服務(wù)端配置 sudo cp -a /etc/ssh/sshd_config"$BACKUP_DIR/" sudo cp -a /etc/ssh/ssh_config"$BACKUP_DIR/"2>/dev/null sudo cp -a /etc/ssh/banner.txt"$BACKUP_DIR/"2>/dev/null # 備份主機(jī)密鑰(恢復(fù)時(shí)需要,否則所有客戶端會(huì)報(bào)host key changed) sudo cp -a /etc/ssh/ssh_host_*"$BACKUP_DIR/" # 備份fail2ban配置 sudo cp -a /etc/fail2ban/jail.local"$BACKUP_DIR/"2>/dev/null # 備份CA密鑰(如果有) sudo cp -a /etc/ssh/ca_user_key*"$BACKUP_DIR/"2>/dev/null sudo cp -a /etc/ssh/revoked_keys"$BACKUP_DIR/"2>/dev/null # 設(shè)置備份文件權(quán)限 sudo chmod 600"$BACKUP_DIR"/ssh_host_* sudo chmod 600"$BACKUP_DIR"/ca_user_key 2>/dev/null # 清理過(guò)期備份 find"$BACKUP_BASE"-maxdepth 1 -typed -mtime +$((KEEP_WEEKS * 7)) -execrm -rf {} ; echo"SSH配置備份完成:$BACKUP_DIR" ls -la"$BACKUP_DIR/"
5.3.2 恢復(fù)流程
停止服務(wù)(如果sshd還在運(yùn)行):
# 不要直接stop,先確認(rèn)有其他方式訪問(wèn)服務(wù)器(VNC/IPMI/控制臺(tái)) sudo systemctl stop sshd
恢復(fù)配置文件:
# 找到最近的備份 ls -lt /data/backup/ssh/ | head -5 # 恢復(fù)配置 RESTORE_DIR="/data/backup/ssh/20250115_020000" sudo cp"$RESTORE_DIR/sshd_config"/etc/ssh/sshd_config sudo cp"$RESTORE_DIR"/ssh_host_* /etc/ssh/ # 恢復(fù)權(quán)限 sudo chmod 600 /etc/ssh/ssh_host_*_key sudo chmod 644 /etc/ssh/ssh_host_*_key.pub sudo chmod 644 /etc/ssh/sshd_config
驗(yàn)證配置:
sudo sshd -t
重啟服務(wù):
sudo systemctl start sshd sudo systemctl status sshd ss -tlnp | grep sshd
六、總結(jié)
6.1 技術(shù)要點(diǎn)回顧
端口+認(rèn)證雙重加固:改默認(rèn)端口過(guò)濾自動(dòng)化掃描,禁密碼認(rèn)證杜絕暴力破解。實(shí)測(cè)改端口后掃描日志從每天數(shù)萬(wàn)條降到個(gè)位數(shù),禁密碼后暴力破解徹底歸零。
ed25519是當(dāng)前最優(yōu)密鑰算法:比RSA-4096更安全、密鑰更短(68字節(jié) vs 800+字節(jié))、簽名驗(yàn)證更快(約30%)。除非目標(biāo)系統(tǒng)OpenSSH低于6.5,否則一律用ed25519。
fail2ban是必備防護(hù)組件:配合MaxAuthTries形成兩層防線——MaxAuthTries限制單次連接嘗試次數(shù),fail2ban在多次連接失敗后封禁IP。兩者配合效果遠(yuǎn)大于單獨(dú)使用。
SSH Config + ProxyJump實(shí)現(xiàn)高效多主機(jī)管理:用別名替代IP+端口,用ProxyJump實(shí)現(xiàn)透明跳轉(zhuǎn),用ControlMaster實(shí)現(xiàn)連接復(fù)用。管理200+臺(tái)服務(wù)器和管理2臺(tái)一樣方便。
證書(shū)認(rèn)證是大規(guī)模環(huán)境的終極方案:超過(guò)50臺(tái)服務(wù)器時(shí),逐臺(tái)維護(hù)authorized_keys不現(xiàn)實(shí)。CA簽發(fā)證書(shū)后服務(wù)端只需信任CA公鑰,人員變動(dòng)只需吊銷證書(shū),不用逐臺(tái)操作。
配置變更必須有回滾方案:改SSH配置前備份、保持活躍會(huì)話、先放行新端口再改配置、用sshd -t檢查語(yǔ)法。這些流程每一步都不能省。
6.2 進(jìn)階學(xué)習(xí)方向
SSH證書(shū)認(rèn)證與HashiCorp Vault集成
Vault可以作為SSH CA,動(dòng)態(tài)簽發(fā)短期證書(shū)(比如有效期8小時(shí)),實(shí)現(xiàn)"用完即廢"的零信任模式
學(xué)習(xí)資源:HashiCorp Vault官方文檔 SSH Secrets Engine章節(jié)
實(shí)踐建議:先在測(cè)試環(huán)境搭建Vault,配置SSH Secrets Engine,體驗(yàn)動(dòng)態(tài)證書(shū)簽發(fā)流程
基于FIDO2/U2F硬件密鑰的SSH認(rèn)證
OpenSSH 8.2+支持FIDO2安全密鑰(如YubiKey),私鑰存儲(chǔ)在硬件中無(wú)法導(dǎo)出,比軟件密鑰更安全
學(xué)習(xí)資源:OpenSSH 8.2 Release Notes,Yubico官方SSH配置指南
實(shí)踐建議:購(gòu)買一個(gè)YubiKey 5系列,配置ssh-keygen -t ed25519-sk生成硬件綁定密鑰
Teleport/Boundary等零信任SSH網(wǎng)關(guān)
替代傳統(tǒng)跳板機(jī),提供會(huì)話錄制、RBAC權(quán)限控制、審計(jì)日志、MFA集成等企業(yè)級(jí)功能
學(xué)習(xí)資源:Teleport官方文檔,Gravitational GitHub倉(cāng)庫(kù)
實(shí)踐建議:用Docker快速部署Teleport試用版,體驗(yàn)Web Terminal和會(huì)話回放功能
6.3 參考資料
OpenSSH官方文檔- sshd_config所有參數(shù)的權(quán)威說(shuō)明
Mozilla SSH安全指南- Mozilla內(nèi)部SSH加固標(biāo)準(zhǔn),推薦的加密算法列表
fail2ban官方Wiki- fail2ban配置詳解和自定義filter編寫(xiě)
SSH Mastery (Michael W Lucas)- SSH進(jìn)階書(shū)籍,覆蓋證書(shū)認(rèn)證、端口轉(zhuǎn)發(fā)等高級(jí)主題
CIS Benchmark for Linux- CIS安全基線中SSH加固章節(jié)
附錄
A. 命令速查表
# ===== 密鑰管理 ===== ssh-keygen -t ed25519 -C"comment" # 生成ed25519密鑰 ssh-keygen -t rsa -b 4096 -C"comment" # 生成RSA-4096密鑰 ssh-keygen -lf ~/.ssh/id_ed25519.pub # 查看密鑰指紋 ssh-keygen -R 192.168.1.100 # 刪除known_hosts中的主機(jī)記錄 ssh-copy-id -i ~/.ssh/id_ed25519.pub -p 52222 user@host # 分發(fā)公鑰 # ===== 連接和調(diào)試 ===== ssh -p 52222 user@host # 指定端口連接 ssh -vvv user@host # 詳細(xì)調(diào)試模式 ssh -J jump user@internal-host # 通過(guò)跳板機(jī)連接 ssh -L 33073306 user@jump # 本地端口轉(zhuǎn)發(fā) ssh -D 1080 user@host # SOCKS代理 # ===== 服務(wù)管理 ===== sudo sshd -t # 檢查配置語(yǔ)法 sudo sshd -T # 顯示完整有效配置 sudo systemctl reload sshd # 重載配置(不斷連接) sudo systemctl restart sshd # 重啟服務(wù)(斷開(kāi)所有連接) # ===== fail2ban ===== sudo fail2ban-client status sshd # 查看SSH jail狀態(tài) sudo fail2ban-clientsetsshd unbanip 1.2.3.4 # 解封IP sudo fail2ban-clientsetsshd banip 1.2.3.4 # 封禁IP # ===== 證書(shū)認(rèn)證 ===== ssh-keygen -s ca_key -I cert_id -n user -V +52w user.pub # 簽發(fā)證書(shū) ssh-keygen -L -f cert.pub # 查看證書(shū)信息 # ===== 權(quán)限設(shè)置 ===== chmod 700 ~/.ssh # .ssh目錄權(quán)限 chmod 600 ~/.ssh/authorized_keys # authorized_keys權(quán)限 chmod 600 ~/.ssh/id_ed25519 # 私鑰權(quán)限 chmod 644 ~/.ssh/id_ed25519.pub # 公鑰權(quán)限 chmod 755 ~ # 家目錄權(quán)限上限
B. 配置參數(shù)詳解
sshd_config 關(guān)鍵參數(shù)速查:
| 參數(shù) | 默認(rèn)值 | 推薦值 | 說(shuō)明 |
|---|---|---|---|
| Port | 22 | 52222 | SSH監(jiān)聽(tīng)端口 |
| PermitRootLogin | yes | no | 是否允許root登錄 |
| PasswordAuthentication | yes | no | 是否允許密碼認(rèn)證 |
| PubkeyAuthentication | yes | yes | 是否允許公鑰認(rèn)證 |
| MaxAuthTries | 6 | 3 | 單次連接最大認(rèn)證嘗試次數(shù) |
| LoginGraceTime | 120 | 30 | 認(rèn)證超時(shí)時(shí)間(秒) |
| MaxSessions | 10 | 5 | 單連接最大會(huì)話數(shù) |
| MaxStartups | 10100 | 1060 | 未認(rèn)證連接限制 |
| ClientAliveInterval | 0 | 300 | 心跳探測(cè)間隔(秒) |
| ClientAliveCountMax | 3 | 3 | 心跳失敗斷開(kāi)閾值 |
| UseDNS | yes | no | 是否做DNS反向解析 |
| GSSAPIAuthentication | yes | no | 是否啟用GSSAPI認(rèn)證 |
| X11Forwarding | yes | no | 是否允許X11轉(zhuǎn)發(fā) |
| AllowAgentForwarding | yes | no | 是否允許Agent轉(zhuǎn)發(fā) |
| LogLevel | INFO | VERBOSE | 日志級(jí)別 |
| Banner | none | /etc/ssh/banner.txt | 登錄前顯示的警告信息 |
| StrictModes | yes | yes | 是否檢查文件權(quán)限 |
客戶端 ~/.ssh/config 常用參數(shù):
| 參數(shù) | 說(shuō)明 | 示例 |
|---|---|---|
| HostName | 實(shí)際主機(jī)地址 | 192.168.1.100 |
| Port | SSH端口 | 52222 |
| User | 登錄用戶名 | opsadmin |
| IdentityFile | 私鑰文件路徑 | ~/.ssh/id_ed25519 |
| IdentitiesOnly | 只用指定密鑰 | yes |
| ProxyJump | 跳板機(jī) | jump |
| ServerAliveInterval | 心跳間隔(秒) | 60 |
| ControlMaster | 連接復(fù)用 | auto |
| ControlPath | 復(fù)用socket路徑 | ~/.ssh/sockets/%r@%h-%p |
| ControlPersist | 復(fù)用保持時(shí)間(秒) | 600 |
| Compression | 壓縮傳輸 | yes |
| ForwardAgent | Agent轉(zhuǎn)發(fā) | no |
C. 術(shù)語(yǔ)表
| 術(shù)語(yǔ) | 英文 | 解釋 |
|---|---|---|
| 非對(duì)稱加密 | Asymmetric Encryption | 使用公鑰加密、私鑰解密的加密方式,SSH密鑰認(rèn)證的基礎(chǔ) |
| 公鑰 | Public Key | 可以公開(kāi)分發(fā)的密鑰,放在服務(wù)端的authorized_keys中 |
| 私鑰 | Private Key | 必須嚴(yán)格保密的密鑰,存放在客戶端,權(quán)限必須是600 |
| 密鑰指紋 | Key Fingerprint | 密鑰的哈希摘要,用于快速識(shí)別和驗(yàn)證密鑰身份 |
| CA | Certificate Authority | 證書(shū)頒發(fā)機(jī)構(gòu),SSH證書(shū)認(rèn)證中負(fù)責(zé)簽發(fā)和吊銷用戶證書(shū) |
| 跳板機(jī) | Jump Host / Bastion Host | 作為SSH中轉(zhuǎn)的服務(wù)器,內(nèi)網(wǎng)服務(wù)器只允許從跳板機(jī)訪問(wèn) |
| 端口轉(zhuǎn)發(fā) | Port Forwarding | 通過(guò)SSH隧道將本地端口映射到遠(yuǎn)程端口,或反向映射 |
| Agent轉(zhuǎn)發(fā) | Agent Forwarding | 將本地ssh-agent轉(zhuǎn)發(fā)到遠(yuǎn)程服務(wù)器,實(shí)現(xiàn)多跳免密 |
| 連接復(fù)用 | Connection Multiplexing | 多個(gè)SSH會(huì)話共用一個(gè)TCP連接,減少握手開(kāi)銷 |
| fail2ban | fail2ban | 入侵防御工具,監(jiān)控日志并自動(dòng)封禁惡意IP |
| GSSAPI | Generic Security Services API | 通用安全服務(wù)接口,用于Kerberos認(rèn)證集成 |
| SELinux | Security-Enhanced Linux | 安全增強(qiáng)Linux,強(qiáng)制訪問(wèn)控制機(jī)制,影響SSH端口和文件訪問(wèn) |
-
服務(wù)器
+關(guān)注
關(guān)注
14文章
10299瀏覽量
91588 -
SSH
+關(guān)注
關(guān)注
0文章
200瀏覽量
17761
原文標(biāo)題:SSH安全加固與免密登錄:企業(yè)級(jí)SSH管理方案
文章出處:【微信號(hào):magedu-Linux,微信公眾號(hào):馬哥Linux運(yùn)維】歡迎添加關(guān)注!文章轉(zhuǎn)載請(qǐng)注明出處。
發(fā)布評(píng)論請(qǐng)先 登錄
對(duì)目前流行的ssh密碼暴力破解工具進(jìn)行實(shí)戰(zhàn)研究、分析和總結(jié)
Linux上建立SSH安全連接的10種方法
虹科干貨 | 工業(yè)樹(shù)莓派開(kāi)發(fā)工具指南之SSH登錄工具篇
虹科干貨 | 工業(yè)樹(shù)莓派開(kāi)發(fā)工具指南之SSH登錄工具篇
SSH端口號(hào)是什么?SSH是如何工作的?
Ubuntu修改SSH默認(rèn)端口指南
NAS教程:鐵威馬如何登錄 SSH終端?
交換機(jī)如何配置SSH遠(yuǎn)程登錄
禁止使用root用戶通過(guò)ssh遠(yuǎn)程登錄Linux
rsync 的免密傳輸(同步)文件
信息安全管理必備!Linux系統(tǒng)使用SSH登錄root賬號(hào)的方法
SSH遠(yuǎn)程登錄與控制教程
SSH安全加固與免密登錄實(shí)戰(zhàn)指南
評(píng)論