Azure KeyVault: SPN KeyVault Access Denied - azure

I am using below Azure Powershell command in VSTS.
(Get-AzureKeyVaultSecret -vaultName "debugkv" -name "CoreConfig-StorageAccount-AccessKey")
I am getting ##[error]Access denied error while running it in VSTS but loclaly it works fine.
I have added the SPN in KV's access policies also with GET and SET permissions for secrets.
Need help in troubleshooting it.

To link VSTS to you need to give the Service Principal, which forms the Service Endpoint in VSTS, access to the Key Vault; you already know this.
What can be confusing is that you can assign the application and the service principal to have access to the key vault depending on your use case. Therefore, you must ensure that you assign the right object to the access policy.
The best way to ensure you assign the right object is to do it through Azure Powershell.
Running a signed in Azure Powershell session:
$spObjectId = Get-AzureRmAdServicePrincipal -SearchString <ServicePrincipalName> | Foreach-Object {$_.Id}
Set-AzureRmKeyVaultAccessPolicy -VaultName <VaultName> -ObjectId $spObjectId -PermissionsToSecrets Get,Set
If you wanted to see further details (objectids, permissions etc) of the access policies you can get these through Powershell also:
Get-AzureRmKeyVault -VaultName <VaultName> | Foreach-Object {$_.AccessPolicies}

Related

Connecting to Azure KeyVault via SPN

I need help accessing an Azure KeyVault via Service Principal. I currently have two subscriptions that need to communicate and access the other subscription's Key Vault but in order to do so I would need the connection to occur via SPN. I have looked at the documentation for Get-AzureRmKeyVault and it provides no way to authenticate via a SPN from what I can find.
If anyone has a solution I would greatly appreciate it!
Not sure what actually do you mean access keyvault, in azure keyvault, there are Management plane and Data plane, they use different access control mechanisms.
If you want your service principal to do Management plane operations(e.g. set the tag of your keyvault), you need to give it a role in Access control (IAM) of your keyvault in the portal. If you want to do Data plane operations(e.g. operate on the keys, secrets, certificates in the keyvault), you need to add your service principal with correct permissions to the Access policies of the keyvault.
For more details about access control of keyvault, you could check - Secure access to a key vault.
So make sure your service principal already had the correct permission, then use the command below.
$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 you can do the Management plane operations like Update-AzKeyVault, or the Data plane operations like Get-AzKeyVaultSecret.
To access the keyvault in a different subscription, just use the command below to select subscription.
Set-AzContext -Subscription <subscription-id>
And I notice seems you are using the old AzureRm module, it was deprecated and will not be updated anymore, I recommend you to use the new Az module, follow Migrate Azure PowerShell from AzureRM to Az.

Add/get secret to Azure Keyvault with Azure powershell task in Azure devops

I am trying to set the secrets inside my Azure Keyvault using the Azure Powershell Task in Azure DevOps.
I use the following code:
Set-AzureKeyVaultSecret -VaultName $KeyvaultName -Name $SecretName -SecretValue $secretvalue
With the names and the value all setup inside variables and tried to use this without also variables.
The value is saved as a secure string with the following code.ConvertTo-SecureString
But when I run this powershell code inside my Azure DevOps Release pipeline I keep getting following Error message:
Cannot retrieve access token for resource 'AzureKeyVaultServiceEndpointResourceId'. Please ensure that you have provided the appropriate access tokens when using access token login.
So I've made sure that the service principal and the build server are having the right access on the keyvault by adding them both to the access policies with the get,list,set secrets permission.
I've also added following lines of code to make sure that the profile is loaded correctly
########################################################################################
$azureRmProfile = [Microsoft.Azure.Commands.Common.Authentication.Abstractions.AzureRmProfileProvider]::Instance.Profile
$profileClient = New-Object -TypeName Microsoft.Azure.Commands.ResourceManager.Common.RMProfileClient -ArgumentList ($azureRmProfile)
$context = Get-AzureRmContext
$AzureToken = $profileClient.AcquireAccessToken($context.Tenant.Id)
Add-AzureRmAccount -AccessToken $AzureToken.AccessToken -AccountId $AzureToken.UserId
########################################################################################
By adding this code in the beginning of the inline script and using the profile with the commando as variable to the -DefaultProfile.
I also enabled the option to enable the script to access the Oauth token.
Is there someone who also tried to set the secret from the powershell task in Azure DevOps. Or know why the powershell script can't get access on the keyvault.
The azurermContext commando provided me with the right output, even tried the Get-AzureRmKeyvault command to figure out if the connection to the environment was already setup right. And that also didn't gave any problems.
below working for sure (using this reguarly)
Set-AzContext -SubscriptionId $SubscriptionId
## $SubscriptionId is a subscription ID where is the target KV
$Secretvalue = ConvertTo-SecureString $SecretValuePlainText -AsPlainText -Force
## $SecretValuePlainText is the secret to store
Set-AzKeyVaultSecret -VaultName $KeyVaultName -Name $SecretName -SecretValue $Secretvalue -ErrorVariable setSecretError -Expires $ExpirationDate -NotBefore $ActivationDate
## $SecretName, $ExpirationDate, $ActivationDate - obvious :)
of course if your refer to variable not from script or inline, but from release the use $(variable_name)
Service Principal/Service Connection we use for this is temporary an Owner of target subscription (or key vault, up to you).
I had the exact same issue.
Found that the problem was a missing access token.
Namely -KeyVaultAccessToken when you call Add-AzureRmAccount.
Found the solution here: https://github.com/Azure/azure-powershell/issues/4818#issuecomment-376155173
I fixed my question with the following.
I used a service connection that was based on a managed identity. And this needed some workaround to access the key vault like #john mentioned. But this was unnecessary. by creating a new service connection based on a service principal. This workaround was not necessary and fixed the issue.

