Best Practices for Moving Azure Function App Environment Variables to Key Vault

Vishal Bhalabar 0 Reputation points
2026-09-04T07:27:27.25+00:00

Context

We have an existing Azure Function App running on Python 3.11.4. Our goal is to move sensitive data (like API keys and connection strings) out of the local app settings and into an Azure Key Vault.

Currently, our environment variables include a mix of custom secrets and platform-managed system variables, such as:

  • XDG_CACHE_HOME
  • APPINSIGHTS_INSTRUMENTATIONKEY
  • APPLICATIONINSIGHTS_CONNECTION_STRING
  • AzureFunctionsJobHost__functionTimeout
  • AzureWebJobsFeatureFlags
  • AzureWebJobsStorage
  • BUILD_FLAGS
  • FUNCTION_APP_EDIT_MODE
  • FUNCTIONS_EXTENSION_VERSION
  • FUNCTIONS_WORKER_RUNTIME
  • SCM_DO_BUILD_DURING_DEPLOYMENT

We have a few specific questions regarding what can safely be removed, referenced, or transitioned.


Questions

  1. Regarding AzureWebJobsStorage

We enabled a Managed Identity on the Function App and assigned the Storage Blob Data Owner and Storage Table Data Contributor roles to the storage account. After deleting the AzureWebJobsStorage environment variable and adding AzureWebJobsStorage__accountName environment variable, the Function App continues to work perfectly.

  • Is completely deleting this variable the recommended approach, or are additional configuration changes required to ensure long-term stability?
  1. Regarding APPLICATIONINSIGHTS_CONNECTION_STRING

When we moved APPLICATIONINSIGHTS_CONNECTION_STRING to the Key Vault and deleted the environment variable from the Function App configuration, the Function App stopped working. We made code changes in function app to refer app insight key from key vault but still that didn't work.

  • Can we reference APPLICATIONINSIGHTS_CONNECTION_STRING from Key Vault using @Microsoft.KeyVault(...) syntax in the App Settings?
  • If not, is it mandatory to keep this specific string directly inside the Function App's environment variables?
  1. Regarding System and Deployment Variables

Do we need to migrate the remaining platform-specific variables (e.g., FUNCTIONS_EXTENSION_VERSION, FUNCTIONS_WORKER_RUNTIME, SCM_DO_BUILD_DURING_DEPLOYMENT, BUILD_FLAGS) to Key Vault?

  • What would be the performance or operational impact if we attempted to move or reference these through Key Vault?
  1. Key Vault Reference Latency & Scaling
  • If we use Key Vault references (@Microsoft.KeyVault(...)) for our custom API keys, does it introduce cold-start latency or performance bottlenecks during high-scaling events for a Python Function App?
  1. Key Vault Secret Rotation
  • If we use Key Vault references for our application secrets, will the Function App automatically pick up updated secret versions without restarting, or is a manual restart required?
Azure Functions
Azure Functions

An Azure service that provides an event-driven serverless compute platform.

0 comments No comments

3 answers

