# 在 Windows PowerShell 端建立 SSH 公鑰認證,免密碼登入 Ubuntu Server - 伺服器:Ubuntu Server(固定 IP,例如 `192.168.X.XXX`) - 用戶端:Windows 10/11(以 PowerShell 操作) - 目標:使用公鑰認證(public key authentication)免密碼登入,並關閉密碼登入 ## 前置條件 - Windows 需已安裝 OpenSSH Client(預設已內建,可在 PowerShell 執行 ssh -V 確認) - Ubuntu 可連上 22/TCP(若有 UFW/防火牆,先允許:sudo ufw allow OpenSSH) ## 流程總覽 ```mermaid sequenceDiagram actor Win as Windows PowerShell participant U as Ubuntu Server Win->>U: 1) 使用密碼 ssh 你的userName@192.168.X.XXX 初次登入 U-->>Win: 要求密碼並允許登入 Win->>U: 2) 安裝 openssh-server(若未安裝) U-->>Win: sshd 服務啟動 Win->>Win: 4) 產生本機 SSH 金鑰 (ed25519) Win->>U: 5) 傳送公鑰到 ~/.ssh/authorized_keys Win->>U: 7) 設定 sshd 僅允許金鑰、禁止 root 密碼 U-->>Win: 重新載入 sshd 設定 Win->>U: 6/8) 測試:金鑰可登入;密碼登入已被拒絕 ``` ## 詳細步驟 1) 先用密碼連線到 Ubuntu Server 在 PowerShell: ```powershell ssh 你的userName@192.168.X.XXX ``` 首次會提示是否信任指紋,輸入 yes,並輸入使用者密碼登入。 2) 安裝 OpenSSH Server(若已安裝可略過) 在 Ubuntu 端: ```bash sudo apt update sudo apt install -y openssh-server sudo systemctl enable --now ssh sudo systemctl status ssh --no-pager ``` 3) 備份 sshd_config 在 Ubuntu 端: ```bash sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%F_%H%M%S) ``` 4) 在 Windows PowerShell 產生 SSH 金鑰 在 PowerShell: ```powershell ssh-keygen -t ed25519 -a 100 -C "你的名稱@你的電腦" # 產生: # C:\Users\<你>\.ssh\id_ed25519 (私鑰 private key,請妥善保護) # C:\Users\<你>\.ssh\id_ed25519.pub (公鑰 public key,會放到伺服器) ``` 說明: - 註解(Comment)僅用於識別,例如 "alice@my-laptop" 或你的電子郵件。 5) 將公鑰傳到 Ubuntu 的 authorized_keys **方法 A:使用 scp(建議)** ```powershell $PUB="$env:USERPROFILE\.ssh\id_ed25519.pub" scp $PUB 你的userName@192.168.X.XXX:~/id_ed25519.pub.tmp ssh 你的userName@192.168.X.XXX "umask 077; mkdir -p ~/.ssh && chmod 700 ~/.ssh; touch ~/.ssh/authorized_keys && chmod 600 ~/.ssh/authorized_keys; cat ~/id_ed25519.pub.tmp >> ~/.ssh/authorized_keys; rm ~/id_ed25519.pub.tmp" ``` **方法 B:使用管線(處理 CRLF 問題)** ```powershell $PUB="$env:USERPROFILE\.ssh\id_ed25519.pub" type $PUB | ssh 你的userName@192.168.X.XXX "umask 077; mkdir -p ~/.ssh && touch ~/.ssh/authorized_keys && chmod 700 ~/.ssh && chmod 600 ~/.ssh/authorized_keys && tr -d '\r' >> ~/.ssh/authorized_keys" ``` 6) 測試「只用公鑰」能否登入 請先保持你目前的 SSH 連線不要關閉,再開新視窗測試: ```powershell ssh -o PreferredAuthentications=publickey -o PasswordAuthentication=no 你的userName@192.168.X.XXX ``` 若成功即代表金鑰配置無誤。 7) 設定安全的 SSH 連線(建議使用方法 1) **方法 1:建立優先權設定檔(推薦)** ```bash sudo tee /etc/ssh/sshd_config.d/99-custom.conf << EOF PubkeyAuthentication yes PasswordAuthentication no KbdInteractiveAuthentication no PermitRootLogin prohibit-password UsePAM yes AuthenticationMethods publickey EOF ``` **方法 2:編輯主設定檔** ```bash sudo vim /etc/ssh/sshd_config ``` 確認或加入以下設定: ``` PubkeyAuthentication yes PasswordAuthentication no KbdInteractiveAuthentication no PermitRootLogin prohibit-password UsePAM yes AuthenticationMethods publickey ``` 套用前先檢查語法並重新載入: ```bash sudo sshd -t sudo systemctl reload ssh ``` ## 驗證設定 **檢查 SSH 伺服器的實際運行設定:** ```bash sudo sshd -T | grep -Ei "(passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|authenticationmethods)" ``` **期望輸出應該是:** ``` pubkeyauthentication yes passwordauthentication no kbdinteractiveauthentication no authenticationmethods publickey ``` **若系統有 Match 區塊,使用更精確的檢查:** ```bash sudo sshd -T -C user=你的userName,host=$(hostname),addr=192.168.X.XXX | grep -Ei "(passwordauthentication|kbdinteractiveauthentication|pubkeyauthentication|authenticationmethods)" ``` 8) 驗證密碼登入已被禁用 - 金鑰登入仍應成功: ```powershell ssh 你的userName@192.168.X.XXX ``` - 強制用密碼嘗試,應被拒絕: ```powershell ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no 你的userName@192.168.X.XXX ``` 看到 Permission denied 即為正確。 完成後,就可以在 Windows PowerShell 以 SSH 公鑰認證安全、免密碼地登入 Ubuntu Server,並且伺服器端已禁止密碼登入,降低被暴力破解的風險。 ## 安全建議 1. **測試後再斷線**:在確認 SSH 金鑰登入正常運作之前,請保持至少一個 SSH 連線會話開啟。 2. **備份設定檔**: ```bash sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.backup ``` 3. **監控登入日誌**: ```bash sudo tail -f /var/log/auth.log ``` 4. **考慮使用額外的安全措施**: - 更改 SSH 預設埠號 - 設定防火牆規則 - 使用 fail2ban 防止暴力破解 - 限制允許登入的使用者: ```bash # 在 sshd 設定中加入 AllowUsers 你的userName # 或使用群組控制 AllowGroups sshusers ``` ## 常見問題:Cloud-init 設定覆蓋 ### 問題描述 在 Ubuntu Server 22.04 中,即使在 `/etc/ssh/sshd_config` 中設定了 `PasswordAuthentication no`,使用 `sudo sshd -T` 檢查時可能仍然顯示 `passwordauthentication yes`,導致密碼登入依然被允許。 ### 根本原因 現代 Ubuntu Server 預設包含 **Cloud-init** 系統,它會透過 `/etc/ssh/sshd_config.d/` 目錄中的設定檔覆蓋主要的 SSH 設定。 **SSH 設定檔的載入機制:** 1. OpenSSH 從上到下解析 `/etc/ssh/sshd_config` 2. 當遇到 `Include /etc/ssh/sshd_config.d/*.conf` 指令時,會在該位置展開所有 `.conf` 檔案(按字母順序) 3. 後出現的設定會覆蓋先前的設定 4. Ubuntu 22.04 預設在主設定檔開頭附近就有 Include 指令 ### 為什麼全新安裝的 Linux 會有 Cloud-init? 現代 Linux 發行版(特別是 Ubuntu Server)預設包含 cloud-init,原因如下: 1. **雲端優先設計**:Ubuntu Server 針對雲端部署優化,即使在本地安裝也包含雲端工具 2. **統一映像檔**:使用相同的 ISO 映像檔部署到不同環境(本地、AWS、Azure、GCP 等) 3. **自動化需求**:即使在本地環境,也可能需要自動化配置功能 #### Cloud-init 的主要功能 ``` 初始開機時自動執行: ├── 網路設定 (IP、DNS、路由) ├── 使用者帳號建立與 SSH 金鑰配置 ├── 套件安裝與更新 ├── 檔案系統掛載與調整 ├── SSH 服務設定 (包括認證方式) ├── 主機名稱設定 └── 執行自訂腳本 ``` ### 診斷步驟 **檢查是否存在 Include 設定和額外的設定檔:** ```bash # 檢查主設定檔中的 Include 指令 grep -n "Include" /etc/ssh/sshd_config # 列出額外的設定檔 ls -la /etc/ssh/sshd_config.d/ # 檢查 cloud-init 設定檔內容 cat /etc/ssh/sshd_config.d/50-cloud-init.conf ``` 典型的 `50-cloud-init.conf` 內容可能包含: ``` PasswordAuthentication yes ``` ### 解決方案 **方法 1:建立優先權更高的設定檔(推薦)** sshd_config.d 的設定套用順序是按照字母順序排列的,後面的設定會覆蓋前面的設定: ```bash sudo tee /etc/ssh/sshd_config.d/99-custom.conf << EOF PubkeyAuthentication yes PasswordAuthentication no KbdInteractiveAuthentication no PermitRootLogin prohibit-password AuthenticationMethods publickey EOF sudo sshd -t && sudo systemctl reload ssh ``` **方法 2:停用 Cloud-init SSH 設定檔** 如果是地端架設的 Ubuntu Server 且確定不需要 Cloud-init 的 SSH 管理: ```bash sudo mv /etc/ssh/sshd_config.d/50-cloud-init.conf /etc/ssh/sshd_config.d/50-cloud-init.conf.disabled sudo sshd -t && sudo systemctl reload ssh ``` ### 驗證修正結果 ```bash # 確認設定已正確套用 sudo sshd -T | grep -Ei "(passwordauthentication|authenticationmethods|pubkeyauthentication)" # 測試設定檔語法 sudo sshd -t # 測試密碼登入(應被立即拒絕,不會提示輸入密碼) ssh -o PreferredAuthentications=password -o PubkeyAuthentication=no username@localhost ``` ### 關於 PermitRootLogin 設定說明 - `PermitRootLogin no`:完全禁止 root 登入(包括金鑰登入) - `PermitRootLogin prohibit-password`:禁止 root 密碼登入,但允許金鑰登入 - `PermitRootLogin yes`:允許 root 以任何方式登入(不建議) ### 補述:關於 Cloud-init Cloud-init 是一個雲端環境初始化系統,用於在虛擬機器或容器啟動時自動執行配置。即使在本地安裝的 Ubuntu Server 也會包含此套件。 如果您的環境確定不需要 Cloud-init 功能,可以選擇: **完全移除 Cloud-init:** ```bash sudo apt remove --purge cloud-init sudo rm -rf /etc/cloud/ /var/lib/cloud/ ``` **或禁用 Cloud-init 的 SSH 模組:** ```bash sudo vim /etc/cloud/cloud.cfg # 在 cloud_config_modules 區段中註解掉: # - ssh ``` **注意**:移除 Cloud-init 會影響雲端化引導流程與部分自動化工具,建議在本機/裸機長期使用且確定無需雲端初始化時再執行。