Esercitazione: Creare un'app a più livelli sicura nel servizio app Azure

Molte applicazioni hanno più di un singolo componente. Ad esempio, potrebbe essere disponibile un front-end accessibile pubblicamente e si connette a un'API back-end o a un'app Web che a sua volta si connette a un database, a un account di archiviazione, a un insieme di credenziali delle chiavi, a un'altra macchina virtuale o a una combinazione di queste risorse. Questa architettura costituisce un'applicazione a più livelli. È importante progettare applicazioni di questo tipo per proteggere al massimo le risorse back-end.

Questa esercitazione illustra come distribuire un'applicazione a più livelli sicura con un'app Web front-end che si connette a un'altra app Web isolata dalla rete. Tutto il traffico è isolato all'interno dell'Rete virtuale di Azure usando Rete virtuale endpoint privati e di integrazione. Per indicazioni più complete che includono altri scenari, vedere:

Architettura dello scenario

Il diagramma seguente illustra l'architettura che verrà creata durante questa esercitazione.

Architecture diagram of an n-tier App Service.

  • La rete virtuale contiene due subnet, una è integrata con l'app Web front-end e l'altra ha un endpoint privato per l'app Web back-end. La rete virtuale blocca tutto il traffico di rete in ingresso, ad eccezione dell'app front-end integrata con essa.
  • App Web front-end Integrata nella rete virtuale e accessibile dalla rete Internet pubblica.
  • App Web back-end Accessibile solo tramite l'endpoint privato nella rete virtuale.
  • L'endpoint privato si integra con l'app Web back-end e rende l'app Web accessibile con un indirizzo IP privato.
  • zona DNS privato Consente di risolvere un nome DNS nell'indirizzo IP dell'endpoint privato.

Nota

L'integrazione della rete virtuale e gli endpoint privati sono disponibili fino al livello Basic in servizio app. Il livello Gratuito non supporta queste funzionalità. Con questa architettura:

  • Il traffico pubblico verso l'app back-end è bloccato.
  • Il traffico in uscita da servizio app viene instradato alla rete virtuale e può raggiungere l'app back-end.
  • servizio app è in grado di eseguire la risoluzione DNS all'app back-end.

Questo scenario illustra uno dei possibili scenari a più livelli in servizio app. È possibile usare i concetti trattati in questa esercitazione per creare app più complesse a più livelli.

Contenuto dell'esercitazione:

  • Creare una rete virtuale e subnet per l'integrazione della rete virtuale servizio app.
  • Creare zone DNS private.
  • Creare endpoint privati.
  • Configurare l'integrazione della rete virtuale in servizio app.
  • Disabilitare l'autenticazione di base nel servizio app.
  • Distribuire continuamente in un'app Web back-end bloccata.

Prerequisiti

L'esercitazione usa due app di esempio Node.js ospitate in GitHub. Se non si ha già un account GitHub, creare gratuitamente un account.

Se non si ha una sottoscrizione di Azure, creare un account Azure gratuito prima di iniziare.

Per completare questa esercitazione:

1. Creare due istanze di un'app Web

Sono necessarie due istanze di un'app Web, una per il front-end e una per il back-end. È necessario usare almeno il livello Basic per usare l'integrazione della rete virtuale e gli endpoint privati. L'integrazione della rete virtuale e altre configurazioni verranno configurate in un secondo momento.

  1. Creare un gruppo di risorse per gestire tutte le risorse create in questa esercitazione.

    # Save resource group name and region as variables for convenience
    groupName=myresourcegroup
    region=eastus
    az group create --name $groupName --location $region
    
  2. Creare un piano di servizio app. Sostituire <app-service-plan-name> con un nome univoco. Modificare il --sku parametro se è necessario usare uno SKU diverso. Assicurarsi di non usare il livello gratuito perché tale SKU non supporta le funzionalità di rete necessarie.

    # Save App Service plan name as a variable for convenience
    aspName=<app-service-plan-name>
    az appservice plan create --name $aspName --resource-group $groupName --is-linux --location $region --sku P1V3
    
  3. Creare le app Web. Sostituire <frontend-app-name> e <backend-app-name> con due nomi univoci globali (i caratteri validi sono a-z, 0-9e -). Per questa esercitazione vengono fornite app di esempio Node.js. Se vuoi usare le tue app, modifica il --runtime parametro di conseguenza. Eseguire az webapp list-runtimes per l'elenco dei runtime disponibili.

    az webapp create --name <frontend-app-name> --resource-group $groupName --plan $aspName --runtime "NODE:18-lts"
    az webapp create --name <backend-app-name> --resource-group $groupName --plan $aspName --runtime "NODE:18-lts"
    

