az login fails from github action task - azure

I'm trying to create a GitHub action that deploys infra and my system to Azure. To log in, I use an azure login action like so:
- name: Azure Login
uses: azure/login#v1.4.0
with:
creds: ${{ secrets.AZURE_CREDENTIALS }}
To be able to do this, you must first create a service principal in Azure and store the secrets as a secret in your GitHub repo. I neatly created an sp using the az ad sp create-for-rbac command and defined enough permissions and all (as described here), however... I cannot use the --sdk-auth flag anymore because it's deprecated. I don't know if this flag makes a difference, but there is a difference in the JSON object the Azure CLI outputs compared to previous versions. The (JSON) object this commands outputs looks like so:
{
"appId": "guid",
"displayName": "Name I gave the app in the az ad sp create for RBAC command",
"name": "guid",
"password": "very-secret-string",
"tenant": "guid"
}
This seems to be some sort of a new object because, in previous versions, the object looked slightly different. The previous version of the AZ CLI outputs an object that looks like this:
{
"clientId": "guid",
"clientSecret": "super-secret-string",
"subscriptionId": "guid",
"tenantId": "guid"
}
Now, as a result, the login action in my GH Actions workflow doesn't work anymore and I desperately need it ;)
I also tried to create a Federated Credential, but without a result. Now, I'm out of ideas to be honest and I could use some differenty insights.

It looks like there was an issue with the Azure CLI versions installed on the workers.
According to the GH issue, this has been resolved now and shouldn't occur in the future anymore: https://github.com/Azure/cli/issues/56#issuecomment-965186851
Released a long term fix for any further mismatch issues.
Now the default value for azcliversion dynamically points to the version installed on agent. So there will be no mismatch again unless someone explicitly mentions latest. If for some reason there is no version of az cli on the agent then action fall backs to latest.
Most of the hosted agents are also updated to 2.30.0.
Please test your scenarios and let us know if you face any more issues.

Related

Can docker on Azure Linux App Service authenticate with the ACR without us specifying the password in the app settings?

We deploy a Linux App Service to Azure using terraform. The relevant configuration code is:
resource "azurerm_app_service" "webapp" {
app_settings = {
DOCKER_REGISTRY_SERVER_URL = "https://${local.ctx.AcrName}.azurecr.io"
DOCKER_REGISTRY_SERVER_USERNAME = data.azurerm_key_vault_secret.acr_admin_user.value
DOCKER_REGISTRY_SERVER_PASSWORD = data.azurerm_key_vault_secret.acr_admin_password.value
...
}
...
}
The problem is that terraform does not consider app_settings a secret and so it outputs in the clear the DOCKER_REGISTRY_SERVER_PASSWORD value in the Azure DevOps output (I obfuscated the actual values):
So, I am wondering - can docker running on an Azure Linux App Service host authenticate with the respective ACR without us having to pass the password in a way that makes it so obvious to every one who can inspect the pipeline output?
The following article seems relevant in general - https://docs.docker.com/engine/reference/commandline/login, but it is unclear how we can apply it in my context, if at all.
Also, according to https://feedback.azure.com/forums/169385-web-apps/suggestions/36145444-web-app-for-containers-acr-access-requires-admin#%7Btoggle_previous_statuses%7D Microsoft has started working on something relevant, but looks like this is still a work in progress (almost 5 months).
I'm afraid you must set the environment variables about DOCKER_REGISTRY_* to pull the images from the ACR, it's the only way to do that designed by Azure. But for the sensitive info about the password, it also provides a way to hide it. You can use the Key Vault to store the password in secret, and then get the password from the secret. Take a look at the document Use Key Vault references for App Service. So you can change the app_setting for the password like this:
DOCKER_REGISTRY_SERVER_PASSWORD = "#Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret/ec96f02080254f109c51a1f14cdb1931)"
Or
DOCKER_REGISTRY_SERVER_PASSWORD = "#Microsoft.KeyVault(VaultName=myvault;SecretName=mysecret;SecretVersion=ec96f02080254f109c51a1f14cdb1931)"
Then it just shows the reference of the Key Vault, not the exact password.
Unfortunately Azure Web Apps do not support interacting with ACR using a managed identity, you must pass those Environment Variables to the App Service.
Terraform does not currently support applying a "sensitive" flag to arbitrary values. You can define outputs as sensitive, but it will not help with values you want to hide during the plan phase.
I would suggest checking out https://github.com/cloudposse/tfmask, using the TFMASK_RESOURCES_REGEX configuration to block the output you want to hide during your pipeline. If you're averse to adding dependencies, similar effect could be achieved by piping terraform apply through grep --invert-match "DOCKER_REGISTRY" instead.
#charles-xu has a good answer as well if you want to set up mappings between keyvault and your web app then push your tokens into kv secrets.
Now it's possible to use managed identity to pull images from ACR.
You may do the next:
go to your Container Registry page in the Azure portal
Open the tab Access Control (IAM)
The open Role assignments tab
Add role assignment AcrPull to your App Service or Function App
In the Deployment Center of your App Service choose Managed Identity for the Authentication setting.
Or you may use CLI by following the steps from the official documentation (link below):
https://learn.microsoft.com/en-us/azure/app-service/configure-custom-container?pivots=container-linux#use-managed-identity-to-pull-image-from-azure-container-registry
After you added role assignment DOCKER_REGISTRY_SERVER_URL, DOCKER_REGISTRY_SERVER_USERNAME and DOCKER_REGISTRY_SERVER_PASSWORD settings may be removed from App Service's App Settings.

