I am trying to setup a powershell code which would update the storage account credentials every once in a while and below is the script that I have come across and it works perfectly fine.
function setupContext(){
Add-AzureRmAccount
Save-AzureRmContext -Path “path\to\json\file”
}
#setupContext
Import-AzureRmContext -Path “path\to\json\file”
$subscriptionId='***********************************'
Select-AzureRMSubscription -SubscriptionId $subscriptionId -WarningAction SilentlyContinue
$resourceGroup="**************"
$storageAccountName="******************"
$BLOBKey= New-AzureRmStorageAccountKey -ResourceGroupName $resourceGroup -Name $storageAccountName -KeyName key2
Write-Host "BLOB Key:"$BLOBKey.Keys[0]
The above code does the required work, however it requires us to login to the azure-rm account which basically defeats the idea of automating this process since I would need keep updating this generated profile.
Note: I am not allowed to use az module as of now since the environment in which I work has some .NET version limitations.
So if there any other solution which could overcome the azure rm login issue, please suggest.
Use Azure Automation. This automatically sets up something called RunAs account. Which simply said is just Azure AD Service Principal.
Then assign this principal privileges on the storage account just like any other user and you are done.
And in the Automation Runbook do
$connection = Get-AutomationConnection -Name AzureRunAsConnection
Connect-AzureRmAccount `
-ServicePrincipal `
-Tenant $connection.TenantID `
-ApplicationID $connection.ApplicationID `
-CertificateThumbprint $connection.CertificateThumbprint
$AzureContext = Select-AzureRmSubscription -SubscriptionId $connection.SubscriptionID
... run rest of the code ...
If you want to run this from outside of Azure like on-prem server then set up manually service principal. Here is guide
https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-create-service-principal-portal
And just log into this app from powershell instead of the user.
Looks you want to use a non-interactive way to do that automatically. To access the azure resource with a non-interactive way, your best option currently is to use the service principal(AD App).
An Azure service principal is an identity created for use with applications, hosted services, and automated tools to access Azure resources.
The other reply is for azure automation runbook, you could follow my steps to automate it in other places else.
1.Create an Azure Active Directory application and create a secret for the app, save the secret and get values for signing in.
2.Navigate to the storage account(or the subscription which the storage account located) in the portal -> Access control (IAM) -> Add -> Add role assignment -> search your service principal(AD App) with name and add it as a role(e.g. Owner/Contributor) -> Save.
Note: To give the role, you need to use an account which is an Owner of the specific scope(storage account/subscription).
3.Then use the script as below, replace the specific properties with the values in step 1.
function setupContext(){
$azureAplicationId ="<application id>"
$azureTenantId= "<tenant id>"
$azurePassword = ConvertTo-SecureString "<client secret>" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAplicationId , $azurePassword)
Add-AzureRmAccount -Credential $psCred -TenantId $azureTenantId -ServicePrincipal
Save-AzureRmContext -Path “path\to\json\file”
}
#setupContext
Import-AzureRmContext -Path “path\to\json\file”
$subscriptionId='***********************************'
Select-AzureRMSubscription -SubscriptionId $subscriptionId -WarningAction SilentlyContinue
$resourceGroup="**************"
$storageAccountName="******************"
$BLOBKey= New-AzureRmStorageAccountKey -ResourceGroupName $resourceGroup -Name $storageAccountName -KeyName key2
Write-Host "BLOB Key:"$BLOBKey.Keys[0]
Besides, if you want to learn more about the service principal, you could take a look at this link - Application and service principal objects in Azure Active Directory
Related
I am trying to automate the creation of certain azure resources via an Azure PowerShell script that is triggered from an Azure DevOps release pipeline. I want to create a function app, and automatically integrate reading right access to secrets in an already existing Key Vault. This Key Vault is in the same Azure subscription.
While I can create most resources following the documentation, there seems to be a lack of documentation regarding the creation of certain resources using Azure PowerShell (or I can't find it).
If I follow the sample from this link, I can accomplish it without a problem by using the UI in the Azure Portal, but I can't find any documentation on Microsoft Docs to do it using PowerShell.
Write-Host "Creating Function App..."
$fnApp = New-AzFunctionApp -Name $functionAppName `
-ResourceGroupName $emailFunctionRg `
-Location "$(AzureRegion)" `
-StorageAccount $storageName `
-Runtime dotnet `
-FunctionsVersion '3' `
-IdentityType SystemAssigned
Write-Host "Function App created!"
Write-Host "Assigning Key Vault access..."
$appId = Get-AzADServicePrincipal -DisplayName $functionAppName
Set-AzKeyVaultAccessPolicy -VaultName EmailSettings -ServicePrincipalName $appId -PermissionsToSecrets Get,List
Write-Host "Key Vault access granted!"
Running Set-AzKeyVaultAccessPolicy fails with "Insufficient privileges to complete the operation.". But I am not sure if this is the right path to follow, it was just a guess, based on the available functions in the documentation.
Any ideas?
Two potential issues to check out here:
your app creation assigns the result to $fnApp. perhaps $fnApp or as commented above, $fnApp.ApplicationId is what you should be using for the -ServicePrincipalName parameter on the access policy grant.
you don't have privileges to assign RBAC roles. Go to the Key Vault, choose Access Control, then click the Role Assignments tab and verify that your user appears in the list as an Administrator, User Access Administrator, or Owner.
Edit: With respect to the RBAC privilege, since this is running in Azure Powershell from Azure DevOps, you need to check the role assignment for the Service Connection's service principal - under Azure Active Directory in the Azure Portal, look up the principal used to create the service connection, and make sure THAT gets the correct Role on the key vault.
After a little of trial and error I just came to the conclusion I was not using the right parameter for the Set-AzKeyVaultAccessPolicy cmdlet.
The following script will work (if the service principle running it has the appropriate role, like WaitingForGuacamole mentioned in his/her answer):
Write-Host "Creating Function App..."
$fnApp = New-AzFunctionApp -Name <FnAppName> `
-ResourceGroupName <ResourceGroupName> `
-Location <AzureRegion> `
-StorageAccount <StorageAccount> `
-Runtime dotnet `
-FunctionsVersion '3' `
-IdentityType SystemAssigned
Write-Host "Function App created!"
Write-Host "Assigning Key Vault access..."
Set-AzKeyVaultAccessPolicy -VaultName <NameOfTheKeyVault> -ObjectId (Get-AzADServicePrincipal -DisplayName <FnAppName>).Id -PermissionsToSecrets <Get, List, etc...>
Write-Host "Key Vault access granted!"
I need to upload files to an storage account without using SAS.
I create an "app registration" and give contributor access to the storage account.
If I want to upload files from powershell? How can I do it?
First az login? and then azcopy? Because I tried this way but ask me for a token
The Azure Powershell, Azure CLI and AzCopy are three different things, you should not mix them together.
If you want to use powershell to upload file with the service principal, after you create the App Registration, please get values for signing in, then create a new application secret.
In your storage account, the Contributor role is enough, but you should note, actually the Contributor does not have the permission to access the blob directly, it just let you get the context of the storage account, then use the context to access the blob, to access the blob directly, we need the Storage Blob Data Owner/Contributor as mentioned in the comment.
Then use the script below(the Get-Credential in another reply is an interactive way, here is a non-interactive way, usually, we use the service principal in a non-interactive way for the automation)
$azureAplicationId ="<Application-ID>"
$azureTenantId= "<Tenant-ID>"
$azurePassword = ConvertTo-SecureString "<Application-secret>" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAplicationId , $azurePassword)
Connect-AzAccount -Credential $psCred -TenantId $azureTenantId -ServicePrincipal
$context = (Get-AzStorageAccount -ResourceGroupName <group-name> -Name <storageaccount-name>).Context
Set-AzStorageBlobContent -Container <container-name> -File <localfile-path> -Blob <blob-name> -Context $context
You can use a Service Principal or a certificate to login using azcopy, and then copy your files to the storage account. Please reference this article for further information.
There are lots of ways to do this. Since you mentioned PowerShell, I'll use it in this example.
# The following assumes you have already created the App registration.
# Either through the portal, PS, whatever.
$creds = Get-Credential
# Uername = Application ID
# password = The service principle secret. You need to create this.
Connect-AzAccount `
-Credential $creds `
-Tenant $tenantId `
-ServicePrincipal
# you will need to get the storage accounts context.
# There are a few ways to do this I usually just get the storage account
$context = (Get-AzStorageAccount -Name $saName -ResourceGroupName $rgName).Context
# You will need to give the App Registration permissions to upload the blob.
# If you don't assign permissions this cmdlet will fail.
Set-AzStorageBlobContent `
-Container $containerName `
-File $filePath `
-Blob $blobName `
-Context $context
I am trying to add a subnet to SQL Server using Azure Az Module. The command I am using is
New-AzSqlServerVirtualNetworkRule -VirtualNetworkRuleName "newvnetrule1" -ServerName $sqlServer.ServerName -ResourceGroupName $sqlServer.ResourceGroupName -VirtualNetworkSubnetId $newsubnetId -ErrorAction Stop
I get an exception saying:
The client with object id does not have permission to perform this action
The object id belong to a SPN of name Azure SQL Virtual Network to Network Resource Provider.
I get the exact same issue while provisioning cosmos db account with ARM template only this time the erroneous SPN is Azure Cosmos DB Virtual Network to Network Resource Provider
Can anyone throw some light on this? The same code used to work fine. All the services are registered for the subnet too
The Owner role is enough, I test it on my side, it works fine.
$virtualNetworkSubnetId = "/subscriptions/xxxxxxx/resourceGroups/joynet/providers/Microsoft.Network/virtualNetworks/joysqlnet/subnets/default"
New-AzSqlServerVirtualNetworkRule -ResourceGroupName joynet -ServerName joyser -VirtualNetworkRuleName vnetrule1 -VirtualNetworkSubnetId $virtualNetworkSubnetId
To fix the issue, try to use Clear-AzContext to clear all the local account information, then use the script below to login again.
$azureAplicationId ="<Application ID>"
$azureTenantId= "<Tenant ID>"
$azurePassword = ConvertTo-SecureString "<Client secret>" -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAplicationId , $azurePassword)
Connect-AzAccount -Credential $psCred -TenantId $azureTenantId -ServicePrincipal
Then run (Get-AzContext).Account, make sure the Id is the same as the Application ID of the service principal you are using, also the Tenant ID of the service principal should be the same as the GUID in Tenants.
When i execute following command
Clear-AzureProfile
Connect-AzAccount -TenantID xxxxxxxxxxxxxxxxxxx
Set-AzContext -SubscriptionId xxxxxxxxxxxxxxxxxxx
in Azure PowerShell i get this error.
Set-AzContext : Please provide a valid tenant or a valid subscription.
At line:6 char:1
+ Set-AzContext -SubscriptionId xxxxxxxxxxxxxxxxxxx
and if i run the same command in Azure Cloud Shell it works
Name Account SubscriptionName Environment TenantId
xxxx xxxxxxx xxxx xxxx xxxx
I switched from free-trial to pay-as-you-go subscription and using credentials for pay-as-you-go in both environment but it doesn't work. can anyone help
Close your powershell and open a new one, or use Clear-AzContext, not Clear-AzureProfile. Then use Connect-AzAccount -Tenant xxxxx -Subscription xxxxx, it should work.
If you are cycling through subscriptions in the same tenant and don't want to have to sign in with Connect-AzAccount multiple times, the following worked for me to switch between subscriptions:
Remove-AzContext -InputObject (Get-AzContext) -Force | Out-Null;
$sub = Set-AzContext -Subscription $_.SubscriptionName;
Before adding the Remove-AzContext statement I was seeing that Set-AzContext was not actually switching the context to another subscription for some reason.
I used to have this problem too, and my solution was different that one provided on top of this.
Apparently, in our Azure Cloud Shell, we have several contexts available, so, we don't have to set the context (using Set-AzContext), but to switch to one or other context, using Select-AzContext)
I can list the contexts using
Get-AzContext -ListAvailable
Then choose one using the
Select-AzContext -Name ...
For-example, in scripts, I use this one-line command to switch to the subscription having ID $SubscriptionID :
Select-AzContext -name ((Get-AzContext -ListAvailable).Name -match $SubscriptionId)[0]
Not elegant, but efficient
I don't know why we are in such situation. Maybe because we are administrating using invited accounts from another tenant.
Hope this help someone in same situation than us.
I'm building my Azure Logic Apps worklow which is supposed to check some conditions and run following Powershell:
Stop-AzureWebsiteJob -Name MyWebsite -JobName MyWebJob
Start-AzureWebsiteJob -Name MyWebsite -JobName MyWebJob -JobType Continuous
The question is: what's the easiest way to invoke such script in Azure Logic Apps? It seems like there's no built in block/connector for Powershell so I'd like to know what are the possibilites. Or perhaps it might be easier to run az CLI command with similar operation
Finally I ended up with a solution which takes advantage of Azure Automation. From Azure Portal we can create new Resource typing in Automation:
Once the resource is created we can add new Runbook under runbooks tab:
Runbook can run Powershell Workflow and get authorized using AzureRunAsConnection option (details here). My sample Powershell which is supposed to restart WebJob an specific App Service looks like below:
Workflow RestartMyWebJob
{
$Conn = Get-AutomationConnection -Name AzureRunAsConnection
Add-AzureRMAccount -ServicePrincipal -Tenant $Conn.TenantID -ApplicationId $Conn.ApplicationID -CertificateThumbprint $Conn.CertificateThumbprint
$AzureContext = Select-AzureRmSubscription -SubscriptionId $Conn.SubscriptionID
$Apiversion = "2015-08-01"
$ResourceGroupName = 'My-Resource-Group-Name'
$ResourceName = 'My-Resource-Group-Name/My-AppService--WebJob-Name'
Invoke-AzureRmResourceAction -ResourceGroupName $ResourceGroupName -ResourceType Microsoft.Web/sites/ContinuousWebJobs -ResourceName $ResourceName -Action stop -ApiVersion $Apiversion -Force
Invoke-AzureRmResourceAction -ResourceGroupName $ResourceGroupName -ResourceType Microsoft.Web/sites/ContinuousWebJobs -ResourceName $ResourceName -Action start -ApiVersion $Apiversion -Force
}
Having this Workflow setup we can run it from Azure Logic Apps by adding new block to our logic.
Currently, azure logic seems not support to run powershell and cli script, here is a voice in azure feedback, you could vote it.
Workaround:
If you want to start and stop the webjob, you can call the Kudu WebJobs API in the logic app.
You can follow the steps below.
1.Run the powershell command locally to generate the Authorization token of your web app.
$creds = Invoke-AzureRmResourceAction -ResourceGroupName joywebapp -ResourceType Microsoft.Web/sites/config -ResourceName joywebapp2/publishingcredentials -Action list -ApiVersion 2015-08-01 -Force
$username = $creds.Properties.PublishingUserName
$password = $creds.Properties.PublishingPassword
$base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f $username, $password)))
The $base64AuthInfo is what we need, it should be like JGpveXdlYmFwcDI6NnJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzRktSdXlUcU5acUUzdFhNb05j.
The token will never be changed except you reset the publish profile, so you just need to do this step once.
2.In the logic app, specific the Method, URI, Headers(The header should be like
Authorization: Basic JGpveXdlYmFwcDI6NnJxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxzRktSdXlUcU5acUUzdFhNb05j, note use space to separate the Basic and token), for example , I start a triggered webjob in my web app.
Triggered result:
So you just need to follow the steps above, for your issue, refer to the APIS:
Start a continuous job
Stop a continuous job
Create an Azure Function with an http trigger with Powershell as the function language (or any other supported language). Then you call the Function easily in the Logic app by calling an Http endpoint.
actually nowdays Azure provide this option, without creating runbooks and automation accounts. It is still in preview mode, but seems to be working !
You can also have your PowerShell code run in an Azure Container Instance supporting PowerShell and create an new Container Group from the Logic App workflow.