2. Creare un'infrastruttura di rete

Verranno create le risorse di rete seguenti:

  • Una rete virtuale.
  • Una subnet per l'integrazione della rete virtuale servizio app.
  • Una subnet per l'endpoint privato.
  • Una zona DNS privata.
  • Endpoint privato.
  1. Crea una rete virtuale. Sostituire <virtual-network-name> con un nome univoco.

    # Save vnet name as variable for convenience
    vnetName=<virtual-network-name>
    az network vnet create --resource-group $groupName --location $region --name $vnetName --address-prefixes 10.0.0.0/16
    
  2. Creare una subnet per l'integrazione della rete virtuale servizio app.

    az network vnet subnet create --resource-group $groupName --vnet-name $vnetName --name vnet-integration-subnet --address-prefixes 10.0.0.0/24 --delegations Microsoft.Web/serverfarms --disable-private-endpoint-network-policies false
    

    Per servizio app, è consigliabile che la subnet di integrazione della rete virtuale abbia almeno un blocco CIDR./26 /24 è più che sufficiente. --delegations Microsoft.Web/serverfarmsspecifica che la subnet è delegata per l'integrazione della rete virtuale servizio app.

  3. Creare un'altra subnet per gli endpoint privati.

    az network vnet subnet create --resource-group $groupName --vnet-name $vnetName --name private-endpoint-subnet --address-prefixes 10.0.1.0/24 --disable-private-endpoint-network-policies true
    

    Per le subnet degli endpoint privati, è necessario disabilitare i criteri di rete degli endpoint privati impostando su --disable-private-endpoint-network-policiestrue.

  4. Creare la zona DNS privata.

    az network private-dns zone create --resource-group $groupName --name privatelink.azurewebsites.net
    

    Per altre informazioni su queste impostazioni, vedere Configurazione DNS dell'endpoint privato di Azure.

    Nota

    Se si crea l'endpoint privato usando il portale, viene creata automaticamente una zona DNS privata e non è necessario crearla separatamente. Per coerenza con questa esercitazione, si crei la zona DNS privata e l'endpoint privato separatamente usando l'interfaccia della riga di comando di Azure.

  5. Collegare la zona DNS privato alla rete virtuale.

    az network private-dns link vnet create --resource-group $groupName --name myDnsLink --zone-name privatelink.azurewebsites.net --virtual-network $vnetName --registration-enabled False
    
  6. Nella subnet dell'endpoint privato della rete virtuale creare un endpoint privato per l'app Web back-end. Sostituire <backend-app-name> con il nome dell'app Web back-end.

    # Get backend web app resource ID
    resourceId=$(az webapp show --resource-group $groupName --name <backend-app-name> --query id --output tsv)
    az network private-endpoint create --resource-group $groupName --name myPrivateEndpoint --location $region --connection-name myConnection --private-connection-resource-id $resourceId --group-id sites --vnet-name $vnetName --subnet private-endpoint-subnet
    
  7. Collegare l'endpoint privato alla zona DNS privata con un gruppo di zone DNS per l'endpoint privato dell'app Web back-end. Questo gruppo di zone DNS consente di aggiornare automaticamente la zona DNS privata quando è presente un aggiornamento all'endpoint privato.

    az network private-endpoint dns-zone-group create --resource-group $groupName --endpoint-name myPrivateEndpoint --name myZoneGroup --private-dns-zone privatelink.azurewebsites.net --zone-name privatelink.azurewebsites.net
    
  8. Quando si crea un endpoint privato per un servizio app, l'accesso pubblico viene disabilitato in modo implicito. Se si tenta di accedere all'app Web back-end usando l'URL predefinito, l'accesso viene negato. Da un browser passare a per confermare <backend-app-name>.azurewebsites.net questo comportamento.

    Screenshot of 403 error when trying to access backend web app directly.

    Per altre informazioni sulle restrizioni di accesso servizio app con endpoint privati, vedere app Azure Restrizioni di accesso al servizio.

