Azure VM Customscript not Downloading - azure

I am using below terraform .tf file . Its always showing the error as
DownloadFileAsync: Error in downloading file from
https://github.dxc.com/raw/gist/jmathews4/2095e2436571715f94e05e5ac5400a67/raw/f554d018ae4fee12979b2ee6f5ac4abb3ff509aa/Terraform.ps1?token=AAAMrnoBPpBc7C8kN2_haQueWaqDhth-ks5bUGqhwA%3D%3D,
retry count 25, exception: System.Net.WebException: The request was
aborted: Could not create SSL/TLS secure channel. at
System.Net.WebClient.DownloadFile(Uri address, String fileName)
Any idea what could be issue with GIT?
provider "azurerm" {
}
variable "location" { default = "Southeast Asia" }
variable "resourceGroup" { default = "TerraformResearchResourceGroup" }
variable "virtualMachine" { default = "terraformrvm" }
resource "azurerm_virtual_machine_extension" "ext" {
name = "eagpocvmexxt"
location = "Southeast Asia"
resource_group_name = "terraformrg"
virtual_machine_name = "terraformvm"
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.8"
settings = <<SETTINGS
{
"fileUris": ["https://github.dxc.com/raw/gist/jmathews4/2095e2436571715f94e05e5ac5400a67/raw/f554d018ae4fee12979b2ee6f5ac4abb3ff509aa/Terraform.ps1?token=AAAMrnoBPpBc7C8kN2_haQueWaqDhth-ks5bUGqhwA%3D%3D"],
"commandToExecute": "powershell.exe -ExecutionPolicy unrestricted -NoProfile -NonInteractive -File Terraform.ps1"
}
SETTINGS
tags {
environment = "Production"
}
}

Yeah, the issue is Git is enforcing TLS 1.2 and extension doesnt like that, your workaround is to put the file somewhere where extension can download it without intervention. Azure Storage.

Related

Run a powershell script in a storage account using Terraform when building an azure vm

I am attempting to write terraform code which when the VM is being created the code will reach out to a storage account and run a powershell script. there seems to be some solutions to my answer but all the solutions I have found are using a public blob access. I have to disable enable blob public access. Below is my terraform code and error
resource "azurerm_virtual_machine_extension" "powershell" {
count = length(var.instances)
name = "runpowershell"
virtual_machine_id = azurerm_windows_virtual_machine.vm.*.id[count.index]
depends_on = [azurerm_windows_virtual_machine.vm]
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.9"
settings = <<SETTINGS
{
"fileUris": ["https://test.blob.core.windows.net/scripts/deployment.ps1"],
"commandToExecute": "powershell -ExecutionPolicy Unrestricted -file deployment.ps1"
}
SETTINGS
I changed the code to
``{
"fileUris": ["https://test.blob.core.windows.net/scripts/deployment.ps1"]
}
SETTINGS
protected_settings = <<PROTECTED_SETTINGS
{
"storageAccountKey": "Vg/4BBah3......ASt2sbGww==",
"storageAccountName": "test",
"commandToExecute": "powershell -ExecutionPolicy Unrestricted -File deployment.ps1"
}
PROTECTED_SETTINGS
}
now i get the message - which reads Forbidden now not conflict - I checked the key and it is correct
Error: Code="VMExtensionProvisioningError" Message="VM has reported a failure when processing extension 'runpowershell'. Error message: "Failed to download all specified files. Exiting. Error Message: The remote server returned an error: (403) Forbidden."\r\n\r\nMore information on troubleshooting is available at https://aka.ms/VMExtensionCSEWindowsTroubleshoot "
Well, I found my answer. In the code I pasted I changed the name of the actual storage account. In my code for fileurs I had the correct name but for storage account in protected settings I spelled the account wrong. Once I fixed that...it all worked.

Is there a way in terraform to create a replacement group of related resources before destroying the original group?

