Azure Powershell Add-AzureKeyVaultManagedStorageAccount failing - powershell

I am unable to perform the Azure Powershell command Add-AzureKeyVaultManagedStorageAccount, even though I am executing it under the subscription owner profile. I successfully create keyvault, storage account, and storage account key in the following manner:
$KeyVault = New-AzureRmKeyVault `
-VaultName "<redacted>" `
-ResourceGroupName $ResourceGroup.ResourceGroupName `
-Location $Location `
-EnabledForDiskEncryption `
-EnabledForDeployment `
-Tag $Tags
$StorageAccount = New-AzureRmStorageAccount `
-ResourceGroupName $ResourceGroup.ResourceGroupName `
-Name "<redacted>" `
-SkuName Standard_LRS `
-Location $Location `
-Kind "Storage" `
-EnableEncryptionService "Blob,File" `
-Tag $Tags `
-AssignIdentity
$StorageAccountKey = New-AzureRmStorageAccountKey `
-ResourceGroupName $ResourceGroup.ResourceGroupName `
-Name $StorageAccount.StorageAccountName `
-KeyName "key1"
but trying to manage the storage account key in my key vault fails
$KeyVaultManagedStorageAccount = Add-AzureKeyVaultManagedStorageAccount `
-VaultName $KeyVault.VaultName `
-AccountName $StorageAccount.StorageAccountName `
-AccountResourceId $StorageAccount.Id `
-ActiveKeyName "key1" `
-Tag $Tags
This is the error. As I mentioned, I am executing under the subscription owner profile, so how can it not have authorization? Secondly, the "same redacted object Id" identified below does not correspond to any object in my subscription that I can find. I first experienced this problem with Azure Powershell 4.2.1, and have since upgraded to 4.3.0 and still have the problem.
Add-AzureKeyVaultManagedStorageAccount : The client '<same redacted object Id>' with object id '<same redacted object Id>' does not have authorization to perform action
'Microsoft.Authorization/permissions/read' over scope
'/subscriptions/<subscription ID>/resourceGroups/<resource group name>/providers/Microsoft.Storage/storageAccounts/<storage account name>/providers/Microsoft.Authorization'.
At E:\BitSync\Scripts\Azure\Create-Environment.ps1:129 char:34
+ ... VaultManagedStorageAccount = Add-AzureKeyVaultManagedStorageAccount `
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : CloseError: (:) [Add-AzureKeyVaultManagedStorageAccount], KeyVaultErrorException
+ FullyQualifiedErrorId : Microsoft.Azure.Commands.KeyVault.AddAzureKeyVaultManagedStorageAccount
BTW, there does not appear to be any way to manage Storage Account keys through Key Vault in the portal other than cut and paste.

According to your error message, it is a RBAC issue, the service principal you are using does not have rights within that tenant.
Tenants have subscriptions and service principals belong to tenants. Azure resource manager also exposes role based authorization for a given principal, which would give it rights on Azure resources. It appears the service principal doesn't have rights to read from that subscription.
We can assign RBAC roles at the resource scope via Azure portal, more information about assign RBAC, please refer to this link.
Note:
Key vault needs permissions to list and regenerate keys for a storage account.we can use the following steps to do it:
Get ObjectId of your account:
Get-AzureRmADServicePrincipal -SearchString "Azure Key Vault"
Assign Storage Key Operator role to Azure Key Vault Identity:
New-AzureRmRoleAssignment -ObjectId <objectId of AzureKeyVault from previous command> -RoleDefinitionName 'Storage Account Key Operator Service Role' -Scope '<azure resource id of storage account>'
More information about setup for role-based access control permissions, please refer to this article.
Update:
Also, we should set Azure key vault access policy permissions to storage.
Set-AzureRmKeyVaultAccessPolicy -VaultName 'jasonkey01' -ResourceGroupName 'jasontest' -ObjectId '556ca95d-2f50-4acd-b98e-a111b5b41b66' -PermissionsToStorage 'all'
Here is the screenshot about my keyvault:
In this way, we can use your script to add key vault for storage account.
Update2:
I have reproduce this error, the root cause is that we can't grant permission to service principal Azure Key Vault.
We can use this command to find object id, same as your error message.
Get-AzureRmADServicePrincipal -SearchString "Azure Key Vault"
Then we grant permission to this service principal, use this script:
New-AzureRmRoleAssignment -ObjectId '2f6d671f-6c8d-4104-812a-390c5648aed0' -RoleDefinitionName 'Storage Account Key Operator Service Role' -Scope '/subscriptions/53847abb-xxxx-xxxx-xxxx-xxxxe29axxxx/resou
rceGroups/jasonkey/providers/Microsoft.Storage/storageAccounts/jasondisk321'
Here is my result:
Update3:
After run Add-AzureKeyVaultManagedStorageAccount, we should run this command to get secret URI:
Set-AzureKeyVaultManagedStorageSasDefinition -Service Blob -ResourceType Container,Service -VaultName yourKV
-AccountName msak01 -Name blobsas1 -Protocol HttpsOnly -ValidityPeriod ([System.Timespan]::FromDays(1)) -Permission Read,List
Here is the result:
More information about get the secret URI, please refer to this article.

Related

Use the AZ module in a non-interactive environment?

I'm hoping to be able to use the Az module to retrieve a secret from an Azure key vault, for use with a PowerShell script that has been deployed to a server and is run daily by Windows Task Scheduler.
Initially, I needed to follow the oauth (a guess) process:
Connect-AzAccount -Tenant '69a29f45-...'
Which redirects to https://login.microsoftonline.com/..., asking you to choose an account:
eventually, it indicates success:
Authentication complete. You can return to the application. Feel free to close this browser tab.
After this has been completed, the script that retrieves the secret works as expected:
...
$AccessToken = Get-AzKeyVaultSecret -VaultName 'MyVault' -Name 'MySecret' | Select-Object -ExpandProperty SecretValue | ConvertFrom-SecureString -AsPlainText
...
I'm concerned that the token will expire, causing my script to fail.
The SharePoint module (Pnp.PowerShell) can make use of a credential stored in Windows Credential Manager. Can the Az module do so as well?
If not, is there another way to handle this authentication process without interaction?
You can logon using a certificate tied to a Service Principal (SP) in your AD tenant. Then you just have to make sure that the SP has access to your key vault as at least a reader.
Looks we could not use Az module with the Windows Credential Manager, to use Az powershell in a non-interactive way, we always use a service principal, please follow the steps below.
1.Register an application with Azure AD and create a service principal.
2.Get values for signing in and create a new application secret.
3.Then use the commands below.
Note: Don't forget to add the service principal to the Access policies with the secret permission of the keyvault in the portal first.
$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
#get the secret
$AccessToken = Get-AzKeyVaultSecret -VaultName 'MyVault' -Name 'MySecret' | Select-Object -ExpandProperty SecretValue | ConvertFrom-SecureString -AsPlainText

Azure Automation | Runbook | Powershell | Get-AzRoleAssignment | Microsoft.Rest.Azure.CloudException

I have an Automation account and I have set up the Run-As-Account for non-classic resources. In my automation Account I have imported Az.Resources, Az.Account, Az.Storage and Az.KeyVault.
I have a script that does not work under the Automation service principle. The following error is a first of 3;
Get-AzRoleAssignment : Exception of type 'Microsoft.Rest.Azure.CloudException' was thrown. At line:26 char:10
I have granted the application registration the following set of application api permissions in Azure Active Directory (more than I anticipate needing);
At the start of the script I run the Connect-AzAccount cmdlet;
$servicePrincipalConnection = Get-AutomationConnection -Name 'AzureRunAsConnection'
Connect-AzAccount -ServicePrincipal `
-Tenant $servicePrincipalConnection.TenantID `
-ApplicationId $servicePrincipalConnection.ApplicationID `
-CertificateThumbprint $servicePrincipalConnection.CertificateThumbprint
Followed by the failing command;
If(!(Get-AzRoleAssignment | Where-Object { $_.RoleDefinitionName -eq "Storage Blob Data Contributor" `
-and $_.scope -eq "/subscriptions/$subscription/resourceGroups/$resourceGroup/providers/Microsoft.Storage/storageAccounts/$serviceName" `
-and $_.SignInName -eq (Get-AzContext).Account.Id})){
# There does not exist the requisite permission for the run-as-account context, grant; 'Storage Blob Data Contributor'.
New-AzRoleAssignment -RoleDefinitionName "Storage Blob Data Contributor" `
-ApplicationId (Get-AzADServicePrincipal | Where-Object { $_.DisplayName -eq "jupiterautomation01" }).ApplicationId `
-Scope "/subscriptions/$subscription/resourceGroups/$resourceGroup/providers/Microsoft.Storage/storageAccounts/$serviceName"
}
I need to grant the right permissions, but do not know what they are.
The permissions assigned need to be consented to by an 'admin'. The button was only available when accessing Azure via the Microsoft account used to create the Active Directory tenant.
Sign in with an admin account that can consent.
Grant API permissions to read or read/write (i needed write as well) on Active Directory to the application.
Give admin consent using the button displayed in the image.