3. Configurare l'integrazione della rete virtuale nell'app Web front-end

Abilitare l'integrazione della rete virtuale nell'app. Sostituire <frontend-app-name> con il nome dell'app Web front-end.

az webapp vnet-integration add --resource-group $groupName --name <frontend-app-name> --vnet $vnetName --subnet vnet-integration-subnet

L'integrazione della rete virtuale consente al traffico in uscita di fluire direttamente nella rete virtuale. Per impostazione predefinita, solo il traffico IP locale definito in RFC-1918 viene instradato alla rete virtuale, ovvero ciò che serve per gli endpoint privati. Per indirizzare tutto il traffico alla rete virtuale, vedere Gestire il routing di integrazione della rete virtuale. Il routing di tutto il traffico può essere usato anche se si vuole instradare il traffico Internet attraverso la rete virtuale, ad esempio tramite un nat di Azure Rete virtuale o un Firewall di Azure.

4. Abilitare la distribuzione nell'app Web back-end da Internet

Poiché l'app Web back-end non è accessibile pubblicamente, è necessario consentire allo strumento di distribuzione continua di raggiungere l'app rendendo il sito SCM accessibile pubblicamente. L'app Web principale può continuare a negare tutto il traffico.

  1. Abilitare l'accesso pubblico per l'app Web back-end.

    az webapp update --resource-group $groupName --name <backend-app-name> --set publicNetworkAccess=Enabled
    
  2. Impostare l'azione regola non corrispondente per l'app Web principale per negare tutto il traffico. Questa impostazione nega l'accesso pubblico all'app Web principale anche se l'impostazione generale di accesso alle app è impostata per consentire l'accesso pubblico.

    az resource update --resource-group $groupName --name <backend-app-name> --namespace Microsoft.Web --resource-type sites --set properties.siteConfig.ipSecurityRestrictionsDefaultAction=Deny
    
  3. Impostare l'azione regola non corrispondente per il sito di Gestione controllo servizi per consentire tutto il traffico.Set the unmatched rule action for the SCM site to allow all traffic.

    az resource update --resource-group $groupName --name <backend-app-name> --namespace Microsoft.Web --resource-type sites --set properties.siteConfig.scmIpSecurityRestrictionsDefaultAction=Allow
    

5. Bloccare l'accesso FTP e SCM

Ora che il sito SCM back-end è accessibile pubblicamente, è necessario bloccarlo con una maggiore sicurezza.

  1. Disabilitare l'accesso FTP per le app Web front-end e back-end. Sostituire <frontend-app-name> e <backend-app-name> con i nomi dell'app.

    az resource update --resource-group $groupName --name ftp --namespace Microsoft.Web --resource-type basicPublishingCredentialsPolicies --parent sites/<frontend-app-name> --set properties.allow=false
    az resource update --resource-group $groupName --name ftp --namespace Microsoft.Web --resource-type basicPublishingCredentialsPolicies --parent sites/<backend-app-name> --set properties.allow=false
    
  2. Disabilitare l'accesso di autenticazione di base alle porte WebDeploy e ai siti degli strumenti SCM/avanzati per entrambe le app Web. Sostituire <frontend-app-name> e <backend-app-name> con i nomi dell'app.

    az resource update --resource-group $groupName --name scm --namespace Microsoft.Web --resource-type basicPublishingCredentialsPolicies --parent sites/<frontend-app-name> --set properties.allow=false
    az resource update --resource-group $groupName --name scm --namespace Microsoft.Web --resource-type basicPublishingCredentialsPolicies --parent sites/<backend-app-name> --set properties.allow=false
    

La disabilitazione dell'autenticazione di base in servizio app limita l'accesso agli endpoint FTP e SCM agli utenti supportati da Microsoft Entra ID, che protegge ulteriormente le app. Per altre informazioni sulla disabilitazione dell'autenticazione di base, tra cui come testare e monitorare gli account di accesso, vedere Disabilitazione dell'autenticazione di base in servizio app.

