卖兜搞IT

通过Azure Cloud Shell连接没有Public IP的虚拟机

阅读原文 https://www.xiaopeng163.com/azure-cloud-shell/

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
Image

以Bash为例,选择No Storage account required,然后选中你的subscription
Image

等待shell ready后,在shell里执行 az account show

Image

注册resource provider

确认下面三个provider已经注册

  • Microsoft.CloudShell

  • Microsoft.ContainerInstance

  • Microsoft.Relay

注册方法如下:

  • 在你的 subscription页面左边菜单里找到Settings

  • 在Setting里找到 Resource providers,点击.

  • 在搜索框里输入 cloudshell 找到Microsoft.CloudShell,点击上面的register

  • 同样的步骤重复 Microsoft.ContainerInstance 和 Microsoft.Relay
    Image

创建一个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
Image

Get the Azure container instance ID

在搜索框里搜索 Microsoft Entra ID

Image

点进去后,到overview里搜索 azure container instance service,然后在结果里点击 Azure Container Instance Service

Image

在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

Image

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

Image

会重新加载cloud shell,这次我们需要选择

  • Mount storage account

  • 选择我们的subscription

  • 勾选使用我们的private virtual network

Image

然后在vnet的configuration里选中我们之前创建好的资源,比如relay,profile等等
Image

最后开始部署,这个过程需要几分钟。后面ready的时候,我们可以查看我们的shell的ip,这个ip就是我们之前创建的vent1的subnet

Image

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了

Image

那最终的连接关系如下

Image

环境清理

直接删除我们的resource group就可以了
Image

参考链接

  • https://www.redeploy.com/post/running-cloud-shell-from-your-virtual-network

  • https://learn.microsoft.com/en-gb/azure/cloud-shell/vnet/deployment