I have a VM template I'm deploying an Azure Virtual Desktop environment with terraform (via octopus deploy) to Azure. On top of the Virtual Machines, I'm installing a number of extensions which culminates with a vm extension to register the VM with the Host Pool.
I'd like to rebuild the VM each time the custom script extension is applied (Extension #2, after domain join). But in rebuilding the VM, I'd like to build out a new VM, complete with the host pool registration before any part of the existing VM is destroyed.
Please accept the cut down version below to understand what I am trying to do.
I expect the largest number of machine recreations to come from enhancements to the configuration scripts that configure the server on creation. Not all of the commands are expected to be idempotent and we want the AVD vms to be ephemeral. If an issue is encountered, the support team is expected to be able to drain a server and destroy it once empty to get a replacement by terraform apply. In a case where the script gets updated though, we want to be able to replace all VMs quickly in an emergency, or at the very least minimize the nightly maintenance window.
Script Process: parameterized script > gets filled out as a template file > gets stored as an az blob > called by custom script extension > executed on the machine.
VM build process: VM is provisioned > currently 8 extensions get applied one at a time, starting with the domain join, then the custom script extension, followed by several Azure monitoring extensions, and finally the host pool registration extension.
I've been trying to use the create_before_destroy lifecycle feature, but I can't get it to spin up the VM, and apply all extensions before it begins removing the hostpool registration from the existing VMs. I assume there's a way to do it using the triggers, but I'm not sure how to do it in such a way that it always has at least the current number of VMs.
It would also need to be able to stop if it encounters an error on the new vm, before destroying the existing vm (or better yet, be authorized to rebuild VMs if an extension fails part way through).
resource "random_pet" "avd_vm" {
prefix = var.client_name
length = 1
keepers = {
# Generate a new pet name each time we update the setup_host script
source_content = "${data.template_file.setup_host.rendered}"
}
}
data "template_file" "setup_host" {
template = file("${path.module}\\scripts\\setup-host.tpl")
vars = {
storageAccountName = azurerm_storage_account.storage.name
storageAccountKey = azurerm_storage_account.storage.primary_access_key
domain = var.domain
aad_group_name = var.aad_group_name
}
}
resource "azurerm_storage_blob" "setup_host" {
name = "setup-host.ps1"
storage_account_name = azurerm_storage_account.scripts.name
storage_container_name = time_sleep.container_rbac.triggers["name"]
type = "Block"
source_content = data.template_file.setup_host.rendered #"${path.module}\\scripts\\setup-host.ps1"
depends_on = [
azurerm_role_assignment.account1_write,
data.template_file.setup_host,
time_sleep.container_rbac
]
}
data "template_file" "client_r_drive_mapping" {
template = file("${path.module}\\scripts\\client_r_drive_mapping.tpl")
vars = {
storageAccountName = azurerm_storage_account.storage.name
storageAccountKey = azurerm_storage_account.storage.primary_access_key
}
}
resource "azurerm_windows_virtual_machine" "example" {
count = length(random_pet.avd_vm)
name = "${random_pet.avd_vm[count.index].id}"
...
lifecycle {
ignore_changes = [
boot_diagnostics,
identity
]
}
}
resource "azurerm_virtual_machine_extension" "first-domain_join_extension" {
count = var.rdsh_count
name = "${var.client_name}-avd-${random_pet.avd_vm[count.index].id}-domainJoin"
virtual_machine_id = azurerm_windows_virtual_machine.avd_vm.*.id[count.index]
publisher = "Microsoft.Compute"
type = "JsonADDomainExtension"
type_handler_version = "1.3"
auto_upgrade_minor_version = true
settings = <<SETTINGS
{
"Name": "${var.domain_name}",
"OUPath": "${var.ou_path}",
"User": "${var.domain_user_upn}#${var.domain_name}",
"Restart": "true",
"Options": "3"
}
SETTINGS
protected_settings = <<PROTECTED_SETTINGS
{
"Password": "${var.admin_password}"
}
PROTECTED_SETTINGS
lifecycle {
ignore_changes = [settings, protected_settings]
}
depends_on = [
azurerm_virtual_network_peering.out-primary,
azurerm_virtual_network_peering.in-primary,
azurerm_virtual_network_peering.in-secondary
]
}
# Multiple scripts called by ./<scriptname referencing them in follow-up scripts
# https://web.archive.org/web/20220127015539/https://learn.microsoft.com/en-us/azure/virtual-machines/extensions/custom-script-windows
# https://learn.microsoft.com/en-us/azure/virtual-machines/extensions/custom-script-windows#using-multiple-scripts
resource "azurerm_virtual_machine_extension" "second-custom_scripts" {
count = var.rdsh_count
name = "${random_pet.avd_vm[count.index].id}-setup-host"
virtual_machine_id = azurerm_windows_virtual_machine.avd_vm.*.id[count.index]
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.10"
auto_upgrade_minor_version = "true"
protected_settings = <<PROTECTED_SETTINGS
{
"storageAccountName": "${azurerm_storage_account.scripts.name}",
"storageAccountKey": "${azurerm_storage_account.scripts.primary_access_key}"
}
PROTECTED_SETTINGS
settings = <<SETTINGS
{
"fileUris": ["https://${azurerm_storage_account.scripts.name}.blob.core.windows.net/scripts/setup-host.ps1","https://${azurerm_storage_account.scripts.name}.blob.core.windows.net/scripts/client_r_drive_mapping.ps1"],
"commandToExecute": "powershell -ExecutionPolicy Unrestricted -file setup-host.ps1"
}
SETTINGS
depends_on = [
azurerm_virtual_machine_extension.first-domain_join_extension,
azurerm_storage_blob.setup_host
]
}
resource "azurerm_virtual_machine_extension" "last_host_extension_hp_registration" {
count = var.rdsh_count
name = "${var.client_name}-${random_pet.avd_vm[count.index].id}-avd_dsc"
virtual_machine_id = azurerm_windows_virtual_machine.avd_vm.*.id[count.index]
publisher = "Microsoft.Powershell"
type = "DSC"
type_handler_version = "2.73"
auto_upgrade_minor_version = true
settings = <<-SETTINGS
{
"modulesUrl": "https://wvdportalstorageblob.blob.core.windows.net/galleryartifacts/Configuration_3-10-2021.zip",
"configurationFunction": "Configuration.ps1\\AddSessionHost",
"properties": {
"HostPoolName":"${azurerm_virtual_desktop_host_pool.pooleddepthfirst.name}"
}
}
SETTINGS
protected_settings = <<PROTECTED_SETTINGS
{
"properties": {
"registrationInfoToken": "${azurerm_virtual_desktop_host_pool_registration_info.pooleddepthfirst.token}"
}
}
PROTECTED_SETTINGS
lifecycle {
ignore_changes = [settings, protected_settings]
}
depends_on = [
azurerm_virtual_machine_extension.second-custom_scripts
]
}