6. Configurare la distribuzione continua con GitHub Actions

  1. Passare all'app di esempio back-end Node.js. Questa app è una semplice app Hello World.

  2. Selezionare il pulsante Fork in alto a destra nella pagina GitHub.

  3. Selezionare Proprietario e lasciare il nome repository predefinito.

  4. Selezionare Crea fork.

  5. Ripetere lo stesso processo per l'app di esempio front-end Node.js. Questa app è un'app Web di base che accede a un URL remoto.

  6. Creare un'entità servizio. Sostituire <subscription-id>, <frontend-app-name>e <backend-app-name> con i valori.

    az ad sp create-for-rbac --name "myApp" --role contributor --scopes /subscriptions/<subscription-id>/resourceGroups/$groupName/providers/Microsoft.Web/sites/<frontend-app-name> /subscriptions/<subscription-id>/resourceGroups/$groupName/providers/Microsoft.Web/sites/<backend-app-name> --sdk-auth
    

    L'output è un oggetto JSON con le credenziali di assegnazione di ruolo che forniscono l'accesso alle app servizio app. Copiare questo oggetto JSON per il passaggio successivo. Include il segreto client, che è visibile solo in questo momento. È sempre consigliabile concedere l'accesso minimo. L'ambito in questo esempio è limitato solo alle app, non all'intero gruppo di risorse.

  7. Per archiviare le credenziali dell'entità servizio come segreti GitHub, passare a uno dei repository di esempio con fork in GitHub e passare a Impostazioni> Sicurezza>segreti e variabili>Azioni.

  8. Selezionare Nuovo segreto del repository e creare un segreto per ognuno dei valori seguenti. I valori sono disponibili nell'output JSON copiato in precedenza.

    Nome valore
    AZURE_APP_ID <application/client-id>
    AZURE_PASSWORD <client-secret>
    AZURE_TENANT_ID <tenant-id>
    AZURE_SUBSCRIPTION_ID <subscription-id>
  9. Ripetere questo processo per l'altro repository di esempio con fork.

  10. Per configurare la distribuzione continua con GitHub Actions, accedere al portale di Azure.

  11. Passare alla pagina Panoramica per l'app Web front-end.

  12. Nel riquadro sinistro selezionare Centro distribuzione. Selezionare quindi Impostazioni.

  13. Nella casella Origine selezionare "GitHub" nelle opzioni CI/CD.

    Screenshot that shows how to choose the deployment source.

  14. Se si esegue la distribuzione da GitHub per la prima volta, selezionare Autorizza e seguire le istruzioni di autorizzazione. Se si vuole eseguire la distribuzione da un repository utente diverso, selezionare Cambia account.

  15. Se si usa l'app di esempio Node.js copiata tramite fork come parte dei prerequisiti, usare le impostazioni seguenti per Organizzazione, Repository e Ramo.

    Impostazione Valore
    Organization <your-GitHub-organization>
    Repository nodejs-frontend
    Filiale main
  16. Seleziona Salva.

  17. Ripetere gli stessi passaggi per l'app Web back-end. Le impostazioni del Centro distribuzione sono indicate nella tabella seguente.

    Impostazione Valore
    Organization <your-GitHub-organization>
    Repository nodejs-backend
    Filiale main

7. Usare un'entità servizio per la distribuzione di GitHub Actions