can I create a resource group in one subscription using other subscription endpoint in vsts CD task?

I am modifying a CD pipeline.
I have a azure powershell task to create app insight using powershell.
Argument passed:
-SubscriptionName $(SubscriptionName) -ResourceGroupName $(ResourceGroupName) -clientID $(clienttestID) -AccessKey $(AccesstestKey)
The ResourceGroup(ResourceGroupName) is available on SubscriptionName(SubscriptionName ~~abc) and I am using Azure Subscription connection xyz.
Is this a correct scenario, or will it fail as resource group on which I am creating app insight is under different subscription?
To create any resources using powershell, you need to be logged in to the same subscription account in which your resource group exist otherwise it will give you an error like below
In order to create a application insight under a resource group after switching to a right subscription, you can follow below steps:-
# Connect-AzureRmAccount / Connect-AzureRmAccount
# Set the name of the Application Insights Resource
$appInsightsName = "SampleApp"
# Set the application name used for the value of the Tag "AppInsightsApp"
$applicationTagName = "My-Sample-App"
# Set the name of the Resource Group to use.
# Default is the application name.
$resourceGroupName = "My-RG"
###################################################
# Create the Resource and Output the name and iKey
###################################################
Get-AzureRmSubscription -SubscriptionName "Sample Subscription name"
# Select the azure subscription
Select-AzureSubscription -SubscriptionName "Sample Subscription name"
# Create the App Insights Resource
$resource = New-AzureRmResource -ResourceName $appInsightsName -ResourceGroupName $resourceGroupName -Tag #{ applicationType = "web"; applicationName = $applicationTagName} -ResourceType "Microsoft.Insights/components" -Location "East US" -PropertyObject #{"Application_Type"="web"} -Force
# Give owner access to the team
New-AzureRmRoleAssignment `
-SignInName "myteam#sampleDomain.com" `
-RoleDefinitionName Owner `
-Scope $resource.ResourceId
# Display iKey
Write-Host "App Insights Name = " $resource.Name
Write-Host "IKey = " $resource.Properties.InstrumentationKey
Once the resource would be added, you will be able to see the details for it like below-

Authentication_MissingOrMalformed when executing New-AzureADApplication

I'm trying to run this script but I get this error :
New-AzureADApplication : Error occurred while executing NewApplication
Code: Authentication_MissingOrMalformed
Message: Access Token missing or malformed.
Import-Module AzureAD  -Force
$rmAccount = Add-AzureRmAccount
$subscriptionId = $rmAccount.Context.Subscription.Id
$tenantId = $rmAccount.Context.Tenant.Id
$tokenCache = $rmAccount.Context.TokenCache
$cachedTokens = $tokenCache.ReadItems() `
| where { $_.TenantId -eq $tenantId } `
| Sort-Object -Property ExpiresOn -Descending
$infos = Connect-AzureAD -TenantId $tenantId `
-AadAccessToken $cachedTokens[0].AccessToken `
-AccountId $rmAccount.Context.Account.Id
$clientAadApplication = New-AzureADApplication -DisplayName "TodoListClient-NativeDotNet" `
-ReplyUrls "https://TodoListClient-NativeDotNet" `
-PublicClient $True
$currentAppId = $clientAadApplication.AppId
$clientServicePrincipal = New-AzureADServicePrincipal -AppId $currentAppId -Tags {WindowsAzureActiveDirectoryIntegratedApp}
$currentAppId = $clientAadApplication.AppIds
What I'm trying to do is to automatically register a native application in Azure Active Directory without dependency to Azure portal so I logged in using Add-AzureRmAccount to get TenantId and SubscriptionId then I used the cached token to connect to AzureAD to prevent double login.
The token that you obtain when you run Add-AzureRmAccount is for the https://management.core.windows.net audience, but Azure AD cmdlets need a token for Azure AD Graph audience (https://graph.windows.net). So you can't reuse that token while calling New-AzureADApplication. You should choose between Azure RM or Azure AD cmdlets, but not both. But as far as I know New-AzureRmADApplication doesn't support creating a native application, so then you should use only Azure AD cmdlets.
You were close, but the token you are passing from the AzureRMAccount is not the correct Audience/Resource for the actions you are doing. Just removing that bit and running something like this below will work with the correct Audience and Resource permissions for your Token. You can always check your Token Audience and scope by copying and pasting it at https://jwt.ms (a useful Token debugger by Microsoft).
Import-Module AzureAD -Force
Connect-AzureAD
$clientAadApplication = New-AzureADApplication -DisplayName "TodoListClient-NativeDotNet" `
-ReplyUrls "https://TodoListClient-NativeDotNet" `
-PublicClient $True
$currentAppId = $clientAadApplication.AppId
$clientServicePrincipal = New-AzureADServicePrincipal -AppId $currentAppId -Tags {WindowsAzureActiveDirectoryIntegratedApp}
$currentAppId = $clientAadApplication.AppIds

Azure Rotate Storage Keys and Update ADF Linked Service

I am looking for a way to implement doing key rotation in an Azure Automation I have found a way to create a powershell runbook and have implemented the following code:
$azureAccountName = <acct_name>
$azurePassword = ConvertTo-SecureString <pass> -AsPlainText -Force
$psCred = New-Object System.Management.Automation.PSCredential($azureAccountName, $azurePassword)
Login-AzureRmAccount -ServicePrincipal -Credential $psCred -TenantId <tenant id> -SubscriptionId <sub id>
#Optionally you may set the following as parameters
$StorageAccountName = <storage acct name>
$RGName = <rg name>
#Key name. For example key1 or key2 for the storage account
New-AzureRmStorageAccountKey -ResourceGroupName $RGName -Name $StorageAccountName -KeyName "key1" -Verbose
New-AzureRmStorageAccountKey -ResourceGroupName $RGName -Name $StorageAccountName -KeyName "key2" -Verbose
When I ran this, it worked, however, it broke my Azure Data Factory Linked Service. I realized that the connection string for the linked service is broken, so I set out to try to reset the connection string in the automation script. I was able to get the connection string by doing:
(Get-AzureRmDataFactoryLinkedService -DataFactoryName <adf name> -ResourceGroupName <rg name> -Name <ls name>).Properties.TypeProperties.ConnectionString
I cannot find a way to set this connection string using powershell and azure automation.
You could use Power Shell to rest this connection. But you need use Remove-AzureRmDataFactoryLinkedService (Removes a linked service from Azure Data Factory.) and use New-AzureRmDataFactoryLinkedService to re-link your storage account to data factory.
Please refer to this tutorial.
You need create a json file like below:
{
"name": "AzureStorageLinkedService",
"properties": {
"type": "AzureStorage",
"typeProperties": {
"connectionString": "DefaultEndpointsProtocol=https;AccountName=<accountname>;AccountKey=<accountkey>"
}
}
}
Use New-AzureRmDataFactoryLinkedService to link.
New-AzureRmDataFactoryLinkedService -ResourceGroupName ADFTutorialResourceGroup -DataFactoryName <Name of your data factory> -File .\AzureStorageLinkedService.json
But if you use Azure automation to execute this, there is a issue you will meet. On runbook, you could not store a json file, maybe you could save on a public github(no safe). Another solution is use Hybrid Runbook Worker.