Moving secret between azure key vaults from different subscription using DevOps - azure

I have 2 different subscriptions (Dev & Prod) and each subscription we are using separate key vault. So, for Dev- keyvault: az-kv-dev & for Prod- keyvault: az-kv-prod.
Now, we want to read the secrets from Dev and needs to write all to Prod key vault using Azure DevOps release pipeline. Please note, we do not hard-code the password inside devops.
Is there any way to do that?

I'm not familiar with DevOps. But It seems you could move the key vault(az-kv-dev) to Prod subscription first, then copy all secrets to az-kv-prod.
Moving Key Vault to a new subscription:
If the two subscriptions are in the same tenant, you could move just in the portal. Navigate to your key vault -> Overview -> "Move" button. If you move key vault to a subscription in a new tenant, you could use Powershell.
Select-AzSubscription -SubscriptionId <your-subscriptionId>
$vaultResourceId = (Get-AzKeyVault -VaultName myvault).ResourceId
$vault = Get-AzResource –ResourceId $vaultResourceId -ExpandProperties
$vault.Properties.TenantId = (Get-AzContext).Tenant.TenantId
$vault.Properties.AccessPolicies = #()
Set-AzResource -ResourceId $vaultResourceId -Properties $vault.Properties
Clear-AzContext
Connect-AzAccount
Copy all secrets from new-az-kv-dev to az-kv-prod:
Param(
[Parameter(Mandatory)]
[string]$sourceVaultName,
[Parameter(Mandatory)]
[string]$destVaultName
)
$secretNames = (Get-AzKeyVaultSecret -VaultName $sourceVaultName).Name
$secretNames.foreach{
Set-AzKeyVaultSecret -VaultName $destVaultName -Name $_ `
-SecretValue (Get-AzKeyVaultSecret -VaultName $sourceVaultName -Name $_).SecretValue
}
For more details about moving to another subscription, see here.

Related

Assign Key Vault Secrets to an Azure Function using Azure PowerShell

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!"

Restore All secret to Azure Key Vault

I have to restore all blob files to the same key vault from where i backed up the files. I have backed up the files using the referenced website. Then deleted all the secrets and now 'restore all' is not working.I can restore individual secrets but not all of them at once.
I am trying following script.
[string]$VaultName = 'NewVault'
Get-AzureKeyVaultSecret -VaultName $VaultName | ForEach-Object {
Restore-AzureKeyVaultSecret -VaultName $VaultName -InputFile ('C:\Backup1\backup_{0}.blob' -f $_."Name")
}
Reference
Azure Key Vault: Backup Secrets using PowerShell
If you want to restore all secrets in a folder to keyvault, you could use the script below.
[string]$VaultName = 'joykeyvault'
$files = Get-ChildItem C:\Backup1 -Filter Backup_*.blob -Recurse | % { $_.FullName }
foreach($file in $files){
Restore-AzureKeyVaultSecret -VaultName $VaultName -InputFile $file
}
Note: In the screenshot, I use the new Az command Restore-AzKeyVaultSecret, in your case, you are using the old AzureRM module, so just use Restore-AzureKeyVaultSecret.
One thing you can check is if the Azure Key Vault is soft-deleted
Upon deleting a key vault object, such as a key, the service will
place the object in a deleted state, making it inaccessible to any
retrieval operations. While in this state, the key vault object can
only be listed, recovered, or forcefully/permanently deleted.
https://learn.microsoft.com/en-us/azure/key-vault/general/soft-delete-overview#key-vault-object-recovery
You can check this with this command from Azure Cloud Shell:
az keyvault list-deleted
If you have a soft-deleted key vault it will show up as a:
"type": "Microsoft.KeyVault/deletedVaults"
You can then recover the complete vault like this:
az keyvault recover --name <key-vault-name>
https://learn.microsoft.com/en-us/cli/azure/keyvault?view=azure-cli-latest

Deploy SAS token to Azure Key Vault Through Azure DevOps

Context: I have a Release pipeline that does the following:
- Delete my runbooks from the automation account- reason
- Copy my runbooks from a my repository into my blob storage
- Run my ARM template where I fetch the blob storage runbook and deploy this to my automation account.
For the third step I need my ARM template to retrieve the blob storage. In Azure devops this is easily done by using the output variable of the copy step en use this inside my deployment step and just override the parameters. But the ARM template I use is a linked template (main template) and the ARM that deploys the runbook doesn't have parameters but a parameter file so I can't just override the parameters there.
The solution for this is to put the SAS token inside a Keyvault secret so the ARM template that needs the SAS token just gets this from the KeyVault.
To do this I copied my Runbook to my blob storage account and exported the sas token in Azure devops. In the next step I want to set the keyvault secret to this variable. So that with every run a fresh SAS token will be in place for the ARM template to retrieve. The problem I am facing now is this.
I use the following lines of code
$Secret = ConvertTo-SecureString -String $(StorageToken) -AsPlainText -Force
Set-AzureKeyVaultSecret -VaultName 'keyvault' -Name 'supersecret-sas-token' -SecretValue $(StorageToken)
But the sas token has a value like this ?sv=2015-05-14&551qf54q5f4&qz5f4qz5f4&qz5f
Like you can see there are some ampersand(&) in the string. And Powershell gives me a hard time for this.
I get the following error message
the ampersand (&) character is not allowed. The & operator is reserved for future use; wrap an ampersand in double quotation marks ("&") to pass it as part of a string.
I tried replacing the amersand value in the string with the value "&" with the quotation marks. ----> didn't work
I tried adding "' '" before and after the string ----> didn't work
Does anyone know a workaround to deploy the sas token to a KeyVault.
Definitely put the string in quotes $Secret = ConvertTo-SecureString -String "$(StorageToken)" -AsPlainText -Force
If it still doesn't work try escaping the ampersands ?sv=2015-05-14`&551qf54q5f4`&qz5f4qz5f4`&qz5f
According to my test, you can use the following script to store SAS token to Azure Key Vault
Connect-AzAccount
$context = New-AzStorageContext -StorageAccountName $StorageAccountName -StorageAccountKey $StorageAccountKey
$sas = New-AzStorageAccountSASToken -Service Blob,File,Table,Queue -ResourceType Service,Container,Object -Permission "racwdlup" -Context $context
$vaule =ConvertTo-SecureString -String $sas -AsPlainText -Force
$secret =Set-AzKeyVaultSecret -VaultName testkey08 -Name test02 -SecretValue $vaule
$secret.SecretValueText

Azure storage account key updation using RM module

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

Creating KeyVault in Azure with no user

Is there a way in Azure to create keyvault without any user? I am trying to follow the documentation but dont see any command that will achieve this in one line?
New-AzureRmKeyVault -VaultName my-test -ResourceGroupName abc -Location "Brazil South"
Any powershell command I can add above to not create any access policy or principal user?
You can use a template to create a vault with no access policy - see: https://github.com/Azure/azure-quickstart-templates/blob/master/101-key-vault-create/azuredeploy.json and just remove this: https://github.com/Azure/azure-quickstart-templates/blob/master/101-key-vault-create/azuredeploy.json#L105-L114
You can deploy that with PowerShell using New-AzureRMResourceGroupDeployment.
The New-AzureRmKeyVault create keyvault with access policy by default, if you want to achieve this in one line, you could use powershell pipeline, try the command below, it works fine on my side.
New-AzureRmKeyVault -VaultName '<VaultName>' -ResourceGroupName '<ResourceGroupName>' -Location 'East US' | Remove-AzureRmKeyVaultAccessPolicy -ObjectId "<ObjectId of your signin user or service principal>"
Update:
I suppose you create the keyvault via a user account, you could get the ObjectId via Get-AzureRmADUser,-UserPrincipalName is your account.
Complete command:
$ObjectId = (Get-AzureRmADUser -UserPrincipalName "xxxx#xxxx.com").Id
New-AzureRmKeyVault -VaultName '<VaultName>' -ResourceGroupName '<ResourceGroupName>' -Location 'East US' | Remove-AzureRmKeyVaultAccessPolicy -ObjectId $ObjectId

Resources