Azure / static-web-apps

Azure Static Web Apps. For bugs and feature requests, please create an issue in this repo. For community discussions, latest updates, kindly refer to the Discussions Tab. To know what's new in Static Web Apps, visit https://aka.ms/swa/ThisMonth
https://aka.ms/swa
MIT License
325 stars 56 forks source link

Auth fails when used with Bicep template Microsoft.Web/staticSites/config@2022-03-01 #1076

Closed johnnyreilly closed 1 year ago

johnnyreilly commented 1 year ago

Describe the bug

We use Bicep to deploy all of our Azure resources as an organisation. When upgrading one of our apps to use the latest Bicep templates, we uncovered an issue with the Microsoft.Web staticSites/config 'appsettings' 2022-03-01 Bicep template.

A clear and concise description of what the bug is.

To Reproduce Steps to reproduce the behavior:

  1. Deploy an Azure Static Web App using Bicep / ARM templates.
  2. The app should use authentication backed by Azure AD which is configured via a Microsoft.Web/staticSites/config@2022-03-01 Bicep / ARM template
  3. Authentication should result in an endless loop.

staticwebapp.config.json:

{
    "auth": {
        "identityProviders": {
            "azureActiveDirectory": {
                "registration": {
                    "openIdIssuer": "https://login.microsoftonline.com/6d6a11bc-469a-48df-a548-d3f353ac1be8/v2.0",
                    "clientIdSettingName": "AAD_CLIENT_ID",
                    "clientSecretSettingName": "AAD_CLIENT_SECRET"
                }
            }
        }
    },
    "navigationFallback": {
        "rewrite": "index.html"
    },
    "routes": [
        {
            "route": "/login",
            "rewrite": "/.auth/login/aad",
            "allowedRoles": ["anonymous", "authenticated"]
        },
        {
            "route": "/.auth/login/github",
            "statusCode": 404
        },
        {
            "route": "/.auth/login/twitter",
            "statusCode": 404
        },
        {
            "route": "/logout",
            "redirect": "/.auth/logout",
            "allowedRoles": ["anonymous", "authenticated"]
        },
        {
            "route": "/*.json",
            "allowedRoles": ["authenticated"]
        }
    ],
    "responseOverrides": {
        "401": {
            "redirect": "/login",
            "statusCode": 302
        }
    },
    "globalHeaders": {
        "content-security-policy": "default-src https: 'unsafe-eval' 'unsafe-inline'; object-src 'none'"
    },
    "mimeTypes": {
        ".json": "text/json",
        ".md": "text/markdown",
        ".xml": "application/xml"
    }
}

staticwebapp.bicep

@description('Tags that our resources need')
param tags object

@description('Location for the resources')
param location string

@description('Type of managed service identity. SystemAssigned, UserAssigned. https://docs.microsoft.com/en-us/azure/templates/microsoft.web/staticsites?tabs=bicep#managedserviceidentity')
param identityType string = 'SystemAssigned'

@description('The list of user assigned identities associated with the resource.')
param userAssignedIdentities object = {}

@description('The SKU for the static site. https://docs.microsoft.com/en-us/azure/templates/microsoft.web/staticsites?tabs=bicep#skudescription')
param sku object = {
  name: 'Standard'
  tier: 'Standard'
}

@description('Lock the config file for this static web app. https://docs.microsoft.com/en-us/azure/templates/microsoft.web/staticsites?tabs=bicep#staticsite')
param allowConfigFileUpdates bool = true

@description('Where the repository lives eg https://dev.azure.com/investec/investec-cloud-experience/_git/tea-and-biscuits')
param repositoryUrl string

@description('The branch being deployed eg main')
param repositoryBranch string

@description('The name of the static site eg stapp-tab-prod-001')
param staticSiteName string

@secure()
@description('Configuration for your static site')
param appSettings object = {}

@secure()
@description('Configuration for your static site function app')
param functionAppAppSettings object = {}

@description('Build properties for the static site.')
param buildProperties object = {}

@allowed([
  'Disabled'
  'Disabling'
  'Enabled'
  'Enabling'
])
@description('State indicating the status of the enterprise grade CDN serving traffic to the static web app.')
param enterpriseGradeCdnStatus string = 'Disabled'