Sort by: Oldest
  1. Fabian Zankl 185 Reputation points
    2026-09-04T08:25:11.67+00:00

    Hi @Vishal Bhalabar ,

    You have already moved the host storage connection to a managed identity and now want to know what else in the function app configuration can move to Key Vault, what must stay, and how references behave under scale and rotation. Taking the five points in order.

    AzureWebJobsStorage

    Deleting AzureWebJobsStorage and adding AzureWebJobsStorage__accountName is the documented configuration, not a workaround. The app settings reference describes __accountName as the setting to use instead of the connection string in an identity-based host storage connection. The roles you assigned also match the documentation: Storage Blob Data Owner is the minimum for the host, and Storage Table Data Contributor is the addition recommended so the host can persist diagnostic events.

    Four things determine whether this stays stable beyond the first test:

    • Triggers that depend on host storage. Blob Storage, Event Hubs, Durable Functions and Timer triggers all rely on AzureWebJobsStorage. The extension versions your app uses must themselves support identity-based connections, and several of these bindings need broader storage roles than the host alone; the Bindings tab of the linked page lists the requirement per extension.
    • Hosting plan. On a Consumption or Elastic Premium plan the app also uses Azure Files through WEBSITE_CONTENTAZUREFILECONNECTIONSTRING, and Azure Files does not support managed identity. The documented recommendation for those plans is to keep that one connection string and store it as a Key Vault reference, together with WEBSITE_SKIP_CONTENTSHARE_VALIDATION=1 and a content share that already exists, because the platform no longer validates or creates it (see Considerations for Azure Files mounting). Your settings list does not show that variable, which either means you are on a Dedicated or Flex Consumption plan, or you left it out. If it exists, it still contains an account key today.
    • Remote build. Your list includes SCM_DO_BUILD_DURING_DEPLOYMENT. On a Linux Consumption plan the remote build stores deployment artifacts through the AzureWebJobsStorage connection, and the same page states that with an identity-based connection you must deploy from an external deployment package instead. If you are on Linux Consumption, verify that your next deployment still succeeds before treating the migration as done.
    • Disabling shared key access. If your goal is to disable account key access on the storage account, do it only after the Azure Files point above is resolved, because that share is still key-based.

    APPLICATIONINSIGHTS_CONNECTION_STRING

    Two separate points here.

    Key Vault references do work for this setting, but the App Service documentation recommends configuring it directly instead: the portal uses APPINSIGHTS_INSTRUMENTATIONKEY and APPLICATIONINSIGHTS_CONNECTION_STRING to surface telemetry on the function app, and that integration stops working when the value comes from Key Vault. The same page points out that the connection string is not treated as a secret. The Azure Monitor documentation on connection strings says the same thing more directly: the instrumentation key identifies the target resource and is not a security token.

    Why the code change did not help: the Functions host itself writes its logs to Application Insights using this setting (it is listed as a host-required connection). Code in your Python functions that fetches the value from Key Vault only affects SDK calls you make yourself; the host never sees it. As for the app failing outright, that depends on what you did with the setting. If you replaced its value with a Key Vault reference, check the resolution status (Environment variables, edit the setting, the dialog shows the status); an unresolved reference hands the host the literal @Microsoft.KeyVault(...) string as its connection string, which is the documented failure mode for a missing Key Vault Secrets User role, a vault firewall, or a syntax error. If you deleted the setting entirely, the host simply runs without Application Insights, so a hard failure then points at the code change: a Key Vault SDK call executed at module import that fails (identity without the Secrets User role, or no network path to the vault) raises before your functions are indexed, and the app then shows no functions at all rather than a telemetry gap. The function app log stream or the Diagnose and solve problems blade will show which of the two it was.

    The recommendation: leave APPLICATIONINSIGHTS_CONNECTION_STRING as a plain app setting. What protects the Application Insights resource is requiring Entra authentication for ingestion, since the instrumentation key was never a credential in the first place. That is the identity-based equivalent of what you did for storage: set APPLICATIONINSIGHTS_AUTHENTICATION_STRING to Authorization=AAD, assign the managed identity the Monitoring Metrics Publisher role scoped to the Application Insights resource (despite the name, that role publishes all telemetry types, not only metrics), and then disable local authentication on that resource. The connection string stays where it is; it just no longer grants ingestion on its own.

    While you are there, remove APPINSIGHTS_INSTRUMENTATIONKEY. The reference page states the two settings should not both be present, and the connection string is the one to keep.

    Platform and deployment settings

    None of FUNCTIONS_EXTENSION_VERSION, FUNCTIONS_WORKER_RUNTIME, SCM_DO_BUILD_DURING_DEPLOYMENT, BUILD_FLAGS, FUNCTION_APP_EDIT_MODE, AzureWebJobsFeatureFlags or AzureFunctionsJobHost__functionTimeout contains a secret. They are runtime selectors, build switches and host.json overrides. Moving them to Key Vault buys nothing and adds a resolution dependency to settings the platform reads before your code runs. FUNCTION_APP_EDIT_MODE is managed by the runtime based on language stack and deployment status, and the app setting considerations warn that changing read-only platform settings can leave the app unresponsive. Leave all of these as they are.

    The rule of thumb: only values that grant access to something (API keys, connection strings that embed a key, tokens) belong in Key Vault, and only where the target service cannot be reached with a managed identity.

    Latency and scaling

    App Service resolves Key Vault references at the platform level and hands the resolved value to your code as an ordinary environment variable; the documentation states the values are cached and refetched every 24 hours, and the app code needs no changes. Your Python code therefore does not call Key Vault on any request path, and the reference count does not scale with invocations.

    What the documentation does not publish is how long the resolution step adds to an instance start, or whether every newly scaled-out instance performs its own fetch. If that matters for your scaling profile, the check is empirical: enable Key Vault diagnostic logging and correlate SecretGet events against scale-out events over a load test. Absent that measurement, the model consistent with the documentation is a per-instance-start fetch of a handful of secrets, not a per-request one.

    Rotation

    If the reference omits a secret version, the app uses the latest version. When a new version is created, the app picks it up automatically within 24 hours because of the cache described above; no manual restart is required for that path. Two ways to shorten the window are documented on the same page: any configuration change restarts the app and refetches all references immediately, or you can force resolution without a config change by an authenticated POST to https://management.azure.com/<function app resource ID>/config/configreferences/appsettings/refresh?api-version=2022-03-01.

    If you pin a version in the reference, rotation requires updating the reference itself, which is a configuration change and therefore restarts the app.

    References


    Drafted with help from Claude, disclosed per the Q&A AI usage policy. All technical claims checked against the Microsoft Learn pages listed under References.

    Was this answer helpful?

    0 comments No comments

  2. Tejaswini Billakurthi 270 Reputation points Microsoft External Staff Moderator
    2026-09-07T10:40:21.7833333+00:00

    Hello @Vishal Bhalabar ,

    Thank you for the detailed question.

    I agree with the answer provided by @Fabian Zankl . It aligns with the current Microsoft Learn guidance. Summarising the conclusions for clarity:

    1. AzureWebJobsStorage

    Deleting the connection string and configuring AzureWebJobsStorage__accountName is the documented identity-based configuration, not a workaround. The roles you assigned align with the documented minimum permissions required for host storage access.

    1. APPLICATIONINSIGHTS_CONNECTION_STRING

    Although Key Vault references are supported for this setting, Microsoft documentation notes that portal-integrated telemetry experiences are unavailable when the Application Insights settings are sourced from Key Vault. Since the connection string is not considered a secret, many customers choose to keep it as a regular app setting.

    If APPLICATIONINSIGHTS_CONNECTION_STRING is configured, Microsoft recommends not using APPINSIGHTS_INSTRUMENTATIONKEY alongside it.

    Reference: Considerations for Application Insights instrumentation

    1. Platform and deployment variables

    FUNCTIONS_EXTENSION_VERSION, FUNCTIONS_WORKER_RUNTIME, SCM_DO_BUILD_DURING_DEPLOYMENT, BUILD_FLAGS, FUNCTION_APP_EDIT_MODE, AzureWebJobsFeatureFlags, AzureFunctionsJobHost__functionTimeout and XDG_CACHE_HOME contain no secrets. Leave them in app settings. Moving them to Key Vault provides no security benefit and introduces a resolution dependency on settings the platform reads before your code runs.

    1. Latency and scaling

    Key Vault references are resolved at the platform level and passed to your code as ordinary environment variables. Your Python code does not call Key Vault on any request path, so reference usage does not scale with invocation volume.

    1. Secret rotation

    If the reference does not pin a secret version, the app picks up the latest version automatically within 24 hours, with no restart required. This is because App Service caches reference values and refetches them every 24 hours. Any configuration change restarts the app and triggers an immediate refetch.

    Reference: Understand rotation

    Regarding the failure you encountered

    To identify the exact cause, please run the built-in detector: Diagnose and solve problems > Availability and Performance > Function app down or reporting errors > Key Vault Application Settings Diagnostics.

    When a reference fails to resolve, the literal @Microsoft.KeyVault(...) string is passed to the host. The common causes are a missing Key Vault Secrets User role assignment, a Key Vault firewall restriction, or a syntax error in the reference.

    Reference: Troubleshoot Key Vault references

    One point to confirm

    Could you please confirm which hosting plan the Function App uses? If it is Consumption or Elastic Premium, the WEBSITE_CONTENTAZUREFILECONNECTIONSTRING setting also applies. That setting still contains a storage account key and requires separate handling before you disable shared key access on the storage account.

    Please "Accept the Answer" if this information helped you. This will help us and others in the community as well.

    Was this answer helpful?

    0 comments No comments

  3. Vishal Bhalabar 0 Reputation points
    2026-09-07T10:54:59.41+00:00

    @Fabian Zankl , @Tejaswini Billakurthi ,

    Thank you for the detailed clarification.

    Based on your recommendations, we will proceed with the following changes, Kindly confirm.

    1.Keep AzureWebJobsStorage removed and continue using AzureWebJobsStorage__accountName with Managed Identity.

    2.Keep APPLICATIONINSIGHTS_CONNECTION_STRING directly in Function App settings.

    3.Remove APPINSIGHTS_INSTRUMENTATIONKEY from Function App settings.

    4.Do not move platform/runtime configuration such as FUNCTIONS_WORKER_RUNTIME, FUNCTIONS_EXTENSION_VERSION, SCM_DO_BUILD_DURING_DEPLOYMENT, BUILD_FLAGS, AzureWebJobsFeatureFlags, etc. to Key Vault.

    Question:

    1.APPLICATIONINSIGHTS_AUTHENTICATION_STRING=Authorization=AAD is required in Function app settings?

    Was this answer helpful?


Your answer

Answers can be marked as 'Accepted' by the question author and 'Recommended' by moderators, which helps users know the answer solved the author's problem.