Table of contents

Introduction

This post will cover security considerations for the Kudu console in Logic App Standard. However, this is applicable to all Azure Web Apps (App Service, Function Apps Dedicated plans).

Logic App Standard allows you to use Environment Variables where the value is safely stored in a Key Vault containing secrets or connection strings. This makes it harder for users to view the secret and prevents exposure of secrets in code. However, anyone with Contributor or Owner rights to the Logic App can potentially exfiltrate these secrets, even if they don’t have direct Key Vault permissions.

If your user account or automation account has Contributor or Owner access to the Logic App, they effectively own the environment and can see all secrets injected there. This is expected behavior in Azure, so plan your RBAC strategy accordingly to maintain proper security boundaries.

TLDR; Kudu is considered an advanced debugging tool and all information, secrets or not, is readily available, as intended. Ones with Kudu access are ones owning the site. Therefore, access to this interface should be heavily restricted.

If you are giving your app access to secrets or possibly other APIs, and users have access to Kudu for that app, the users can access those secrets or APIs indirectly.

Dumping Key Vault secrets in Kudu

Using Kudu console to view Environment Variables

We will take this Environment Variable referencing a Key Vault Secret as an example. A user without access to the Key Vault containing the secret would not be able to enumerate the secret from this interface.

Appsetting In Azure Portal

In this example, the Key Vault reference is a connection string to a Storage Account. I do, however, recommend using Managed Identity for this setting, but that’s beside the point of this blog post. This works for any Key Vault secret.


When accessing the Logic Apps Kudu Console via the browser, users are authenticated with Entra ID. If you have the correct permission, you will gain access to the interface.

When looking at the Environment Variables presented, we can see that the value is initially hidden.

Environment Variables Hidden In Kudu

At the top of the home page, there is an option to reveal values of Key Vault references.

Show Key Vault Values

We can also, with a simple command in the Debug console using PowerShell, get the actual value of the Key Vault secret.

[System.Environment]::GetEnvironmentVariable("AzureWebJobsStorage")
PowerShell Fetching Enivornment Variable

It’s also possible to extract the actual Key Vault secret values using the Process Explorer interface.

Logic App Standard on Windows run in a secure environment called a sandbox. All Logic Apps have both a main site and an SCM site (where Kudu runs, including WebJobs). The Kudu site runs in the same sandbox as the real site. Each app is viewed by the sandbox as a tree of processes, rooted by the app’s main IIS (w3wp.exe) process. Each app’s lifetime begins with the creation of this w3wp.exe process, which, in turn, may spawn other child processes. You can view all Environment Variables by inspecting the w3wp.exe that doesn’t have the “SCM” tag.

Kudu Process Explorer

Here you can see the actual value of the Key Vault secret.

Kudu Process Explorer Environment Variable

Using Kudu console to dump secrets outside Environment Variables

When Managed Identity is enabled on the Logic App, a local HTTP endpoint that provides access tokens will be available in the sandbox. This can only be requested when running in Azure, on an App Service Plan, for example.

When enabled, you will have two environment variables available.

  • MSI_ENDPOINT
  • MSI_SECRET

Here is a PowerShell function that could be used in the debug console to retrieve an access token. Modify the Resource parameter for which resource you want to access. This will be the Audience in the token.