Azure Function ARM Deployment with listkeys results in BadRequest Error

I have a simple ARM template that deploys two Azure Functions, an App Service Plan and a Storage Account:
The only "special" thing is, that the function function-key-issue-two adds the default host key from the function function-key-issue-one as an app setting:
"FunctionOneKey": "[listkeys(concat(variables('functionTwoAppId'), '/host/default/'),'2016-08-01').functionKeys.default]",
If I deploy this template to a new resource group, it works the first time. Every subsequent deployment fails with a Bad Request Error on the Resource function-key-issue-one/default:
This is how the operation details looks like:
{
"Code": "BadRequest",
"Message": "Encountered an error (ServiceUnavailable) from host runtime.",
"Target": null,
"Details": [
{
"Message": "Encountered an error (ServiceUnavailable) from host runtime."
},
{
"Code": "BadRequest"
},
{
"ErrorEntity": {
"Code": "BadRequest",
"Message": "Encountered an error (ServiceUnavailable) from host runtime."
}
}
],
"Innererror": null
}
If I remove the FunctionOneKey App Setting, the deployment works. Also If I don't specify the App Setting WEBSITE_RUN_FROM_PACKAGE, the deployment also works.
The function code is deployed later using the AzureFunctionApp#1 Azure DevOps Task as a Zip package (that is why I set WEBSITE_RUN_FROM_PACKAGE to 1).
How to reproduce:
The ARM template I am using is available here.
You can deploy it using. e. g. the New-AzResourceGroupDeployment cmdlet:
New-AzResourceGroupDeployment -ResourceGroupName 'function-key-issue-rg' -TemplateFile "D:\sources\issues\functionDeployment\azuredeploy.json" -name "azuredeploy-$(New-Guid)"
Update 1:
The reason for the ServiceUnavailable error is probably because Kudu adds a web.config with a rewrite rule (because I use WEBSITE_RUN_FROM_PACKAGE but don't have deployed the function):
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name = "Site Unavailable" stopProcessing = "true">
<match url = ".*" />
<action type = "CustomResponse" statusCode = "503" subStatusCode = "0" statusReason = "Site Unavailable" statusDescription = "Could not download zip" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
My next attempt was to prevent Kudu from doing this by setting
SCM_TOUCH_WEBCONFIG_AFTER_DEPLOYMENT to 0 (See: Don't touch web.config at the end of the deployment). And now it looks like, subsequent deployments sometimes succeed:
But still not a reliable solution :-/.
Update 2:
Same issue with the Azure Function Runtime ~2.
Switching the Azure Function to Linux also doesn't solve the issue.
Update 3:
I opend a GitHub issue regarding this topic.
Any idea what is wrong here? Any workarounds?
I too have had this problem deploying Function Apps and app settings with ARM templates.
After a back-and-forth with Azure support, we realised that the persistence of the app settings causes a restart of the Function App during deployment, which results in a 503 Service Unavailable while it spins back up. This happens while the deployment is still in progress, which then causes intermittent failures of the Microsoft.Web/sites/host. This is also despite the ARM deployment mode being set to incremental, which seems to be ignored completely for function app settings.
The Diagnostics Settings of the Function App will list the hard restarts for you and might give some insight into the app setting that caused it.
A suggestion was made from Azure support to separate the app settings into their own Microsoft.Web/sites/config section in the ARM template, which dependsOn the Function App having finished deployment. I've not tried this yet, and this also goes against what's in the Function App ARM examples, where they are a child config resource of a Microsoft.Web/sites.
I think you can change the way you are establishing communication between your functions, and you will also fix your issue. I would recommend you to use Azure Managed Identity to configure the communication between your functions, instead of using the function keys. Please have a look at this article to get more details of what I am saying.
first of all, i would suggest to use Azure KeyVault as a default storage for your keys, like described here.
But it seems, that this is related also some issues regarding Appservice and Package Deployments.
Take a look here: https://github.com/microsoft/azure-pipelines-tasks/issues/10961 and here: https://github.com/microsoft/azure-pipelines-tasks/issues/11444.
The documentation also says something like this:
https://learn.microsoft.com/de-de/azure/azure-functions/run-functions-from-deployment-package
Hope this is helpfull.
I had, sort of, the same problem in a template, that deployed EventGrid Topic subscribers to a Topic. Precense of the the listkey() function in the json template resulted in the same, very non-descriptive error message.
I've made it work, by updating the ARM template schema to the newest schema supported on Azure: 2019-08-01
Like this:
Top line in the file:
"$schema": "https://schema.management.azure.com/schemas/2019-08-01/deploymentParameters.json#",
and inline, in the listkeys function:
listkeys(concat(resourceId('Microsoft.Web/sites', parameters('functionAppName')), '/host/default'), '2019-08-01').functionKeys.default)
Now, several, subsequent deployments work again, at least for me.
I have had this problem recently and contacted the Azure Functions team, and what I understood from them is this: (I am using ARM Template should be same logic to all with different approaches)
1- using WEBSITE_RUN_FROM_PACKAGE = 1 must be set before deploying the Zip File, meaning adding dependency between the ZipDeploy with deploying AppSettings.
why?
if this flag is not set at first, the function would take the ZipFile and extract it to wwroot folder, leading to empty SitePackage folder and breaking the deployment and function. this flag makes the function upload a zip file to a folder in the function shared file system under data/SitePackage, with also a package.txt that has the name of the related Zip.
this flag aren't supposed to be changed back and forth, because it would break the deployment due to confusing whether it should upload the zip to SitePackages or Extract it to wwroot.
an answer i was given if turning your flag for the first time, it could happen that the first deployment fail, and you need to try again.
2- when using WEBSITE_RUN_FROM_PACAKAGE the function go through a sort of restart, that is written on the docs here you see that after deployment a restart is done.
so the step of "listKeys" could fall on a restart and leading to failure, what you need to do is Add a "wait" step for 1-2 minutes after the function deployed to be sure that everything is done.
Good Luck
I have faced pretty much the same issue. I need to feed the Azure Function which its own host key. After several different test scenarios my conclusion is that there is some delay between the Azure Function App deployment finish and the moment the Host keys are available.
My current workaround is to create previously a key in the KeyVault a use this key in two different places:
To create a new host key in the Azure Function
To feed the Azure Function appsettings
Some sample codes:
Generating Key in the KeyVault from PS
$secureSecret = ConvertTo-SecureString New-Guid.ToString() -AsPlainText -Force
Set-AzureKeyVaultSecret -VaultName $keyVaultName -Name "azure-function-key" -SecretValue $secureSecret
Create the host key and passing it to the function
Note that parameters('internalKey') would be fed from the KeyVault reference
"apiVersion": "2019-08-01",
"type": "Microsoft.Web/sites",
"kind": "functionapp",
"name": "[variables('functionAppName')]",
"location": "[variables('location')]",
"resources": [{
"dependsOn": ["[resourceId(resourceGroup().name, 'Microsoft.Web/sites', variables('functionAppName'))]"],
"type": "Microsoft.Web/sites/host/functionKeys",
"apiVersion": "2018-11-01",
"name": "[concat(variables('functionAppName'), '/default/internalkey')]",
"properties": {
"name": "internalkey",
"value": "[parameters('internalKey')]"
}
},
{
"apiVersion": "2019-08-01",
"name": "appsettings",
"type": "config",
"dependsOn": [
"[resourceId(resourceGroup().name, 'Microsoft.Web/sites', variables('functionAppName'))]"
],
"properties": {
"FUNCTIONS_EXTENSION_VERSION": "~3",
"HostFunctionKey": "[parameters('internalKey')]"
}
}]
Even in you try the listKeys approach with your new host key it won't get the value. First time it will fail and successive times it will get the previous value if it has changed.

Specify Function App Configuration with Key Vault Reference in Azure ARM Template

Is there a way to specify KeyVault References in Function App configuration within my ARM template?
I have an ARM template that will deploy an Azure Function App with different deploy parameter for each environment. Currently I am retrieving the secret in my environment via references in the parameter:
{
"storageAccountSecret": {
"reference": {
"keyVault": {
"id": "/subscriptions/plan-id-goes-here/resourceGroups/group-name-goes-here/providers/Microsoft.KeyVault/vaults/vault-name-goes-here"
},
"secretName": "super-secret-name-goes-here"
}
}
I then reference the parameter in the ARM template, resources -> properties -> siteConfig -> appSettings
{
"name": "AzureWebJobsStorage",
"value": "[parameters('storageAccountSecret')]"
},
Above works fine! However, our team also periodically rotate our keys which change the underlying value of the secret. With my current approach, the secret on this function app config won't update until we run the ARM template again.
My get around is to use KeyVault Reference in the config, with the following syntax in the configuration.
#Microsoft.KeyVault(SecretUri=https://vault-name-goes-here.vault.azure.net/secrets/super-secret-name-goes-here/)
Now when the underlying secret changes, my function App will still get the up to date secret. However this require me to do it manually. I would love to achieve the same effect with just the ARM template alone, is that possible? 🤔
For exactly that reason you should always use the full URL to your secrets in Key Vault - including the version. See here.
When you update a secret in Key Vault, you get a new URL. Once you update the app setting (through your ARM template or any other way), the Function will be restarted. This is the desired behavior when updating app settings.

ARM Template: Looking up a user object Id

I'm trying to programatically insert the object Id of a certain user account into an ARM template, like this:
"objectId": "[reference(resourceId('Microsoft.AAD/domainServices/user/read','domain','User.Name'),'2019-01-01').Id]",
I've tried many different resource providers in an attempt to get this to work. For example:
"objectId": "[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities/read','user#domain.onmicrosoft.com'),'2019-01-01').Id]",
and:
"objectId": "[reference(resourceId('Microsoft.Portal/usersettings/read','user#domain.onmicrosoft.com'),'2018-10-01').Id]"
I looked up the API call used to get a list of users, to see if that would hint at the correct provider to use (it didn't):
GET https://graph.windows.net/{TenantId}/users?api-version=1.6 HTTP/1.1
I've been looking through this list of provider operations but have found two problems with this:
1 I can't see an operation which looks relevant to what I want to do.
2 It doesn't provide information on what parameters are required.
So I guess I have two questions really:
How do I dynamically look up the ObjectId of a user in an ARM template?
How do I find out in future which lookup functions are available and which parameters are required?
You could not insert the user object Id in the ARM template.
The user account is managed by your Azure AD tenant, it is not the azure resource, the ARM template is for the azure resources in your subscription.
Reference:https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-overview
Azure Resource Manager is the deployment and management service for Azure. It provides a consistent management layer that enables you to create, update, and delete resources in your Azure subscription.
You can try from below code if you have VM in same template and enabled managed identity
https://learn.microsoft.com/en-us/azure/azure-resource-manager/resource-group-template-functions-resource#remarks-1
{
"type": "Microsoft.KeyVault/vaults",
"properties": {
"tenantId": "[reference(concat('Microsoft.Compute/virtualMachines/', variables('vmName')), '2017-03-30', 'Full').identity.tenantId]",
"accessPolicies": [
{
"tenantId": "[reference(concat('Microsoft.Compute/virtualMachines/', variables('vmName')), '2017-03-30', 'Full').identity.tenantId]",
"objectId": "[reference(concat('Microsoft.Compute/virtualMachines/', variables('vmName')), '2017-03-30', 'Full').identity.principalId]",
"permissions": {
"keys": [
"all"
],
"secrets": [
"all"
]
}
}
]
I find the best way to achieve this is to expose the ID as a parameter, then when you call the ARM template deployment, simply pass the parameter into the template.
How do you get the ID into the template parameter? Well, I run my ARM deployments via Azure DevOps CI/CD and I use the pipeline task AzureAppConfiguration.azure-app-configuration-task.custom-build-release-task.AzureAppConfiguration#1 to extract the ID from my own custom configuration setup.
How do you get the ID into the Azure App Configuration service? Well, when I seed an environment for the first time there will be some initial setup, e.g. users and groups. I just then run some scripts to extract this kind of "metadata" into my Azure App Configuration service.
e.g.
APP_ID=$(az ad sp list --all --query "[?displayName=='name-of-spn'].appId" --output tsv)
az appconfig kv set --name name-of-app-config-store --key name-of-spn-app-id --value ${APP_ID}
I think I have solution.
I am tying to refer to a Client ID in a Managed User Identity generated by an ARM template.
I have declared the name of the Managed Identity as a Parameter to use as an administrator for an SQL server:
[reference(resourceId('Microsoft.ManagedIdentity/userAssignedIdentities',parameters('managed-identity')), '2018-11-30', 'full').properties.clientId]
Once you switch our the parameter you should be good to go.

Azure Logic App creation of Redis Cache requires x-ms-api-version

I'm building an Azure Logic App and try to automate the creation of an Azure Redis Cache. There is a specific action for this (Create or update resource) which I was able to bring up:
As you can see I entered 2016-02-01 as the api version. I was trying different values here just guessing from other api versions I know from Microsoft. I can't find any resource on this on the internet. The result of this step will be:
{
"error":
{
"code": "InvalidResourceType",
"message": "The resource type could not be found in the namespace 'Microsoft.Cache' for api version '2016-02-01'."
}
}
What is the correct value for x-ms-api-version and where can I find the history for this value based on the resource provider?
Try
Resource Provider: Microsoft.Cache
Name: Redis/<yourrediscachename>
x-ms-api-version: 2017-02-01
One easy way to know the supported versions for each resource type is using CLI on your Azure Portal, e.g.
az provider show --namespace Microsoft.Cache --query "resourceTypes[?resourceType=='Redis'].apiVersions | [0]"
would return:
[
"2017-02-01",
"2016-04-01",
"2015-08-01",
"2015-03-01",
"2014-04-01-preview",
"2014-04-01"
]
I made it work with:
HTH

Resources