Azure / bicep-types-az

Bicep type definitions for ARM resources
MIT License
84 stars 27 forks source link

Unable to perform managed runcommand deployed via bicep #2102

Open marshalexander99 opened 7 months ago

marshalexander99 commented 7 months ago

Bicep version v0.25.23

Describe the bug Deploying the runcommand resource against a VM using a domain joined run as account to perform activity on the domain fails. In this case it is simply a script calling the get-addomain command on a domain controller to retrieve domain info to pass to an azure command.

Bicep resource

resource domainjoinstorage 'Microsoft.Compute/virtualMachines/runCommands@2023-09-01' = {
  name: 'domainjoin${storageaccount}'
  location: deploymentLocation
  parent: taskvm
  properties: {
    source: {
      scriptUri: 'https://${scriptsa}.blob.${environment().suffixes.storage}/config/Script-DomainJoinStorage.ps1'
      scriptUriManagedIdentity: {
        clientId: umi
      }
    }
    parameters: stdparamters
    errorBlobUri: 'https://${scriptsa}.blob.${environment().suffixes.storage}/config/error-${storageaccount}-${date}.txt'
    errorBlobManagedIdentity: {
      clientId: umi
    }
    outputBlobUri: 'https://${scriptsa}.blob.${environment().suffixes.storage}/config/output-${storageaccount}-${date}.txt'
    outputBlobManagedIdentity: {
      clientId: umi
    }
    runAsUser: '${domain}\\${domainUsername}'
    runAsPassword:runaspassword
    timeoutInSeconds: 300
  }
  dependsOn: [
    installmanagementmodules
  ]
}

Powershell script being called

param(
    [string] $StorageAccountName,
    [string] $StorageAccountRG,
    [string] $ClientId,
    [string] $SubscriptionId,
    [string] $OUName
)
$ErrorActionPreference = 'stop'
whoami

$spn = "cifs/" + $StorageAccountName + "file.core.windows.net"
$domain = get-addomain
write-host "got $domain.dnsroot info"