Function Get-MSIAccessToken {
    Param (
        [string]$Resource = "https://management.azure.com/"
    )
    $FetchToken = Invoke-RestMethod `
                    -Method Get `
                    -Headers @{ "X-IDENTITY-HEADER" = $env:IDENTITY_HEADER } `
                    -Uri "${env:MSI_ENDPOINT}?resource=${Resource}&api-version=2019-08-01"
    $AccessToken = $FetchToken.access_token
    Return $AccessToken
}
Get-MSIAccessToken

Executing the command in the Kudu debug console (PowerShell): Fetching MSI Access Token Via Local HTTP Endpoint

Since we can fetch an access token from the Logic App via Kudu, we can act as the Logic App. That means everything the app has permission to do, we can do as well. Let’s say that this Logic App has been given permissions on an entire Key Vault, which contains more secrets than this app is necessarily intended to see. We could dump all those secrets using Kudu. If we can do it, an attacker who steals our credentials can do it too.

If the Key Vault or other resource you want to extract data from has public access enabled, an attacker could extract the access token and then make the actual request to the Key Vault from another device.

We can utilize the local HTTP endpoint to fetch an access token, then make another HTTP request to the Key Vault, authenticating as the Logic App using the access token.

Here is a PowerShell function that could be used to fetch Key Vault secrets:

Function Get-KeyVaultSecret {
    Param (
        [string]$VaultName,
        [string]$SecretName
    )
    $Uri = "https://$VaultName.vault.azure.net/secrets/$SecretName"
    $Resource = "https://vault.azure.net"
    $FetchToken = Invoke-RestMethod `
                    -Method Get `
                    -Headers @{ "X-IDENTITY-HEADER" = $env:IDENTITY_HEADER } `
                    -Uri "${env:MSI_ENDPOINT}?resource=${Resource}&api-version=2019-08-01"
    $AccessToken = $FetchToken.access_token
    $Headers = @{'Authorization'="Bearer $AccessToken"}

    $Secret = Invoke-RestMethod -Method GET -Headers $Headers -Uri "${Uri}?api-version=7.4"
    Return $Secret.value
}
Get-KeyVaultSecret -VaultName "example-kv" -SecretName "example-secret"

Executing the command in the Kudu debug console (PowerShell): Fetching Key Vault Secret Using Access Token

Kudu Security Considerations

The Kudu can do and access anything the site itself can and has access to. For instance, Kudu can access all app settings, secrets, and certificates used by the site. It can also access the process memory of the site.

“Authorization wise, only users with publishing/deployment permission (such as Contributor RBAC role) can access Kudu. Those with such permission practically own the sites. For instance, they can deploy any content to the site as well as access all settings (secret or not) required by the site at runtime. Hence, Kudu UI intentionally does not hide or obscure any secret settings. It is considered an advanced debugging tool and all information is readily available.“

Source: https://github.com/projectkudu/kudu/wiki/Kudu-architecture#authentication-and-authorization-model

“Ones with Kudu access are ones owning the site, regardless if read only or not. To expand, they can deploy any code (good or malicious) and are able to read any secret settings of the site (for example KeyVault, SQL and Storage credentials, Private Certificates, etc.). Hence, for Azure, only those with Contributor or Owner access (to be exact, with microsoft.web/sites/publish/action or, for a slot, microsoft.web/sites/slots/publish/action) can access Kudu (SCM).“

Source: https://github.com/projectkudu/kudu/wiki/Accessing-the-kudu-service#security

Modifying workflows to dump secrets

If a user can modify the workflows in the Logic App, they can add new steps to fetch secrets from Key Vault (using the Logic App’s managed identity). A subsequent “Compose” or logging step can then output the secret. Again, this bypasses direct Key Vault permissions, because the app’s identity is doing the retrieval, not the portal user, obviously.

Is this really an issue?

By now, you might be thinking, “So what? This is all by design, not some kind of flaw. The product is working exactly the way it’s supposed to.” And you’d be right. There’s nothing broken here. Everything is functioning as intended.

The issue isn’t that these features exist or how they operate. The real concern is how they can be leveraged as part of a larger attack strategy, potentially undermining the security of not just a single Web App, but the entire Azure environment. If a user with the correct permissions can access this interface and have all these powerful capabilities, an attacker could potentially exploit this as well.

If these capabilities are easy for us to whip out and use, it’s also easy for the attacker.

This could also be an issue if the one designing the RBAC strategy isn’t fully aware of these risks, potentially exposing sensitive information or access to other systems to individuals who should never have access in the first place.

Mitigations

  1. Restrict Contributor and Owner Access: Don’t give every user the built in Contributor role. Instead, use a custom role without microsoft.web/sites/publish/action
  2. Create a custom role with the microsoft.web/sites/publish/action permission
  3. Grant full deployment permissions only when absolutely necessary, for a short time window using Privileged Identity Management (PIM)
  4. Scope Key Vault permissions to the minimal set of secrets. If an app only needs certain secrets, store them in a dedicated vault
  5. Monitor Azure Activity Logs and Key Vault access logs for unusual or suspicious secret retrievals