通过Azure Cloud Shell连接没有public IP的虚拟机
Azure的Cloud Shell非常的方便,它提供了一个基于Web的命令行工具,可以通过bash或者powershell去执行一些命令,比如az,git等等。
但是Cloud shell默认是无法直接访问你的subscription里的resource的,特别是当你的resource没有public IP的时候,比如一个只有私有网络的VM,这个时候如果想要cloud shell能够直接访问这台VM,那么需要cloud shell能够连接到VM所在的Virtual Network里,这篇文章我们就一起看看如何操作。
准备工作
打开cloud shell
以Bash为例,选择No Storage account required,然后选中你的subscription
等待shell ready后,在shell里执行 az account show
注册resource provider
确认下面三个provider已经注册
- Microsoft.CloudShell
- Microsoft.ContainerInstance
- Microsoft.Relay
注册方法如下:
-
在你的 subscription页面左边菜单里找到Settings
-
在Setting里找到 Resource providers,点击.
-
在搜索框里输入 cloudshell 找到Microsoft.CloudShell,点击上面的register
-
同样的步骤重复 Microsoft.ContainerInstance 和 Microsoft.Relay
创建一个resource group,一个vnet,三个subnet
RESOURCE_GROUP_NAME=rg-demo
VNET_NAME=vnet1
# create resource group
az group create --name $RESOURCE_GROUP_NAME --location westeurope
# create vnet
az network vnet create --resource-group $RESOURCE_GROUP_NAME --name $VNET_NAME --address-prefix 10.0.0.0/16
# create subnet for vm
az network vnet subnet create \
--name subnet-vm \
--address-prefixes 10.0.0.0/24 \
--resource-group $RESOURCE_GROUP_NAME \
--vnet-name $VNET_NAME
az network vnet subnet create \
--name sn-containers-dev \
--address-prefixes 10.0.1.0/24 \
--resource-group $RESOURCE_GROUP_NAME \
--vnet-name $VNET_NAME \
--delegations Microsoft.ContainerInstance/containerGroups \
--service-endpoints Microsoft.Storage
# Create Azure Relay subnet
az network vnet subnet create \
--name sn-relay-dev \
--address-prefixes 10.0.2.0/24 \
--resource-group $RESOURCE_GROUP_NAME \
--vnet-name $VNET_NAME
# Disable private endpoint network policies for Azure Relay subnet
az network vnet subnet update \
--name sn-relay-dev \
--resource-group $RESOURCE_GROUP_NAME \
--vnet-name $VNET_NAME \
--private-endpoint-network-policies Disabled
创建Network Profile
RESOURCE_GROUP_NAME=rg-demo
VNET_NAME=vnet1
# get subnet id
containerSubnet=$(az network vnet subnet show \
--name sn-containers-dev \
--resource-group $RESOURCE_GROUP_NAME \
--vnet-name $VNET_NAME \
--query id -o tsv)
# Network profile
az resource create \
--name anp-cloudshell-westeu \
--resource-group $RESOURCE_GROUP_NAME \
--resource-type Microsoft.Network/networkProfiles \
--properties "{\"containerNetworkInterfaceConfigurations\": \
[{\"name\": \"sn-containers-dev\",\"properties\": \
{\"ipConfigurations\":[{\"name\":\"ipconfig01\",\"properties\": \
{\"subnet\": {\"id\": \"$containerSubnet\"}}}]}}]}"
在resource group里选中显示隐藏资源,就可以看到我们创建的network profile
Get the Azure container instance ID
在搜索框里搜索 Microsoft Entra ID
点进去后,到overview里搜索 azure container instance service
,然后在结果里点击 Azure Container Instance Service
在Azure Container Instance Service
的Overview, 找到 Object ID,复制保存好,一会要用
Role assigment
执行命令
containerInstanceId=<前面复制的object ID>
# Get the network profile resource ID
networkProfile=$(az network profile show \
--name anp-cloudshell-westeu \
--resource-group $RESOURCE_GROUP_NAME \
--query id -o tsv)
# Delegate access to the resource
az role assignment create \
--role "Network Contributor" \
--assignee-object-id $containerInstanceId \
--scope $networkProfile
然后在你的network profile里点击Access Control,选中Role assigments就可以看到Azure Container Instance Service有了Network Contributor的Role
Azure Relay namespace
接下来创建Azure Relay
AZURE_RELAY_NAME=arn-cloudshell-westeu1234
az relay namespace create \
--name $AZURE_RELAY_NAME \
--resource-group $RESOURCE_GROUP_NAME
注意,上面的名字要起一个别人没有用过的名字,最好是搞一些随机字符串在后面
创建 private endpoint, 让我们的azure relay可以和cloud shell container通信
# Get Azure Relay subnet ID
azureRelaySubnetId=$(az network vnet subnet show \
--name sn-relay-dev \
--resource-group $RESOURCE_GROUP_NAME \
--vnet-name $VNET_NAME \
--query id -o tsv)
# Get Azure Relay namespace ID
azureRelayResourceId=$(az relay namespace show \
--name $AZURE_RELAY_NAME \
--resource-group $RESOURCE_GROUP_NAME \
--query id -o tsv)
# Create private endpoint
az network private-endpoint create \
--name pe-cloudshell-westeu \
--connection-name CloudShellEndpoint \
--resource-group $RESOURCE_GROUP_NAME \
--subnet $azureRelaySubnetId \
--private-connection-resource-id $azureRelayResourceId \
--group-id namespace
# Delegate access to the resource
az role assignment create \
--role Contributor \
--assignee-object-id $containerInstanceId \
--scope $azureRelayResourceId
Storage Account
# Create a storage account
STORAGE_ACCOUNT_NAME=stocloudshellwesteu1234
az storage account create \
--name $STORAGE_ACCOUNT_NAME \
--resource-group $RESOURCE_GROUP_NAME \
--sku Standard_LRS
# Create file share for Cloud Shell
az storage share create \
--name profile \
--account-name $STORAGE_ACCOUNT_NAME \
--quota 6
# Allow access to storage account from Cloud Shell container
az storage account network-rule add \
--account-name $STORAGE_ACCOUNT_NAME \
--resource-group $RESOURCE_GROUP_NAME \
--vnet-name $VNET_NAME \
--subnet sn-containers-dev
# Deny access by default
az storage account update \
--name $STORAGE_ACCOUNT_NAME \
--resource-group $RESOURCE_GROUP_NAME \
--default-action Deny
测试
reload cloud shell
会重新加载cloud shell,这次我们需要选择
- Mount storage account
- 选择我们的subscription
- 勾选使用我们的private virtual network
然后在vnet的configuration里选中我们之前创建好的资源,比如relay,profile等等
最后开始部署,这个过程需要几分钟。后面ready的时候,我们可以查看我们的shell的ip,这个ip就是我们之前创建的vent1的subnet
Create Test VM
记得修改下面的ssh密码
RESOURCE_GROUP_NAME=rg-demo
VNET_NAME=vnet1
az vm create \
--resource-group $RESOURCE_GROUP_NAME \
--name vm1 \
--image Ubuntu2204 \
--admin-username demo \
--admin-password '**********' \
--vnet-name $VNET_NAME \
--subnet subnet-vm \
--public-ip-address "" \
--nsg-rule SSH \
--location westeurope
创建完成后,我们可以看到它的private IP,然后我们在cloud shell里就可以通过我们的ssh用户名密码去连接这台VM了
那最终的连接关系如下
环境清理
直接删除我们的resource group就可以了
Discussion