﻿# 如何透過 ssh 連入 Multipass 建立的 Ubuntu VM 並啟用 Port forwarding

如果要從 Host 主機連入 Multipass 建立的 Ubuntu VM，其實只要執行 `multipass shell microk8s-vm` 就可以進入了，完全也不用輸入密碼。不過，透過 `multipass shell` 無法使用 Port forwarding (埠號轉送)，沒辦法把我在 Ubuntu 底下的 Ports 轉送到我的 Windows 本機。我原本以為這件事不難，結果卻卡關了一下，這篇文章我就來說說解法。

![Multipass](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/a808992e023ea7c284b1-196269466-957f87c7-ef70-413a-bd20-b45afce5af6b.png)

### 理解 multipass shell 登入 VM 的原理

為什麼我們可以用這麼簡單的命令登入 Linux 呢？

```bash
multipass shell microk8s-vm
```

想也知道他背後肯定使用了 SSH 金鑰來連線，但重點是文件沒寫這份金鑰在哪裡啊？我是從 [GitHub Issue #309](https://github.com/canonical/multipass/issues/309#issuecomment-513594601) 找到的，不過這份 Issue 講的是 macOS 的路徑，沒說 Windows 路徑在哪！

```bash
sudo ssh \
    -i /var/root/Library/Application\ Support/multipassd/ssh-key/id_rsa \
    -L 9000:localhost:80 \
    multipass@<multipass instance ip>
```

我有找到！就在這裡：

```bash
C:\ProgramData\Multipass\data\ssh-keys\id_rsa
```

所以理論上，我們可以這樣登入 VM：

```powershell
ssh -i C:\ProgramData\Multipass\data\ssh-keys\id_rsa ubuntu@192.168.1.14
```

結果卻遇到以下問題：

```
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@         WARNING: UNPROTECTED PRIVATE KEY FILE!          @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
Permissions for 'C:\\ProgramData\\Multipass\\data\\ssh-keys\\id_rsa' are too open.
It is required that your private key files are NOT accessible by others.
This private key will be ignored.
Load key "C:\\ProgramData\\Multipass\\data\\ssh-keys\\id_rsa": bad permissions
multipass@192.168.1.14: Permission denied (publickey).
```

![Permissions for 'C:\\ProgramData\\Multipass\\data\\ssh-keys\\id\_rsa' are too open.](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/417a5f1b0c406274429c-196243022-8b30eff1-71f5-4750-8788-ae349fb23388.png)

簡單來說，就是 `ssh` 要求用金鑰認證的人，其「私密金鑰」的權限不能太開放，否則會不安全，所以你必須把「其他人可以閱讀」的權限移除，才能使用這把金鑰登入遠端主機。

### 調整 SSH 私密金鑰的 NTFS 權限

你可以參考以下步驟進行 NTFS 權限調整：

1.  先查詢現有檔案權限
    
    ```batch
    icacls C:\ProgramData\Multipass\data\ssh-keys\id_rsa
    ```
    
    從回應結果可以發現，原來這個檔案被賦予了 `BUILTIN\Users` 可讀、可執行的權限(`RX`)，那是因為這個檔案的 NTFS 權限是自動從上層目錄繼承來的(`I`)！
    
    ```batch
    C:\ProgramData\Multipass\data\ssh-keys\id_rsa NT AUTHORITY\SYSTEM:(I)(F)
                                                  BUILTIN\Administrators:(I)(F)
                                                  BUILTIN\Users:(I)(RX)
    
    Successfully processed 1 files; Failed processing 0 files
    ```
    
2.  先賦予自己擁有完整權限，並同時移除權限繼承
    
    請以**系統管理員身份**啟動 Windows PowerShell 並執行以下命令：
    
    ```batch
    icacls C:\ProgramData\Multipass\data\ssh-keys\id_rsa /inheritance:r /grant "$(whoami):F" /grant "NT AUTHORITY\SYSTEM:F"
    ```
    
    > 這裡 `/inheritance:r` 是「移除繼承」的意思，若寫 `/inheritance:e` 則代表「啟用繼承」的意思。另外，這裡 `/grant` 是授權的意思，命令中出現了兩次，那是因為我們移除了繼承權限後，需要同時授權給兩個帳戶，一個是自己 (`$(whoami)`)，也就是目前登入者的身分，另一個是系統帳戶 `SYSTEM`，而 `:F` 則是賦予「完整權限」的意思。
    
3.  此時金鑰的 NTFS 權限就被現縮到很小了，而且可以成功連接 Linux VM
    
    ```batch
    icacls C:\ProgramData\Multipass\data\ssh-keys\id_rsa
    ```
    
    ```batch
    C:\ProgramData\Multipass\data\ssh-keys\id_rsa NT AUTHORITY\SYSTEM:(F)
                                                  WILLSUPERPC\user:(F)
    
    Successfully processed 1 files; Failed processing 0 files
    ```
    
    你也可以用 PowerShell 的 `Get-Acl` 查看 ACL 資訊：
    
    ```powershell
    PS> Get-Acl C:\ProgramData\Multipass\data\ssh-keys\id_rsa | fl
    Path   : Microsoft.PowerShell.Core\FileSystem::C:\ProgramData\Multipass\data\ssh-keys\id_rsa
    Owner  : BUILTIN\Administrators
    Group  : NT AUTHORITY\SYSTEM
    Access : NT AUTHORITY\SYSTEM Allow  FullControl
            WILLSUPERPC\user Allow  FullControl
    Audit  :
    Sddl   : O:BAG:SYD:PAI(A;;FA;;;SY)(A;;FA;;;S-1-5-21-1610181907-3261981930-2611305422-1003)
    ```
    
    測試連線成功！
    
    ```bash
    ssh -i C:\ProgramData\Multipass\data\ssh-keys\id_rsa ubuntu@192.168.1.14
    ```
    

### 使用 SSH 的 Port forwarding 轉送埠號

1.  我先在 `microk8s-vm` 執行以下命令
    
    ```bash
    microk8s dashboard-proxy
    ```
    
    此時會在 Linux VM 內監聽 `127.0.0.1:10443` 這個 PORT
    
    ![image](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/5729358e977e5b55bac9-196246887-252f7fee-373a-4915-b619-9c73357120f8.png)
    
2.  另開一個 Terminal 視窗，透過以下命令連入 VM，並搭配 `-L {localport}:{host}:{hostport}` 參數進行埠號轉送
    
    ```powershell
    ssh -i C:\ProgramData\Multipass\data\ssh-keys\id_rsa -L 8443:localhost:10443 -N ubuntu@192.168.1.14
    ```
    
    > 這裡的 `-N` 代表「不登入」的意思，單純用來建立 Port forwarding 而已。
    
    接著你就可以在 Windows 本機輸入 [https://127.0.0.1:8443/](https://127.0.0.1:8443/) 連入網站了！👍
    

### 相關連結

-   [ssh "permissions are too open" - Stack Overflow](https://stackoverflow.com/a/63108878/910074)
-   [Force ssh to ignore id\_rsa permissions - Server Fault](https://serverfault.com/a/990019/234528)
-   [ssh port forwarding without logging in - Unix & Linux Stack Exchange](https://unix.stackexchange.com/a/199664/288400)