Terraform: Error when creating azure kubernetes service with local_account_disabled=true

An error occurs when I try to create a AKS with Terraform. The AKS was created but the error still comes at the end, which is ugly.
│ Error: retrieving Access Profile for Cluster: (Managed Cluster Name
"aks-1" / Resource Group "pengine-aks-rg"):
containerservice.ManagedClustersClient#GetAccessProfile: Failure responding to request:
StatusCode=400 -- Original Error: autorest/azure: Service returned an error. Status=400
Code="BadRequest" Message="Getting static credential is not allowed because this cluster
is set to disable local accounts."
This is my terraform code:
terraform {
required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = "=2.96.0"
}
}
}
resource "azurerm_resource_group" "aks-rg" {
name = "aks-rg"
location = "West Europe"
}
resource "azurerm_kubernetes_cluster" "aks-1" {
name = "aks-1"
location = azurerm_resource_group.aks-rg.location
resource_group_name = azurerm_resource_group.aks-rg.name
dns_prefix = "aks1"
local_account_disabled = "true"
default_node_pool {
name = "nodepool1"
node_count = 3
vm_size = "Standard_D2_v2"
}
identity {
type = "SystemAssigned"
}
tags = {
Environment = "Test"
}
}
Is this a Terraform bug? Can I avoid the error?
If you disable local accounts you need to activate AKS-managed Azure Active Directory integration as you have no more local accounts to authenticate against AKS.
This example enables RBAC, Azure AAD & Azure RBAC:
resource "azurerm_kubernetes_cluster" "aks-1" {
...
role_based_access_control {
enabled = true
azure_active_directory {
managed = true
tenant_id = data.azurerm_client_config.current.tenant_id
admin_group_object_ids = ["OBJECT_IDS_OF_ADMIN_GROUPS"]
azure_rbac_enabled = true
}
}
}
If you dont want AAD integration you need set local_account_disabled = "false".

Azure Virtual Machine Extension fileUris path with Terraform