La configurazione del Centro distribuzione ha creato un file del flusso di lavoro predefinito in ognuno dei repository di esempio, ma usa un profilo di pubblicazione per impostazione predefinita, che usa l'autenticazione di base. Poiché l'autenticazione di base è stata disabilitata, se si seleziona la scheda Log nel Centro distribuzione, si noterà che la distribuzione attivata automaticamente genera un errore. È necessario modificare il file del flusso di lavoro per usare l'entità servizio per l'autenticazione con servizio app. Per i flussi di lavoro di esempio, vedere Aggiungere il file del flusso di lavoro al repository GitHub.

  1. Aprire uno dei repository GitHub con fork e passare alla <repo-name>/.github/workflows/ directory .

  2. Selezionare il file del flusso di lavoro generato automaticamente e quindi selezionare il pulsante "matita" in alto a destra per modificare il file. Sostituire il contenuto con il testo seguente, che presuppone che i segreti gitHub siano stati creati in precedenza per le credenziali. Aggiornare il segnaposto per <web-app-name> nella sezione "env" e quindi eseguire il commit direttamente nel ramo main. Questo commit attiva l'esecuzione di GitHub Action e la distribuzione del codice, questa volta usando l'entità servizio per l'autenticazione.

    name: Build and deploy Node.js app to Azure Web App
    
    on:
      push:
        branches:
          - main
      workflow_dispatch:
    
    env:
      AZURE_WEBAPP_NAME: <web-app-name>   # set this to your application's name
      NODE_VERSION: '18.x'                # set this to the node version to use
      AZURE_WEBAPP_PACKAGE_PATH: '.'      # set this to the path to your web app project, defaults to the repository root
    
    jobs:
      build:
        runs-on: ubuntu-latest
    
        steps:
          - uses: actions/checkout@v2
    
          - name: Set up Node.js version
            uses: actions/setup-node@v1
            with:
              node-version: ${{ env.NODE_VERSION }}
    
          - name: npm install, build
            run: |
              npm install
              npm run build --if-present
    
          - name: Upload artifact for deployment job
            uses: actions/upload-artifact@v2
            with:
              name: node-app
              path: .
    
      deploy:
        runs-on: ubuntu-latest
        needs: build
        environment:
          url: ${{ steps.deploy-to-webapp.outputs.webapp-url }}
    
        steps:
          - name: Download artifact from build job
            uses: actions/download-artifact@v2
            with:
              name: node-app
          - uses: azure/login@v1
            with:
              creds: |
                {
                  "clientId": "${{ secrets.AZURE_APP_ID }}",
                  "clientSecret":  "${{ secrets.AZURE_PASSWORD }}",
                  "subscriptionId": "${{ secrets.AZURE_SUBSCRIPTION_ID }}",
                  "tenantId": "${{ secrets.AZURE_TENANT_ID }}"
                }
    
          - name: 'Deploy to Azure Web App'
            id: deploy-to-webapp
            uses: azure/webapps-deploy@v2
            with:
              app-name: ${{ env.AZURE_WEBAPP_NAME }}
              package: ${{ env.AZURE_WEBAPP_PACKAGE_PATH }}
    
          - name: logout
            run: |
              az logout
    
  3. Ripetere questo processo per il file del flusso di lavoro nell'altro repository GitHub con fork.

I nuovi commit di GitHub attivano un'altra distribuzione per ognuna delle app. Questa volta, la distribuzione dovrebbe avere esito positivo perché il flusso di lavoro usa l'entità servizio per l'autenticazione con i siti SCM delle app.

Per indicazioni dettagliate su come configurare la distribuzione continua con provider come GitHub Actions, vedere Distribuzione continua nel servizio app Azure.

