I have a Powershell Azure Automation runbook that remotes into a machine to update some configuration. The runbook seems to work properly when run from Azure, but fails with an authentication error when run from a Hybrid Worker.
The whole reason for having the Hybrid Worker was so I could secure the PSRemoting ports to known hosts, so this is a bit of a bummer.
The main runbook is triggered via webhook, and that calls a child runbook using dot-notation, which calls...
$creds = Get-AutomationPSCredential -Name 'DeploymentCredentials'
$sessionOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
Invoke-Command -ConnectionUri "https://$($FQDN):5986" -Credential $creds -SessionOption $sessionOptions -ScriptBlock {
$h = hostname
Write-Output "Running on $h"
}
In this case, $FQDN is supplied as a parameter of course.
The error being reported is:
Connecting to remote server
my-server.australiaeast.cloudapp.azure.com failed with the following error message : Access is denied. For more
information, see the about_Remote_Troubleshooting Help topic.
CategoryInfo : OpenError: (my-server.au...udapp.azure.com:String) [], PSRemotingTransportException
FullyQualifiedErrorId : AccessDenied,PSSessionStateBroken
I can manually execute the same code from ISE without issue from the hybrid worker so I know it's not a firewall issue, and I have the credentials writing to the output window so I know they are correct too.
I presume this is something to do with the fact the PowerShell function executes under the system account?
Thx
Answering my own question for posterity.
Altering the Hybrid Worker Group to run using credentials for a machine admin allowed the setup to work; where using the "Default" credentials (System account I believe) did not.
I think in Windows the System account is not allowed to connect to other machines/services so this may be why, but I'm guessing there.
Related
Instead of using Connect-AzAccount, I'm using a profile saved locally on my Hybrid Worker
to authenticate against Azure and loading it each time I run a runbook.
This approach works, but after 2 or 3 successful runs, all the following runbook jobs end up in Suspended state.
Unfortunately, jobs stop working so randomly that I just can't pinpoint a possible cause.
The auth code inside the runbook:
$profile = Import-AzContext -path $path
$subscriptionID = $profile.Context.Subscription.SubscriptionID
Set-AzContext -subscriptionID $subscriptionID
Running Get-AzContext locally confirms that the credentials & context are loaded, but Microsoft-SMA logs show an auth error (407 proxy).
Is there maybe a scope that I should set? Expiration time that I don't know about?
Should I maybe clear the context after each job run?
Any input would be appreciated.
Start by running Clear-AzContext at the beginning of your runbook to ensure any inherited contexts are cleared, or Disconnect-AzAccount at the end of your runbook. Per Microsoft:
By default, the Azure contexts are saved for use between PowerShell sessions. It is possible that when a previous runbook on the Hybrid Runbook Worker has been authenticated with Azure, that context persists to the disk in the System PowerShell profile, as per Azure contexts and sign-in credentials | Microsoft Docs. For instance, a runbook with Get-AzVM can return all the VMs in the subscription with no call to Connect-AzAccount, and the user would be able to access Azure resources without having to authenticate within that runbook. You can disable context autosave in Azure PowerShell, as detailed here.
If that doesn't resolve the issue I would enable Progress logging and step through the runbook to identify which part is causing the issue.
I'm trying to setup a Powershell Runbook to access Azure resources.
I'm following instructions on this page.
I've assigned a system identity to the Automation account, the the sample script simply doesn't work.
# Sign in to your Azure subscription
$sub = Get-AzSubscription -ErrorAction SilentlyContinue
if(-not($sub))
{
Connect-AzAccount
}
Output:
Run Connect-AzAccount to login.
Port 8400 is taken with exception 'A socket operation encountered a dead network'; trying to connect to the next port.
Port 8401 is taken with exception 'A socket operation encountered a dead network'; trying to connect to the next port.
<snip>
Port 8998 is taken with exception 'A socket operation encountered a dead network'; trying to connect to the next port.
Port 8999 is taken with exception 'A socket operation encountered a dead network'; trying to connect to the next port.
Unable to acquire token for tenant 'organizations' with error 'Cannot find an open port.'
Cannot find an open port.
I tried adding Contributor and Owner role to the identity, and that didn't help.
I'm not sure what I'm missing, help?
I am using terraform to stand up the infrastructure, so it's possible I have a setting out of whack that terraform is setting.
The snippet of code you have used is for authentication to enable the identity.
The snippet of code further down that page is what you need to use:
https://learn.microsoft.com/en-us/azure/automation/enable-managed-identity-for-automation#authenticate-access-with-system-assigned-managed-identity
You'll notice it utilises Connect-AzAccount -Identity instead.
# Ensures you do not inherit an AzContext in your runbook
Disable-AzContextAutosave -Scope Process
# Connect to Azure with system-assigned managed identity
$AzureContext = (Connect-AzAccount -Identity).context
# set and store context
$AzureContext = Set-AzContext -SubscriptionName $AzureContext.Subscription -DefaultProfile $AzureContext
I think this is an Azure problem, but I am not confident. Today all my deployments from Octopus stopped working. I am getting an error in the logs that makes me feel like its an authentication issue. I checked the key in Azure didnt expire. If I click the Save and Test button in Octopus its successful. I even made a new app, assigned permissions in Azure and set it up in OCtopus and deployed using that account. Same problem.
If I login to Powershell using the Service Principle, I can run commands everything is good, but every job is getting this error which seems like an account issue. I am currently looking at the Azure side, but nothing yet, so I thought I would ask this community as well.
pushd $env:OctopusCalamariWorkingDirectory
try {
If ([System.Convert]::ToBoolean($OctopusUseServicePrincipal)) {
# Authenticate via Service Principal
$securePassword = ConvertTo-SecureString $OctopusAzureADPassword -AsPlainText -Force
$creds = New-Object System.Management.Automation.PSCredential ($OctopusAzureADClientId, $securePassword)
# Turn off context autosave, as this will make all authentication occur in memory, and isolate each session from the context changes in other sessions
Disable-AzureRMContextAutosave -Scope Process
$AzureEnvironment = Get-AzureRmEnvironment -Name $OctopusAzureEnvironment
if (!$AzureEnvironment) {
Write-Error “No Azure environment could be matched given the name $OctopusAzureEnvironment”
exit -2
}
...
Update 1:
Added info, I expanded the logs to Verbose and noticed this
Performing variable substitution on ‘F:\Octopus\Work\20201030000719-612-78\AppServiceEnvironment-Octopus\ase.ps1’
Attempt 1 of 5 failed: No Azure environment could be matched given the name AzureCloud
Almost like the variable substitution stopped working? Could be a red herring, but figured I would add the information.
Update 2:
I added OctopusPrintEvaluatedVariables and OctopusPrintVariables and set them to True and can see the variables are created right. It seems to be something with the connection between Azure and Octopus that stopped working
I am having questions around the "Stop-AzureRmVm" PowerShell cmdlet. Does the cmdlet power crash the virtual machines? I have few SharePoint and SQL servers used in our non-production environment. I have powershell scripts that do a scheduled stop and start of these virtual machines.
I am worried if the "Stop-AzureRmVm" PowerShell cmdlet power crashes the virtual machines, as I need the servers to gracefully shutdown.
OR do we have any PowerShell cmdlet that gracefully shuts down the Azure virtual machine?
As long as you are not sending the -force parameter, Azure will attempt to gracefully shutdown the guest OS before stopping. If that doesn't work, the -force parameter is akin to "pulling the plug".
Dont worry, the command Stop-AzureRmVm will gracefully shut down the VM.
If you catch the request of the Stop-AzureRmVm and the Stop option of the VM in the portal, you will find essentially they all call the Virtual Machines - Deallocate REST API, it means if you use the powershell command, it is no difference with that in the portal.
Sorry to revive an old question, but Ken W's accepted answer here is not accurate. The -Force parameter only prevents a Yes/No prompt when running the cmdlet (this is useful for when running in an automated script which cannot accept user input). Either way, running Stop-AzureRmVm will always attempt a graceful shutdown.
The newer 'Az' version of this cmdlet (Stop-AzVM) does have a -SkipShutdown option which will skip any attempt at a graceful shutdown, and will immediately deallocate the VM. More details can be found in the following link:
https://learn.microsoft.com/en-us/powershell/module/az.compute/stop-azvm
I have a Jenkins machine running builds, but I would like to run scripts as alternative users across Operating Systems on my Jenkins slaves.
I can do this on my GNU/Linux boxes using symmetrical keys and authorized_keys in ssh, but I am having quite a lot of trouble doing the same on some Windows machines.
I would like to use Powershell to run the commands I am interested in.
I am getting Access Denied errors as the user I would like to have run a specific command. I can run Invoke-Command with Get-Credential with an AD administrative account, and it works correctly but not as other AD users, so I know winrm is running as it should.
How do I add a specific AD user to run Invoke-Command or Enter-PSSession on a specific host?
And related to that question, How does the AD Admin have access to any machine running winrm? Can I emulate that in some way locally for one user on a targeted machine?
If you're authenticating like this then you'll need to export a new file for each authenticating user, and after password changes:
read-host -assecurestring | convertfrom-securestring | out-file UserOneSecureString.txt
I'll beg off the more general parts of your question with docs for about_remote and about_remote_troubleshooting, which you've may've seen.
After a bit of reading, this question can be reduced to Impersonating a domain user on a host in Powershell non-interactively.
Impersonating a domain user on a host in Powershell non-interactively
To impersonate a user in powershell non-interactively you must do the following:
Enable Powershell Remoting
Add User to PowerShell PSSessionConfiguration
Enable CredSSP on Host (As client and server)
Export Asymmetrical Key of Domain user
Initiate session with Credssp authentication
Enable Powershell Remoting
The host we will use needs to have Windows Remote Management enabled, there is a powershell command to do all the work for you.
Enable-PSRemoting -Force
Add User to PowerShell PSSessionConfiguration
If the user is not an administrator on the host, you must add it to the Powershell Session Configuration. You can then control what kind of access you would like to give to the user on that host.
Set-PSSessionConfiguration Microsoft.PowerShell -ShowSecurityDescriptorUI
Enable CredSSP on Host (As client and server)
Credssp deals with the double-hop or second-hop issue on Microsoft products.
This allows credential forwarding to occur for users to access services that may not be on the local host, such as network shares.
In many cases, this is an issue when logging into machine B from machine A and needing a resource on machine C.
In this case, machine A and B are the same host, so we enable Credssp on the host as both the Client and Server roles.
Enable-WSManCredSSP -Role Client -Delegate $env:COMPUTERNAME
Enable-WSManCredSSP -Role Server
Export Asymmetrical Key of Domain user
This is mentioned in one of the answers by 'noam'.
An asymmetrical key can be used by exporting the domain user's password to a file.
Then, the file can be read and a new powershell session can be started on the host.
Read-Host -AsSecureString "Write the password: " | ConvertFrom-SecureString | Out-File C:\somelocation\users-pass-key-file.txt
Initiate session with Credssp authentication
Now you can initiate a non-interactive login session in Powershell by reading the file with the key, and logging into the host.
$user = "DOMAIN\username"
$passkey = Get-Content C:\somelocation\users-pass-key-file.txt | ConvertTo-SecureString
$credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $user,$passkey
Invoke-Command -ComputerName $env:COMPUTERNAME -ScriptBlock { Write-Output $env:USERNAME } -Credential $credential -Authentication Credssp
Using Jenkins with impersonated user
After doing the previous steps you can use your Jenkins slaves or master to execute Powershell commands on behalf of another user.
This will have to be done by running Invoke-Command with the appropriate preface using the credentials stored on the host in question.