Azure App Service makes it easy to run a web app or function without managing servers, but every app ships with a second, highly privileged site (Kudu, the SCM endpoint), downloadable publishing credentials and an app settings blob that often holds every secret the application uses. Those three things, rather than the application code, are where many App Service compromises start. This guide covers how identity works on the platform: built-in authentication for users, managed identities for outbound access, deployment credentials and the Kudu site, Functions access keys, logging and a hardening baseline. It applies to web apps and to Azure Functions, which run on the same platform, and is written for cloud engineers, application security teams and platform owners.
Key takeaways
- Turn off basic authentication for FTP and SCM. Publishing profiles carry a username and password that work from anywhere; Entra ID, Azure Pipelines and GitHub Actions with OIDC replace them.
- Restrict the advanced tools site separately. Kudu has its own access restriction rules; unless you set them, or tell it to use the main site's rules, it may be more exposed than the app.
- Use managed identity and Key Vault references, not secrets in app settings. App settings are encrypted at rest, but anyone who can list them reads them in clear text.
- Built-in authentication authenticates; it does not authorise by default. With the Microsoft provider, any user in your tenant can obtain a token unless you restrict the app registration or check claims.
- Functions keys are shared secrets. The
_masterkey is an administrative credential; production APIs need Easy Auth, API Management or network isolation on top.
How identity and access work in App Service
An App Service app involves four distinct identity flows, each with its own controls.
| Flow | Mechanism | Credential | Primary control |
|---|---|---|---|
| End users to the app | Built-in authentication (Easy Auth) or app code | Session cookie or bearer token | Require authentication, app registration assignment, claims checks |
| App to Azure resources | System-assigned or user-assigned managed identity | Token from the local identity endpoint | Least-privilege role assignments on targets |
| Deployment to the app | Kudu/SCM, FTP, ZIP deploy, pipelines | Publishing credentials (basic auth) or Entra ID tokens | Disable basic auth; OIDC federation for CI |
| Administrators to the resource | Azure RBAC on the app, plan and resource group | Entra ID user or service principal | Role scope, PIM, policy |
Built-in authentication
Easy Auth is platform middleware that runs before your code: on Windows as a native IIS module in the app's sandbox, on Linux and containers as a separate container. It supports Microsoft Entra, Google, GitHub, Facebook, X, Apple (preview) and any OpenID Connect provider, and exposes sign-in at /.auth/login/<provider>.
- Require authentication: rejects anonymous traffic at the platform with 302 (websites), 401 (APIs), 403 or 404. "Allow unauthenticated requests" defers the decision to your code, which is where mistakes happen.
- Authorisation is yours: Microsoft notes that with the Microsoft identity provider any user in the tenant can request a token by default. Set the enterprise application to require assignment, or check roles and groups in claims.
- Token store: holds ID, access and refresh tokens per session so the app can call downstream APIs. Disable it if the app does not need tokens.
- Per-slot app registrations: use separate registrations for each deployment slot so test environments cannot affect production permissions.
- Behind a proxy: when fronted by Azure Front Door, set
forwardProxytoStandardinauthsettingsV2so redirect URIs use the Front Door host name.
Easy Auth also enforces HTTPS redirection (requireHttps) and rejects cookie-authenticated cross-site POSTs from browsers whose Origin or Referer is not approved. It accepts PKCE parameters from the client but does not generate them. See the OAuth 2.1, GNAP and FAPI Guide.
Admin roles and privileged access
- Treat config read as secret read: anyone with a role that can list app configuration or download the publishing profile can read connection strings, app settings and deployment passwords. Contributor-level roles on the app, its resource group or subscription include these actions; Reader does not.
- Scope roles to the app: grant Website Contributor or custom roles on individual apps rather than Contributor on the resource group, and use Privileged Identity Management for standing administrative access. See the Azure RBAC and Service Principals Guide.
- Stop basic auth being re-enabled: create a custom role that places write on
microsoft.web/sites/basicPublishingCredentialsPoliciesand its slot equivalent in NotActions, so app owners cannot quietly turn publishing passwords back on. - Govern with Azure Policy: built-in definitions audit and remediate FTP and SCM basic authentication for apps and slots. See the Azure Policy and Management Groups Guide.
The Kudu (SCM) site
Every app has an advanced tools site, usually reached at the app's .scm. host name. It provides deployment endpoints, a file browser, a debug console and process and environment views, which means it can read the app's files and runtime environment, including secrets resolved into environment variables. Access to it is authenticated either by publishing credentials (basic auth) or by Entra ID for users who hold suitable RBAC roles. Protect it on three levels:
- Disable SCM basic authentication so only Entra ID identities can reach it.
- Apply access restrictions to the advanced tools site: it has its own rule collection and unmatched-rule action. Either select "use main site rules" or set its unmatched action to Deny and allow only build agents or administrator networks.
- Use private endpoints for deployment where possible; access restrictions do not apply to traffic entering through a private endpoint, which is governed by network security groups instead.
Integrations, API tokens and service accounts
Managed identity
A system-assigned identity is tied to the app and deleted with it; a user-assigned identity is a standalone resource that can be shared across apps. Identity configuration is specific to each deployment slot. Inside the app, the platform exposes IDENTITY_ENDPOINT and IDENTITY_HEADER; code requests a token with the X-IDENTITY-HEADER header and api-version=2019-08-01. The header value is rotated by the platform and exists to mitigate server-side request forgery, so never echo environment variables in error pages or diagnostics endpoints.
- Least privilege on targets: a token alone is not enough; the identity needs a role on each Key Vault, storage account or database. Microsoft notes back-end services cache group and role membership for around 24 hours, so revocation is not instant.
- Specify the identity: when using a user-assigned identity, pass
client_id,principal_idormi_res_id; otherwise the request falls back to the system-assigned identity. - Shared user-assigned identities: convenient, but one compromised app then holds every permission the identity has. Prefer one identity per app or per trust boundary.
See the Azure Managed Identities Security Guide.
Key Vault references
App settings of the form @Microsoft.KeyVault(SecretUri=https://myvault.vault.azure.net/secrets/mysecret) or @Microsoft.KeyVault(VaultName=myvault;SecretName=mysecret) resolve at runtime through the app's identity (system-assigned by default, or the one set in keyVaultReferenceIdentity). Grant Key Vault Secrets User on the vault. Unversioned references pick up the latest version, refetched every 24 hours or on any configuration change; a refresh API forces it sooner. Mark references as slot settings so each environment uses its own vault, and for network-restricted vaults route outbound traffic through the virtual network (vnetRouteAllEnabled on Linux). See the Azure Key Vault Security Guide.
Deployment credentials and CI/CD
| Deployment method | After disabling basic auth | Recommended replacement |
|---|---|---|
| FTP / FTPS | Stops working | ZIP deploy via Entra ID; set FTP state to Disabled |
| Local Git, Bitbucket, GitHub or Azure Repos with App Service build service | Stops working | Pipeline-based deployment |
Azure CLI az webapp deploy (2.48.1 and later) | Falls back to Entra ID | Keep, with a scoped identity |
| Visual Studio 2022 17.12 and later | Falls back to Entra ID | Keep for developers in non-production only |
Azure Pipelines AzureWebApp task | Keeps working | Workload identity federation service connection |
| GitHub Actions using a publish profile | Must be recreated | User-assigned identity with OpenID Connect |
A publish profile stored as a CI secret is a static password to production. Federated credentials remove it entirely. See the GitHub Actions OIDC Federation Hardening Guide.
Azure Functions access keys
- Authorisation levels:
anonymous(no key),function(function or host key) andadmin(master key). - Key types: function keys (one function, least privilege), host keys (all functions in the app), the
_masterkey (the app plus runtime admin APIs under/admin/) and system keys used by extensions. - Handling: send keys in the
x-functions-keyheader rather than thecodequery string so they stay out of URLs and logs. Disable the admin endpoints withfunctionsRuntimeAdminIsolationEnabledwhere not needed. - Storage: keys are kept encrypted in the
AzureWebJobsStorageaccount by default;AzureWebJobsSecretStorageType=keyvaultmoves them to Key Vault (use a separate vault per function app). Anyone with access to that storage account can therefore reach the keys. - Revocation: deleting and recreating a function with the same name reuses its stored keys. Rotate or delete keys explicitly.
Logging and detection
| Source | What it records | Detection use |
|---|---|---|
| AppServiceAuditLogs | Logins over FTP and to Kudu, with user, source address and protocol | Any basic auth login after you disabled it; logins from unknown addresses |
| AppServiceIPSecAuditLogs | Requests matching access restriction rules | Validating rules; probes of the SCM site |
| AppServiceFileAuditLogs (Premium and above) | File changes to site content | Web shells and out-of-band changes outside deployments |
| AppServiceHTTPLogs, AppServiceConsoleLogs, AppServiceAppLogs | Web server, stdout/stderr and application logs | Exploitation attempts, errors leaking secrets |
| AppServicePlatformLogs | Container operations | Unexpected restarts or image changes |
| Azure Activity Log | "Get Web App Publishing Profile", "Newpassword Web Apps", configuration changes, slot swaps | Credential harvesting and persistence by administrators or stolen identities |
| Microsoft Defender for App Service | Posture findings and threat alerts | Platform-level detections |
Resource logs are not collected until you add a diagnostic setting, so apply one through Azure Policy to every app. The highest-value alerts are publishing profile downloads, any basic auth login, configuration list operations by unusual identities and file changes outside deployment windows.
Metrics
- Percentage of apps and slots with FTP and SCM basic authentication disabled.
- Percentage of apps whose SCM site denies unmatched traffic or uses main site rules.
- Number of app settings containing literal secrets rather than Key Vault references.
- Percentage of apps with diagnostic settings sending AppServiceAuditLogs to the SIEM.
- Number of Functions using the master key outside administration.
Hardening baseline
- Inventory deployment paths: list every app and slot, how it is deployed and which use publish profiles, FTP or Local Git. Turn on the Azure Policy audit definitions for FTP and SCM basic auth to get the list.
- Move CI/CD to federation: recreate GitHub Actions with OIDC and Azure Pipelines with workload identity federation. Test in a non-production slot first.
- Disable basic auth: set FTP and SCM Basic Auth Publishing Credentials to Off, slot by slot, then enforce with the remediation policies and the custom NotActions role. Roll back per app by switching the setting on temporarily while fixing the pipeline; AppServiceAuditLogs shows who still tries to use it.
- Lock down transport: HTTPS Only on, minimum TLS 1.2 for app and SCM site, FTP state Disabled or FTPS only, client certificates where callers support them.
- Restrict networks: access restrictions on the main and advanced tools sites, Front Door with the
AzureFrontDoor.Backendservice tag plus anX-Azure-FDIDheader filter where used, private endpoints for internal apps, and App Service Environment where full isolation is required. - Move secrets: managed identity per app, Key Vault references for every secret, then remove literal values from app settings.
- Turn on logging and Defender: diagnostic settings by policy, alerts on the events above, and Defender for App Service.
Small teams with a few apps can do all of this in a sprint and should start with basic auth and Key Vault references. Large estates should drive it through Azure Policy at management group scope, accept a staged remediation per business unit and track the metrics above as the programme scorecard.
Common misconfigurations
- Publish profile in a CI secret or developer laptop: a static, internet-usable credential that deploys code to production.
- SCM site left open: main site behind Front Door, Kudu reachable from anywhere with basic auth enabled.
- Literal secrets in app settings: every Contributor and every Kudu session can read them. Hard-coded framework secrets carry similar risk: the ASP.NET machine key attacks showed static keys copied from public samples enabling remote code execution on IIS-hosted ASP.NET applications, a pattern that applies to apps hosted on Windows App Service too.
- "Allow unauthenticated requests" with no code checks: the app assumes the platform authenticated users when it did not.
- Tenant-wide access through Easy Auth: any employee or guest in the tenant can sign in because assignment was never required.
- Master key used by clients: a Functions admin credential embedded in a front end or shared with a partner.
Framework mapping
| Framework | Reference | App Service control |
|---|---|---|
| NIST SP 800-53 Rev. 5 | IA-5 | Remove publishing passwords; Key Vault references |
| NIST SP 800-53 Rev. 5 | AC-6, AC-17 | Scoped RBAC, SCM access restrictions |
| NIST SP 800-53 Rev. 5 | SC-8 | HTTPS Only, minimum TLS |
| NIST SP 800-53 Rev. 5 | AU-2, AU-12 | Diagnostic settings for audit and file logs |
| NIST CSF 2.0 | PR.AA-01, PR.AA-05, PR.PS-04 | Identity management, least privilege, logging |
| MITRE ATT&CK | T1078.004, T1552.001, T1505.003 | Stolen cloud accounts, credentials in files, web shells |
Practitioner checklist
- Disable FTP and SCM basic authentication on every app and slot, and enforce it with Azure Policy.
- Replace publish profiles in CI with OIDC or workload identity federation.
- Restrict the advanced tools site with its own rules or the main site's rules.
- Enable managed identity per app and grant only the target roles it needs.
- Move every secret in app settings to Key Vault references.
- Require authentication in Easy Auth and require user assignment on the app registration.
- Use function keys, not host or master keys, and pass them in the header.
- Send AppServiceAuditLogs, IPSec and file audit logs to the SIEM and alert on publishing profile downloads.
- Set HTTPS Only, minimum TLS 1.2 and FTP state Disabled.
Standards and references
- Microsoft Learn: Disable basic authentication in App Service deployments
- Microsoft Learn: Use managed identities for App Service and Azure Functions
- Microsoft Learn: Authentication and authorization in Azure App Service and Azure Functions
- Microsoft Learn: Azure App Service access restrictions
- Microsoft Learn: Use Key Vault references as app settings
- Microsoft Learn: Work with access keys in Azure Functions
- Microsoft Learn: Security in Azure App Service
- Microsoft Learn: Azure App Service monitoring data reference
Related NHI Mgmt Group resources: Azure Managed Identities Security Guide · Azure Key Vault Security Guide · Microsoft Azure Security Guide · Cloud Workload Identity Guide