if (test-path HKLM:\SOFTWARE\360) {

Write-host "Connecting to managed identity account"
try {
Connect-AzAccount -Identity -AccountId $ClientId -WarningAction:SilentlyContinue
Write-host "Setting Azure subscription to $SubscriptionId"
Select-AzSubscription -SubscriptionId $SubscriptionId
write-host "subscription set"
}
catch {
[System.Exception]
throw $_
}

#get storage account key
try {
New-AzStorageAccountKey -ResourceGroupName $StorageAccountRG -Name $StorageAccountName -KeyName kerb1
$key = ConvertTo-SecureString -AsPlainText ((Get-AzStorageAccountKey -ResourceGroupName $StorageAccountRG -Name $StorageAccountName -ListKerbKey | where-object{$_.Keyname -contains "kerb1"}).value) -force
}
catch {
[System.Exception]
throw $_
}

try {
$computer = New-ADComputer -name $StorageAccountName -samaccountname $StorageAccountName -path $OUName -KerberosEncryptionType "AES256" -accountpassword $key -ServicePrincipalNames $spn -passthru
}
catch {[System.Exception]
write-error "unable to create computer account"
throw $_
}

try {
write-host "configuring storage account"
    set-azstorageaccount -ResourceGroupName $StorageAccountRG -Name $StorageAccountName `
    -EnableActiveDirectoryDomainServicesForFile $true `
    -ActiveDirectoryDomainName $domain.dnsroot `
    -ActiveDirectoryNetBiosDomainName $domain.dnsroot `
    -ActiveDirectoryForestName $domain.forest `
    -ActiveDirectoryDomainGuid $domain.objectguid `
    -ActiveDirectoryDomainsid $domain.domainsid `
    -ActiveDirectoryAzureStorageSid $computer.sid `
    -ActiveDirectorySamAccountName $StorageAccountName `
    -ActiveDirectoryAccountType "computer"
}
catch {[System.Exception]
write-error "unable to set storage account"
write-error $_
}

#mount file share to set permissions
$DriveLetter = 'Y'
$FileShareLocation = '\\' + $StorageAccountName + "file.core.windows.net" + '\data'
$connectTestResult = Test-NetConnection -ComputerName "$StorageAccountName.file.core.windows.net" -Port 445
if ($connectTestResult.TcpTestSucceeded){
try {
Write-Host "mapping drive to set permissions"
    $UserStorage = "/user:Azure\$StorageAccountName"
    $StorageKey = (Get-AzStorageAccountKey -ResourceGroupName $StorageAccountRG -AccountName $StorageAccountName) | Where-Object { $_.KeyName -eq "key1" }
    net use ${DriveLetter}: $FileShareLocation $UserStorage $StorageKey.Value
}
Catch {[System.Exception]
write-error "failed to connect to storage"
write error $_
}

#configure permissions
try {
write-host "assign permissions"
    #$fcgroup = $domain.dnsroot + '\admins'
    #$ragroup = $domain.dnsroot + '\read'
    #icacls ${DriveLetter}: /grant $fcgroup
    #icacls ${DriveLetter}: /grant $ragroup
    net use ${DriveLetter} /delete
}
catch {[System.Exception]
write-error "failed to set permissions"
write error $_
}
}
}

Error message produced:

Attempting to perform the InitializeDefaultDrives operation on the 'ActiveDirectory' provider failed.

get-addomain : Server instance not found on the given port.

At C:\Packages\Plugins\Microsoft.CPlat.Core.RunCommandHandlerWindows\2.0.8\Downloads\Script_domainjoinsticihdjtest_0.ps
1:12 char:11
+ $domain = get-addomain
+           ~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (COMPANY:ADDomain) [Get-ADDomain], ArgumentException
    + FullyQualifiedErrorId : ActiveDirectoryCmdlet:System.ArgumentException,Microsoft.ActiveDirectory.Management.Comm 
   ands.GetADDomain

To Reproduce deploy the above resource to use the script against a domain controller. Running against a server with AD PowerShell installed produces the following error:

get-addomain : Unable to contact the server. This may be because this server does not exist, it is currently down, or 

it does not have the Active Directory Web Services running.

At C:\Packages\Plugins\Microsoft.CPlat.Core.RunCommandHandlerWindows\2.0.8\Downloads\Script_domainjoinsticihdjtest_7.ps

1:11 char:11

+ $domain = get-addomain

+           ~~~~~~~~~~~~

    + CategoryInfo          : ResourceUnavailable: (COMPANY:ADDomain) [Get-ADDomain], ADServerDownException

    + FullyQualifiedErrorId : ActiveDirectoryServer:0,Microsoft.ActiveDirectory.Management.Commands.GetADDomain

Additional context I suspect the issue here is with the managed run command execution not performing elevation however I cannot see anywhere else to log this. Now I obviously don't want to have to run any domain commands against a domain controller in azure, a management server would be preferable but there seems to be a double hop employed when going via that route based off the error above. All the commands function perfectly when run locally. The mechanism employed here has some limitations which aren't well documented. We wanted to use this method as it allows multiple commands to be run. custom script extensions require deployment and removal in order to use again. This is part of a hosted environment where multiple resources are deployed for customers to add some context.

shenglol commented 7 months ago

The error seems to be specific to the resource provider. @marshalexander99 do you mind opening a support ticket against the Microsoft.Compute provider?

marshalexander99 commented 7 months ago

Where's the best place to do that, Azure portal? The above is currently in a visual studio subscription for development purposes so I only have paid support options.

shenglol commented 7 months ago

Yeah, you should be able to create a support request through portal.

marshalexander99 commented 7 months ago
image

unfortunately not

stephaniezyen commented 6 months ago

Unfortunately, creating a support ticket is not possible without a paid subscription, but this is an RP issue, we'll try to route it to the correct team