Mac から Azure Bastion 経由で VM へ接続する

## はじめに
Azure Bastion への ネイティブクライアント接続について、今までは接続元のクライアントとして Windows 端末のみの対応でしたが、`az network bastion tunnel`コマンドを利用することで、Mac 等（Linux 系 OS)からも、ネイティブクライアント接続できるようになりましたので試してみました。

Windows 端末からの`az network bastion rdp`や`az network bastion ssh`コマンドと比べてトンネリングの一手間は必要にはなりますが、Linux 系 OS でも利用可能なことに加えて、トンネリングでの ポートフォーワーディング接続となりますので、例えば、ブラウザより、VM の 80 portへの HTTP 接続など、場合によっては色々と応用可能ではないかと思います。
 
なお、ネイティブクライアント接続の詳細や事前準備等については、以下公式ドキュメントや、同僚の詳細記事を参照いただければと思います。

https://docs.microsoft.com/ja-jp/azure/bastion/connect-native-client-windows

https://qiita.com/Isato-Hiyama/items/106504a2ed49a74d990f

## 実行環境
+ Mac OS Monterey 12.3（21E230）
+ azure-cli
```
~ $ az version
{
  "azure-cli": "2.34.1",
  "azure-cli-core": "2.34.1",
  "azure-cli-telemetry": "1.0.6",
  "extensions": {}
}
~ $ 
```

## `az network bastion tunnel`コマンド
`az network bastion tunnel --name "<BastionName>" --resource-group "<ResourceGroupName>" --target-resource-id "<VMResourceId>" --resource-port "<TargetVMPort>" --port "<LocalMachinePort>"`

詳細は以下公式ドキュメントを参照してください。

https://docs.microsoft.com/en-us/cli/azure/network/bastion?view=azure-cli-latest#az-network-bastion-tunnel-examples

## SSH 接続の例
`az network bastion tunnel`コマンドを利用して Azure bastion 経由で接続対象 VM へトンネリングを行います。なお、こちらのトンネリングが切れてしまうと、後述の SSH 接続も、切断されてしまいますので注意してください。
+ `--resource-port 22`を設定
+ `--port 50022`を設定
    + 後述の Tips でも触れますが、こちらは Mac 等接続元のクライアント側で利用していない Port 番号であればなんでも OK ですが、Well Known ports（0〜1023） は避けた方が良いです

```bash:"実行（例）"
# 環境変数へ設定
export RGNAME="demo_nw"
export BASTION="demo_nw_hub_bastion01"
export RID="/subscriptions/[YOUR_SUBSCRIPTION_ID]/resourceGroups/demo_nw/providers/Microsoft.Compute/virtualMachines/ubuntuvm"
# az network bastion tunnel でトンネルを確立
az network bastion tunnel --name $BASTION --resource-group $RGNAME --target-resource-id $RID  --resource-port 22 --port 50022
Command group 'network bastion' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
Opening tunnel on port: 50022
Tunnel is ready, connect on port 50022
Ctrl + C to close
```

トンネリング確立後(`Tunnel is ready, connect on port 50022`)に、別のTerminalやタブを開き、以下のように、自分自身（127.0.0.1 または、localhost ）のトンネリングポートへSSH接続を行います。

```bash:"実行（例）"
ssh -i ~/.ssh/id_azure azureuser@localhost -p 50022
```

## RDP 接続の例
+ `--resource-port 3389`を設定
+ `--port 53389`を設定

```bash:"実行（例）"
# 環境変数へ設定
export RGNAME="demo_nw"
export BASTION="demo_nw_hub_bastion01"
export RID="/subscriptions/[YOUR_SUBSCRIPTION_ID]/resourceGroups/demo_nw/providers/Microsoft.Compute/virtualMachines/windowsvm"
# az network bastion tunnel でトンネルを確立
az network bastion tunnel --name $BASTION --resource-group $RGNAME --target-resource-id $RID --resource-port 3389 --port 53389
```

トンネリング確立後に、RDP クライアントより、自分自身（127.0.0.1 または、localhost ）のトンネリングポート 53389 へ RDP 接続を行います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/02caefea-a5d1-5286-be28-74932bea0a96.png" width=70%>