Need to implement VM extension, using Terraform and Azure DevOps.I am trying to pass fileUris value from .tfvars or create Dynamically from storage account details ["https://${var.Storageaccountname}.blob.core.windows.net/${var.containername}/test.sh"], Both the scenarios are not working.
resource "azurerm_virtual_machine_extension" "main" {
name = "${var.vm_name}"
location ="${azurerm_resource_group.resource_group.location}"
resource_group_name = "${azurerm_resource_group.resource_group.name}"
virtual_machine_name = "${azurerm_virtual_machine.vm.name}"
publisher = "Microsoft.Azure.Extensions"
type = "CustomScript"
type_handler_version = "2.0"
settings = <<SETTINGS
{
"fileUris" :"${var.fileUris}",
"commandToExecute": "sh <name of file> --ExecutionPolicy Unrestricted\""
}
SETTINGS
}
Any tips on fixing this issue? Maybe some other solution to achieve zero hardcoding in main.tf/variable.tf?
You could refer to this working sample to deploy the extension on Linux VM. The script file stored a Storage account.
resource "azurerm_virtual_machine_extension" "test" {
name = "test-LinuxExtension"
virtual_machine_id = "/subscriptions/xxx/virtualMachines/www"
publisher = "Microsoft.Azure.Extensions"
type = "CustomScript"
type_handler_version = "2.1"
auto_upgrade_minor_version = true
protected_settings = <<PROTECTED_SETTINGS
{
"commandToExecute": "sh aptupdate.sh",
"storageAccountName": "xxxxx",
"storageAccountKey": "xxxxx",
"fileUris": [
"${var.fileUris}"
]
}
PROTECTED_SETTINGS
}
If we store the script in Azure blob storage, we need to provide storage key then the extension can have permission to access the script. For more details, please refer to here. Please add the following setting in your script
...
protected_settings = <<PROTECTED_SETTINGS
{
"storageAccountName": "mystorageaccountname",
"storageAccountKey": "myStorageAccountKey"
}
PROTECTED_SETTINGS
...

Defining Azure VM CustomScriptExtension in Terraform (Expecting state 'Element'.. Encountered 'Text' with name '', namespace ''. \".")

I defined a CustomScriptExtension for Azure VM in Terraform:
resource "azurerm_virtual_machine_extension" "test" {
name = "WinRM"
location = "South Central US"
resource_group_name = "${azurerm_resource_group.test.name}"
virtual_machine_name = "${azurerm_virtual_machine.test.name}"
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.8"
settings = <<SETTINGS
{
"fileUris": "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1",
"commandToExecute": "powershell.exe -ExecutionPolicy Unrestricted -File ConfigureRemotingForAnsible.ps1"
}
SETTINGS
}
However I get (the same error is visible in Azure portal in VM extensions):
azurerm_virtual_machine_extension.test: compute.VirtualMachineExtensionsClient#CreateOrUpdate: Failure sending request: StatusCode=200 -- Original Error: Long running operation terminated with status 'Failed': Code="VMExtensionProvisioningError" Message="VM has reported a failure when processing extension 'WinRM'. Error message: \"Invalid handler configuration. Exiting. Error Message: Expecting state 'Element'.. Encountered 'Text' with name '', namespace ''. \"."
The same parameters executed as an Azure deployment works with no problems (relevant excerpts below):
"fileUris": {
"type": "string",
"defaultValue": "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1",
"metadata": {
"description": "The uri list of files. Split by a space."
}
},
"settings": {
"fileUris": "[split(parameters('fileUris'), ' ')]",
"commandToExecute": "[parameters('commandToExecute')]"
}
Am I missing something, or is it a bug in Terraform?
Some debugging:
If I replace the settings with just:
{
"commandToExecute": "mkdir C:\\Test"
}
the directory gets created, so the problem is with fileUris.
If I replace fileUris in the settings JSON with fileUri (which should be wrong):
{
"fileUri": "https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1",
"commandToExecute": "powershell.exe -ExecutionPolicy Unrestricted -File ConfigureRemotingForAnsible.ps1"
}
there is no the Encountered 'Text' with name '', namespace ''. \". error, powershell.exe fires and reports missing ConfigureRemotingForAnsible.ps1.
Error message: \"Invalid handler configuration. Exiting. Error Message: Expecting state 'Element'.. Encountered 'Text' with name '', namespace ''. \"."
As I known, the value type of fileUris should be an array, I have tested it with Azure deployment, if I configure fileUris as a string value, then I could get the same error as you provided.
UPDATE
The fileUris should look like as follows:
"settings": {
"fileUris": [
"https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
],
"commandToExecute": "powershell.exe -ExecutionPolicy Unrestricted -File ConfigureRemotingForAnsible.ps1"
}
Here is an terraform example , just copy-paste it... I commented the RG section along with location ( from case to case, you might not need it ) :
resource "azurerm_virtual_machine_extension" "win-installansibleclient" {
name = "${var.current-name-convention-core-module}-mtwin-installansibleclient"
#location = "${var.preferred-location-module}"
#resource_group_name = "${var.current-name-convention-core-module}-rg"
virtual_machine_id = "${azurerm_virtual_machine.dcaddns-w2k16.id}"
publisher = "Microsoft.Compute"
type = "CustomScriptExtension"
type_handler_version = "1.8"
settings = <<SETTINGS
{
"fileUris": [
"https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"
],
"commandToExecute": "powershell.exe -ExecutionPolicy Unrestricted -File ConfigureRemotingForAnsible.ps1"
}
SETTINGS
}

Resources