@allowed([
  'Disabled'
  'Enabled'
])
@description('State indicating whether staging environments are allowed or not allowed for a static web app.')
param stagingEnvironmentPolicy string = 'Enabled'

@description('Template Options for the static site. https://docs.microsoft.com/en-us/azure/templates/microsoft.web/staticsites?tabs=bicep#staticsitetemplateoptions')
param templateProperties object = {}

@description('Custom domain name for the static side eg testing-swa.sbx.investec.io')
param customDomainName string = ''

resource staticSite 'Microsoft.Web/staticSites@2022-03-01' = { // https://docs.microsoft.com/en-us/azure/templates/microsoft.web/staticsites?tabs=bicep
  name: staticSiteName
  location: location
  tags: tags
  identity: {
    type: identityType
    userAssignedIdentities: empty(userAssignedIdentities) ? null : userAssignedIdentities
  }
  sku: sku
  properties: {
    allowConfigFileUpdates: allowConfigFileUpdates
    provider: 'DevOps' // see: https://github.com/Azure/static-web-apps/issues/516
    repositoryUrl: repositoryUrl
    branch: repositoryBranch
    buildProperties: empty(buildProperties) ? null : buildProperties
    enterpriseGradeCdnStatus: enterpriseGradeCdnStatus
    stagingEnvironmentPolicy: stagingEnvironmentPolicy
    templateProperties: empty(templateProperties) ? null : templateProperties
  }
}

resource customDomain 'Microsoft.Web/staticSites/customDomains@2022-03-01' = if(!empty(customDomainName)) {
  parent: staticSite
  name: !empty(customDomainName) ? customDomainName : 'blank' // https://github.com/Azure/bicep/issues/1754
  properties: {}
}

// THIS IS THE PROBLEM - 2021-03-01 works fine
resource staticSiteAppsettings 'Microsoft.Web/staticSites/config@2022-03-01' = { 
  parent: staticSite
  name: 'appsettings'
  kind: 'config'
  properties: appSettings
}
// THIS IS THE PROBLEM - 2021-03-01 works fine

resource staticWebAppFunctionAppSettings 'Microsoft.Web/staticSites/config@2022-03-01' = if(!empty(functionAppAppSettings)) {
  name: 'functionappsettings'
  kind: 'config'
  parent: staticSite
  properties: functionAppAppSettings
}

output defaultHostName string = staticSite.properties.defaultHostname // eg gentle-bush-0db02ce03.azurestaticapps.net
output siteName string = staticSite.name
output siteResourceId string = staticSite.id
output siteSystemAssignedIdentityId string = (staticSite.identity.type == 'SystemAssigned') ? staticSite.identity.principalId : ''

Expected behavior

Authentication should work.

Screenshots

N/A

Additional context

On February 14th 2023 I had a support call with Azure support person Sudarshan Yadav / sudyadav@microsoft.com to diagnose this. The case number was 2302130050002282

We'd be happy to share application code; we're essentially using the approach documented by @rick-roche here:

https://www.rickroche.com/2022/03/single-sign-on-azure-static-web-apps-and-azure-active-directory/

johnnyreilly commented 1 year ago

Just thought I'd share that for 3 days last week, this deployment started to work. We briefly thought "great! It's fixed!". It turns out that was not the case; the issue started reoccurring this weekend. You can't see it, but so it doesn't get lost, we have this PR in place which illustrates this issue:

https://dev.azure.com/investec/investec-cloud-experience/_git/azure-engineering-metrics/pullrequest/57942

We've got a deployed environment where it acts up:

https://victorious-sky-0b2e5e403.2.azurestaticapps.net/

thomasgauvin commented 1 year ago

Is this related to https://github.com/Azure/static-web-apps/issues/1089#issuecomment-1458710885?

johnnyreilly commented 1 year ago

yes definitely. And I think the reason auth may be failing, is because it seems that SWAs can only support one method of configuration at a time. So either the SWA config or the Function App config. If the Function App config is in play, the config the SWA needs for auth is "missing" as far as the SWA is concerned. So it looks like auth is broken - it may actually just be as a result of SWAs only supporting 1 config at a time; function app or SWA

johnnyreilly commented 1 year ago

Closing as was related to #1089 as suggested by @thomasgauvin