8. Convalidare le connessioni e l'accesso alle app

  1. Passare all'app Web front-end con il relativo URL: https://<frontend-app-name>.azurewebsites.net.

  2. Nella casella di testo immettere l'URL per l'app Web back-end: https://<backend-app-name>.azurewebsites.net. Se si configurano correttamente le connessioni, dovrebbe essere visualizzato il messaggio "Hello from the backend web app!", ovvero l'intero contenuto dell'app Web back-end. Tutto il traffico in uscita dall'app Web front-end viene instradato attraverso la rete virtuale. L'app Web front-end si connette in modo sicuro all'app Web back-end tramite l'endpoint privato. In caso di problemi con le connessioni, l'app Web front-end si arresta in modo anomalo.

  3. Provare a passare direttamente all'app Web back-end con il relativo URL: https://<backend-app-name>.azurewebsites.net. Dovrebbe essere visualizzato il messaggio Web App - Unavailable. Se è possibile raggiungere l'app, assicurarsi di aver configurato l'endpoint privato e che le restrizioni di accesso per l'app siano impostate per negare tutto il traffico per l'app Web principale.

  4. Per verificare ulteriormente che l'app Web front-end raggiunga l'app Web back-end tramite collegamento privato, ssh a una delle istanze del front-end. Per SSH, eseguire il comando seguente, che stabilisce una sessione SSH per il contenitore Web dell'app e apre una shell remota nel browser.

    az webapp ssh --resource-group $groupName --name <frontend-app-name>
    
  5. Quando la shell viene aperta nel browser, eseguire nslookup per verificare che l'app Web back-end venga raggiunta usando l'indirizzo IP privato dell'app Web back-end. È anche possibile eseguire curl per convalidare di nuovo il contenuto del sito. Sostituire <backend-app-name> con il nome dell'app Web back-end.

    nslookup <backend-app-name>.azurewebsites.net
    curl https://<backend-app-name>.azurewebsites.net
    

    Screenshot of SSH session showing how to validate app connections.

    Deve nslookup essere risolto nell'indirizzo IP privato dell'app Web back-end. L'indirizzo IP privato deve essere un indirizzo dalla rete virtuale. Per confermare l'indirizzo IP privato, passare alla pagina Rete per l'app Web back-end.

    Screenshot of App Service Networking page showing the inbound IP of the app.

  6. Ripetere gli stessi nslookup comandi e curl da un altro terminale (uno che non è una sessione SSH nelle istanze del front-end).

    Screenshot of an external terminal doing a nslookup and curl of the back-end web app.

    Restituisce nslookup l'indirizzo IP pubblico per l'app Web back-end. Poiché l'accesso pubblico all'app Web back-end è disabilitato, se si tenta di raggiungere l'indirizzo IP pubblico, viene visualizzato un errore di accesso negato. Questo errore indica che questo sito non è accessibile dalla rete Internet pubblica, ovvero il comportamento previsto. Non nslookup risolve l'indirizzo IP privato perché può essere risolto solo dall'interno della rete virtuale tramite la zona DNS privata. Solo l'app Web front-end si trova all'interno della rete virtuale. Se si tenta di eseguire curl nell'app Web back-end dal terminale esterno, il codice HTML restituito contiene Web App - Unavailable. Questo errore visualizza il codice HTML per la pagina di errore visualizzata in precedenza quando si è tentato di passare all'app Web back-end nel browser.

9. Pulire le risorse

Nei passaggi precedenti sono state create risorse di Azure in un gruppo di risorse. Se si ritiene che queste risorse non saranno necessarie in futuro, eliminare il gruppo di risorse eseguendo questo comando in Cloud Shell.

az group delete --name myresourcegroup

L'esecuzione del comando può richiedere alcuni minuti.

Domande frequenti

Esiste un'alternativa alla distribuzione usando un'entità servizio?

Poiché in questa esercitazione è stata disabilitata l'autenticazione di base, non è possibile eseguire l'autenticazione con il sito SCM back-end con nome utente e password e non è possibile usare un profilo di pubblicazione. Anziché un'entità servizio, è anche possibile usare OpenID Connessione.

Cosa accade quando si configura la distribuzione di GitHub Actions in servizio app?

Azure genera automaticamente un file del flusso di lavoro nel repository. I nuovi commit nel repository e nel ramo selezionati vengono distribuiti in modo continuo nell'app del servizio app. È possibile tenere traccia dei commit e delle distribuzioni nella scheda Log .

Un file del flusso di lavoro predefinito che usa un profilo di pubblicazione per l'autenticazione per servizio app viene aggiunto al repository GitHub. È possibile visualizzare questo file passando alla <repo-name>/.github/workflows/ directory .

È sicuro lasciare accessibile pubblicamente SCM back-end?

Quando si blocca l'accesso FTP e SCM, garantisce che solo le entità supportate da Microsoft Entra possano accedere all'endpoint SCM anche se è accessibile pubblicamente. Questa impostazione dovrebbe rassicurare l'utente che l'app Web back-end è ancora sicura.

È possibile eseguire la distribuzione senza aprire il sito SCM back-end?

Se si è preoccupati di abilitare l'accesso pubblico al sito SCM o di essere limitati dai criteri, prendere in considerazione altre opzioni di distribuzione servizio app come l'esecuzione da un pacchetto ZIP.

Come è possibile distribuire questa architettura con ARM/Bicep?

Le risorse create in questa esercitazione possono essere distribuite usando un modello ARM/Bicep. Il modello Bicep app connessa a un'app Web back-end consente di creare una soluzione di app a più livelli sicura.

Per informazioni su come distribuire modelli ARM/Bicep, vedere Come distribuire le risorse con Bicep e l'interfaccia della riga di comando di Azure.

Passaggi successivi