Azure VM缩放集:是否可以传递引导脚本/设置而无需从URL下载它们?

时间:2019-02-09 09:12:13

标签: azure-virtual-machine azure-vm-scale-set

我看到有了Custom Script Extension,就可以引导新的VM(在Scale Set中)。要访问脚本,它需要使用Azure存储URI和凭据。这种方法对我不起作用,因为(内部策略)不允许它通过存储凭据。

我的VMSS已分配服务标识,后者已在KeyVault中注册。因此,直接在盒子上获取凭证非常简单。但是为此,我至少需要小的引导脚本=)

我发现了一种通过自定义脚本扩展实现此目标的方法:

$bootstrapScriptPath = Join-Path -Path $PSScriptRoot -ChildPath "bootstrap.ps1"
$bootstrapScriptBlock = get-command $bootstrapScriptPath | Select -ExpandProperty ScriptBlock
$installScriptBase64 = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($bootstrapScriptBlock.ToString()))

"commandToExecute": "[concat('powershell -ExecutionPolicy Unrestricted -EncodedCommand ', parameters('installScriptBase64'))]"

但是我想知道是否有更好的解决方案。

基本上,我需要Cloud Service提供的某些功能-能够上传负载和配置设置。

解决方案

(注意,这是用于Windows VM。对于Linux VM,有一种更简单的方法-感谢@sendmarsh)

请参阅下面的实际实现方法(注意,我将来自@ 4c74356b41的帖子标记为答案,他提出了这个想法)。

3 个答案:

答案 0 :(得分:1)

首先,我真的没有发现任何漏洞,这是有效的方法。

另一种传递数据的方式-使用custom data属性。该文件将作为vm中的文件提供,我不记得它的base64是否已编码,但是您可以在配置后迅速找到它。

另一种方法是对虚拟机使用Managed Service Identity。这样,您只需为VM分配适当的权限,它就可以从存储中下载脚本,而无需您明确地传递它们。

无论哪种方式,都需要将脚本传递给vm并使用脚本扩展名对其进行调用。您可以在脚本中使用自定义图像和脚本。或者您可以将脚本包含在公开的URL中,以便vm始终可以将其提取并执行(在这种情况下,您需要MSI为您处理auth)。

您可以做的另一件事是pull certificates from KV,直接在VM内进行。设置。

答案 1 :(得分:1)

如果是Linux VM,则可以避免将脚本扩展与Custom Data和cloud-init一起使用。不使用脚本扩展名也将节省您几分钟的部署时间。

这里有一个虚拟机示例:https://msftstack.wordpress.com/2018/11/26/speeding-up-azure-resource-manager-templates-using-cloud-init/-您可以按照相同的方法来设置比例尺。

答案 2 :(得分:0)

这是我的结局:

  1. 将Bootstrap.ps1作为自定义数据传递
  2. 通过“自定义脚本扩展”运行复杂的命令-解码CustomData.bin,将其复制为Bootstrap.ps1并使用 参数
  3. 没有下载外部文件
  4. Bootstrap.ps1注册一个任务调度程序以重新运行,从元数据服务获取令牌以获取用户分配的托管身份,然后转到 密钥保管箱获取凭据以下载,下载, 解压缩等。

下面的代码片段介绍了如何使#1和#2正常工作。

Bootstrap.ps1示例:

param(
 [Parameter(Mandatory=$True)]
 [string]
 $param1,

 [Parameter(Mandatory=$True)]
 [string]
 $param2
)

$ErrorActionPreference = "Stop"

Write-Output("Running Bootstrap.ps1 with the following parameters:");
Write-Output("`$param1 = `"$param1`";");
Write-Output("`$param2 = `"$param2`";");

将其作为CustomData传递:

# Encoding bootstrap script
$bootstrapScriptPath = (Join-Path -Path "." -ChildPath "Node/Bootstrap.ps1");
$bootstrapScriptBlock = get-command $bootstrapScriptPath | Select -ExpandProperty ScriptBlock;
$encodedScript = [System.Convert]::ToBase64String([System.Text.Encoding]::Unicode.GetBytes($bootstrapScriptBlock.ToString()));
...
| Set-AzVMOperatingSystem -CustomData $encodedScript

命令行:

$commandLine = "powershell -ExecutionPolicy Unrestricted -Command `"" ` + # Running powershell in cmd
                    "`$ErrorActionPreference = 'Stop';" ` + # Upon any error fail the provisioning of the extension
                    "`$content = [IO.File]::ReadAllText('C:\AzureData\CustomData.bin');" + ` # Read Base64-encoded file
                    "`$bytes = [System.Convert]::FromBase64String(`$content);" + ` # Convert to bytes
                    "`$script = [System.Text.Encoding]::Unicode.GetString(`$bytes);" + ` # Decode to string
                    "[IO.File]::WriteAllText('C:\AzureData\Bootstrap.ps1', `$script);" + ` # Save as Bootstrap.ps1
                    "C:\AzureData\Bootstrap.ps1 " + ` # Run a script
                    "-param1 'test' -param2 'test' " + ` # Pass needed parameters
                    " | Out-File -PSPath 'C:\AzureData\output.log';" ` +
                "`"";

自定义脚本扩展名:

$extensionSettings = @{ "fileUris" = ""; "commandToExecute" = ""};
$extensionProtectedSettings = @{ "commandToExecute" = "$commandLine" };
$result = Set-AzVMExtension -VMName "$($vm.Name)" -Location $resourceGroupLocation -Publisher "Microsoft.Compute" -Type "CustomScriptExtension" `
                            -TypeHandlerVersion "1.9" -Settings $extensionSettings -ProtectedSettings $extensionProtectedSettings `
                            -Name "Bootstrap" -ResourceGroupName $resourceGroup.ResourceGroupName;