Microsoft の dev tunnels でほぼ踏み台いらず

Microsoft の dev tunnels (開発トンネル) は、Microsoft のサーバーに対して、クライアントとサーバーの両方から外向きの接続を張ることで、クライアントからサーバーへのポートフォワーディングを実現します。

これを使えば Azure Bastion のような高級な踏み台サービスを使わずに、無料で組織のネットワークからサーバーへの接続を実現できます。(認められていればですが。)

- 初期設定時は踏み台などを使う想定です
    - `devtunnel` コマンドでインタラクティブな操作なしにクライアントと Azure VM で同一 ID でログインする方法がわからなかったためです
        - コンテナー作成時の非インタラクティブなログインは可能なようです[^container]
- Dev tunnels には CLI からの接続、Visual Studio Code (VS Code) からの接続、Visual Studio からの接続ができますが、この記事では私が普段使わない Visual Studio からの接続は扱いません
- クライアントには Windows、サーバーは Azure 上の Ubuntu (Arm64) を用います
    - 検証なので安い Arm64 にしましたが、実際に使う際は x64 がおすすめです
- Azure のポータルは英語設定です

[^container]: https://github.com/microsoft/vscode/issues/170013#issuecomment-1787378725


## VS Code Remote - Tunnels での接続

### サーバー側

Azure で Ubuntu 24.04 LTS (Arm64) の VM を作成します。

https://code.visualstudio.com/docs/remote/tunnels#_alternative-downloads

上記では URL が x64 になっているので、以下のように arm64 に修正して導入します。

```console
$ curl -Lk 'https://code.visualstudio.com/sha/download?build=stable&os=cli-alpine-arm64' --output vscode_cli.tar.gz
$ tar -xf vscode_cli.tar.gz
$ mkdir -p ~/.local/bin
$ mv code ~/.local/bin
$ echo 'export PATH="$PATH:$HOME/.local/bin"'
$ code tunnel # ログインなどの初期設定と実行
```

出力された `https://vscode.dev/tunnel/<マシン名>` にアクセスすると VS Code Server が開きますが、ここでは VS Code Remote - Tunnels で接続するのでアクセス不要です。

### クライアント側

以下の拡張をインストールします。

https://marketplace.visualstudio.com/items?itemName=ms-vscode.remote-server

その後、以下を実施します。

1. 左端の Remote Explorer アイコンをクリック
1. Sign in to tunnels registered with GitHub (または Microsoft) の「→」をクリック
1. Allow
1. ブラウザーでログインして、Visual Studio Code に対してアクセスを許可
1. Tunnels に設定したマシンが表示されているので「→」をクリック

![画面](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/232368/82477b3f-d018-4090-9ffc-83d70a927377.png)


サーバーに接続されたら、Ctrl+@ でターミナルを開けば、サーバーの bash がそこにあります。

### サーバー (サービスのインストール)

実行中のトンネルを Ctrl+C で終了後、以下を実行します。

```console
$ code tunnel service install
$ sudo loginctl enable-linger $USER # ログアウト後もサービスを継続
```

これで再起動後もつながります。

サービスの中身が気になったので表示してみました。参考になります φ(´・ω・｀)

```console
$ cat ~/.config/systemd/user/code-tunnel.service 
[Unit]
Description=Visual Studio Code Tunnel
After=network.target
StartLimitIntervalSec=0

[Service]
Type=simple
Restart=always
RestartSec=10
ExecStart=/home/azureuser/.local/bin/code "--verbose" "--cli-data-dir" "/home/azureuser/.vscode/cli" "tunnel" "service" "internal-run"

[Install]
WantedBy=default.target
```

ChatGPT によれば、`StartLimitIntervalSec=0` と `Restart=always` で無限再起動、`RestartSec=10` でその間隔を 10 秒にしているそうです。

### 注意点: Microsoft はあなたのアカウントでなんでもできる

Microsoft のサーバーからは、起動したユーザーの権限でなんでもできてしまうので、セキュリティ上好ましくはないと思います。でも Azure を使っている時点で Microsoft はサーバーになんでもできるので、元からセキュアではなく、気にする必要はないでしょう。

### 補足

VS Code の Remote - Tunnels に関してはほかにも面白い記事がありますのでご覧になってみてください。

https://qiita.com/920oj/items/c7d26eb95bc5e556807d


## Dev tunnel での接続

今度は `devtunnel` コマンドを使って SSH にポートフォワーディングしてみます。

### サーバー側

https://learn.microsoft.com/ja-jp/azure/developer/dev-tunnels/get-started?tabs=linux

```console
$ curl -sL https://aka.ms/DevTunnelCliInstall | bash
$ # ↓ --github をつけないと MS アカウント。詳細は -h で。
$ devtunnel user login --github --use-device-code-auth
$ devtunnel list
```

`devtunnel list` で、`code tunnel` で作成したトンネルが表示されます。

```console
$ devtunnel create -l <適当な ID>
$ devtunnel port create <ID> -p 22
$ devtunnel host <ID>
```

### クライアント側

```powershell
winget install Microsoft.devtunnel
devtunnel user login --github # GitHub 以外の場合については -h で。
devtunnel connect <ID>
```

別のタブで、`ssh -i .\path\to\private_key azureuser@localhost` のようにすると、接続できるはずです。

### サーバー側 (サービスのインストール)

Ctrl+C で `devtunnel host` を止め、今度はサービス化してみます。サービス名の `my-ubuntu-devtunnel` はお好みで書き換えてください。

```console
$ systemctl --user edit --full --force my-ubuntu-devtunnel
```

```systemd
[Unit]
After=network.target

[Service]
ExecStart=/home/azureuser/bin/devtunnel host <ID>

[Install]
WantedBy=default.target
```

書き終えたら Ctrl+O で Write Out、ファイル名はそのまま Enter、Ctrl+X で Exit としてください。

```console
$ systemctl --user start my-ubuntu-devtunnel
$ systemctl --user status my-ubuntu-devtunnel # Active: active (running) を確認
$ systemctl --user enable my-ubuntu-devtunnel
```

うまくいかなかった場合は、`journalctl --user -u my-ubuntu-devtunnel` で状況を確認してください。

先ほどの `code tunnel` のサービスのインストール時に `sudo loginctl enable-linger $USER` を実行してあるので、これでログアウト後や再起動後も接続できるはずです。

SSH で接続する前に、クライアント側の `devtunnel connect` コマンドを Ctrl+C で止めてから再実行してください。

### クライアント側 (VS Code Remote - SSH)

Remote - Tunnels とほぼ同じで説明不要だと思いますので、リンクだけ貼っておきます。

https://marketplace.visualstudio.com/items?itemName=ms-vscode-remote.remote-ssh

### 注意点: ホスト中に Public IP を外したりつけたりするとつながらなくなる

Remote - Tunnels では再接続できるのに、なぜか `devtunnel` コマンドは接続できなくなります。

Public IP の設定はシャットダウンしてから行うのが良いと思います。