Unable to access Azure Key vault secret in a powershell script running on Azure Devops

I have a powershell script that attempts to retrieve a secret stored in Azure key vault using this command.
$password = (Get-AzureKeyVaultSecret -vaultName $vaultName -name $secretName).SecretValueText
It is working perfectly fine when I execute my powershell script locally. But, when I try to do the same on Azure Devops, it fails giving below error.
[error]Operation returned an invalid status code 'Forbidden'
I feel it isn't an access policy issue, as I am able to successfully perform read/write on my vault using powershell script running locally.
I'm quite sure it is a access policy issue.
Go to your DevOps Project Settings - Pipelines - Service Connections and click on "Update Service Connection" (Use the full version of the dialog). There you can find the Subscription Id and Service Principal ID.
You then have to give explicit permissions to this SPN:
Login-AzureRmAccount -subscription <YourSubscriptionID>
$spn= Get-AzureRmADServicePrincipal -spn <YourSPN>
Set-AzureRmKeyVaultAccessPolicy -VaultName <YourVaultName> -ObjectId $spn.Id -PermissionsToSecrets get,list;

Azure KeyVault Access Policies - Adding App Service using Powershell and VSTS

I have a Azure Key Vault in which I want to add access policies for my MSI enabled App Service using powershell.
Using portal it's straightforward. As you can see below, I am searching by my app service name and I see app service and app registrations both.
in above example I selected app service directly without registrating it in Azure AD and it's working awesome.
I just need guidance to do the same using Azure Powershell(which will run VSTS SPN).
Please help.
Thanks
Set-AzureRmKeyVaultAccessPolicy -VaultName $valutName -UserPrincipalName 'PattiFuller#contoso.com' -PermissionsToKeys create,import,delete,list -PermissionsToSecrets set,delete -PassThru
Make sure you have logged in from the PowerShell and selected the resource group where the resource exists before you run the command.
Refer documentation for more.
You need to use the the Set-AzureRmKeyVaultAccessPolicy command but with ObjectId parameter.
Set-AzureRmKeyVaultAccessPolicy -VaultName my-keyvault -ResourceGroupName my-resource-group -ObjectId 15faf32d-146a-4985-a315-640527b6c489 -PermissionsToSecrets get
Bear in mind that MSI apps are registered as Enterprise Apps.
EDIT: Curious, what are you trying to achieve?

How do I Choose which AAD you Create the Service Principal in?

I can't find any documentation on how to choose which AAD to create the service principal in. Basically, I can't find out if there is even a way to add the SP to the local AAD.
So we have a default Global AD which covers all of our enrollment and below that all subscriptions. I'm using Powershell derived from the many many examples on the net to create a SP in the default AD. Then I permission that SP against the subscription it is going to be working in.
At this point I've run into the following problem.
I'm rolling out a Key Vault, this works.
New-AzureRmKeyVault -VaultName $VaultName -EnabledForDeployment -EnabledForTemplateDeployment -ResourceGroupName $ResourceGroupName -Location $Location -Verbose
I need to add the first secret into it as part of the deployment. This bit fails because the SP doesn't have access to the KV.
# Set-AzureRmKeyVaultAccessPolicy -VaultName $VaultName -ResourceGroupName $ResourceGroupName -PermissionsToSecrets get,set -ServicePrincipalName $ServicePrincipalName
This is the result of that command.
Set-AzureRmKeyVaultAccessPolicy : Cannot find the Active Directory object
'Service-Principal-Name' in tenant '6166a717-xxxx-xxxxx-b0e8-6b7288c1f7ec'.
Please make sure that the user or application service principal you are
authorizing is registered in the current subscription's Azure Active
directory.
Reading into this, its not possible to set the Global AD Service Principal to have get/set on the local Keyvault. it would have to be a local Service Principal. However, we dont have one of them and nowhere can I work out how to create one of them.
Anyone else feeling this pain and know how to resolve it?
In the settings section of the old portal (manage.windowsazure.com), you will find a list of all subscriptions. The fourth column (Directory) shows the default directory that is associated with each subscription. No matter what, you will have to create the Service Principal in the Directory that is associated with that particular subscription. Please check this link to understand the relationship between Subscriptions and AAD.

Resources