## HTTP 接続の例
+ `--resource-port 80`を設定
+ `--port 50080`を設定

```bash:"実行（例）"
# az network bastion tunnel でトンネルを確立
az network bastion tunnel --name "demo_nw_hub_bastion01" --resource-group "demo_nw" --target-resource-id "/subscriptions/[YOUR_SUBSCRIPTION_ID]/resourceGroups/demo_nw/providers/Microsoft.Compute/virtualMachines/ubuntuvm" --resource-port 80 --port 50080
```
トンネリング確立後に、ブラウザより、自分自身（127.0.0.1 または、localhost ）のトンネリングポート 50080 へ HTTP 接続を行います。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/117986/55101835-77b3-0dbc-979f-8a8002cca9ed.png" width=80%>

## Tips
+ トンネルに利用する port 番号は、Well known ports(0〜1023) よりも上の番号を指定しないと OS （ Mac や Linux 系）によっては、root 権限がないとパーミッションエラーになります。（特権 port の bindには root 権限が必要なため）
  + `sudo` によるコマンド実行でも回避できますが、ダイナミック/プライベートポート（49152〜65535）を使った方良さそうです。

```bash:"実行結果（例）"
~ $ az network bastion tunnel --name "demo_nw_hub_bastion01" --resource-group "demo_nw" --target-resource-id "/subscriptions/[YOUR_SUBSCRIPTION_ID]/resourceGroups/demo_nw/providers/Microsoft.Compute/virtualMachines/ubuntuvm" --resource-port 22 --port 222
Command group 'network bastion' is in preview and under development. Reference and support levels: https://aka.ms/CLI_refstatus
The command failed with an unexpected error. Here is the traceback:
[Errno 13] Permission denied
Traceback (most recent call last):
  File "/usr/local/Cellar/azure-cli/2.34.1/libexec/lib/python3.10/site-packages/knack/cli.py", line 231, in invoke
    cmd_result = self.invocation.execute(args)
  File "/usr/local/Cellar/azure-cli/2.34.1/libexec/lib/python3.10/site-packages/azure/cli/core/commands/__init__.py", line 658, in execute
    raise ex
  File "/usr/local/Cellar/azure-cli/2.34.1/libexec/lib/python3.10/site-packages/azure/cli/core/commands/__init__.py", line 721, in _run_jobs_serially
    results.append(self._run_job(expanded_arg, cmd_copy))
  File "/usr/local/Cellar/azure-cli/2.34.1/libexec/lib/python3.10/site-packages/azure/cli/core/commands/__init__.py", line 692, in _run_job
    result = cmd_copy(params)
  File "/usr/local/Cellar/azure-cli/2.34.1/libexec/lib/python3.10/site-packages/azure/cli/core/commands/__init__.py", line 328, in __call__
    return self.handler(*args, **kwargs)
  File "/usr/local/Cellar/azure-cli/2.34.1/libexec/lib/python3.10/site-packages/azure/cli/core/commands/command_operation.py", line 121, in handler
    return op(**command_args)
  File "/usr/local/Cellar/azure-cli/2.34.1/libexec/lib/python3.10/site-packages/azure/cli/command_modules/network/custom.py", line 8212, in create_bastion_tunnel
    tunnel_server = get_tunnel(cmd, resource_group_name, bastion_host_name, target_resource_id, resource_port, port)
  File "/usr/local/Cellar/azure-cli/2.34.1/libexec/lib/python3.10/site-packages/azure/cli/command_modules/network/custom.py", line 8198, in get_tunnel
    tunnel_server = TunnelServer(cmd.cli_ctx, 'localhost', port, bastion, vm_id, resource_port)
  File "/usr/local/Cellar/azure-cli/2.34.1/libexec/lib/python3.10/site-packages/azure/cli/command_modules/network/tunnel.py", line 59, in __init__
    self.sock.bind((self.local_addr, self.local_port))
PermissionError: [Errno 13] Permission denied
To open an issue, please run: 'az feedback'
~ $
```
:::note info
本記事の実行結果等は執筆時点（2022年4月5日）での内容となります
:::