Tutorial: Creación de una aplicación segura de n niveles en Azure App Service

Muchas aplicaciones tienen más de un único componente. Por ejemplo, puede tener un front-end que sea accesible públicamente y se conecte a una API de back-end o aplicación web que, a su vez, se conecta a una base de datos, una cuenta de almacenamiento, un almacén de claves, otra máquina virtual o una combinación de estos recursos. Esta arquitectura constituye una aplicación de n niveles. Es importante que las aplicaciones como esta estén diseñadas para proteger los recursos de back-end en la mayor medida posible.

En este tutorial, aprenderá a implementar una aplicación segura de n niveles, con una aplicación web de front-end que se conecta a otra aplicación web aislada de la red. Todo el tráfico está aislado dentro de la red virtual mediante la integración de red virtual y los puntos de conexión privados. Para obtener instrucciones más completas que incluyan otros escenarios, consulte:

Arquitectura del escenario

En el diagrama siguiente, se muestra la arquitectura que va a crear durante este tutorial.

Architecture diagram of an n-tier App Service.

  • Red virtual Contiene dos subredes, una se integra con la aplicación web de front-end y la otra tiene un punto de conexión privado para la aplicación web de back-end. La red virtual bloquea todo el tráfico de red entrante, excepto el de la aplicación de front-end que está integrada con ella.
  • Aplicación web de front-end Integrada en la red virtual y accesible desde la red pública de Internet.
  • Aplicación web de back-end Solo se puede acceder a ella mediante el punto de conexión privado de la red virtual.
  • Punto de conexión privado Se integra con la aplicación web de back-end y hace que la aplicación web sea accesible con una dirección IP privada.
  • Zona DNS privada Permite resolver un nombre DNS en la dirección IP del punto de conexión privado.

Nota:

La integración de red virtual y los puntos de conexión privados están disponibles hasta el nivel Básico de App Service. El nivel Gratis no admite estas características. Con esta arquitectura:

  • El tráfico público a la aplicación de back-end está bloqueado.
  • El tráfico saliente de App Service se enruta a la red virtual y puede llegar a la aplicación de back-end.
  • App Service puede realizar la resolución DNS para la aplicación de back-end.

En este escenario, se muestra uno de los posibles escenarios de n niveles en App Service. Puede usar los conceptos descritos en este tutorial para crear aplicaciones de n niveles más complejas.

Temas que se abordarán:

  • Crear una red virtual y subredes para la integración de red virtual de App Service.
  • Crear zonas DNS privadas.
  • Crear puntos de conexión privados.
  • Configurar la integración de red virtual en App Service.
  • Deshabilitar la autenticación básica en App Service.
  • Implementar de forma continua en una aplicación web de back-end bloqueada.

Requisitos previos

En el tutorial, se usan dos aplicaciones de ejemplo de Node.js hospedadas en GitHub. Si aún no tiene una cuenta de GitHub, cree una de manera gratuita.

Si no tiene una suscripción a Azure, cree una cuenta gratuita de Azure antes de empezar.

Para completar este tutorial:

1. Creación de dos instancias de una aplicación web

Necesita dos instancias de una aplicación web, una para el front-end y otra para el back-end. Debe usar al menos el nivel Básico para poder usar la integración de red virtual y los puntos de conexión privados. Configurará la integración de red virtual y otras configuraciones más adelante.

  1. Cree un grupo de recursos para administrar todos los recursos que va a crear en este tutorial.

    # Save resource group name and region as variables for convenience
    groupName=myresourcegroup
    region=eastus
    az group create --name $groupName --location $region
    
  2. Creación de un plan de App Service. Reemplace <app-service-plan-name> por un nombre único. Modifique el parámetro --sku si necesita usar otra SKU. Asegúrese de que no usa el nivel gratis, ya que esa SKU no admite las características de redes necesarias.

    # 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. Cree las aplicaciones web. Reemplace <frontend-app-name> y <backend-app-name> por dos nombres globalmente únicos (los caracteres válidos son a-z, 0-9 y -). En este tutorial, se le proporcionan aplicaciones de ejemplo de Node.js. Si quiere usar sus propias aplicaciones, cambie el parámetro --runtime en consecuencia. Ejecute az webapp list-runtimes para ver la lista de entornos de ejecución disponibles.

    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. Creación de la infraestructura de red

Creará los siguientes recursos de red:

  • Una red virtual.
  • Una subred para la integración de red virtual de App Service.
  • Una subred para el punto de conexión privado.
  • Una zona DNS privada.
  • Un punto de conexión privado.
  1. Cree una red virtual. Reemplace <virtual-network-name> por un nombre único.

    # 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. Cree una subred para la integración de red virtual de App Service.

    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
    

    En App Service, se recomienda que la subred de la integración de red virtual tenga un bloque CIDR /26 como mínimo. /24 es más que suficiente. --delegations Microsoft.Web/serverfarms especifica que la subred se delega para la integración de red virtual de App Service.

  3. Cree otra subred para los puntos de conexión privados.

    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
    

    En las subredes de los puntos de conexión privados, debe deshabilitar las directivas de red del punto de conexión privado; para ello, establezca --disable-private-endpoint-network-policies en true.

  4. Cree la zona DNS privada.

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

    Para obtener más información sobre esta configuración, consulte Configuración de DNS para puntos de conexión privados de Azure.

    Nota:

    Si crea el punto de conexión privado mediante el portal, se crea automáticamente una zona DNS privada y no es necesario crearla por separado. Para mantener la coherencia en este tutorial, creará la zona DNS privada y el punto de conexión privado por separado mediante la CLI de Azure.

  5. Vincule la zona DNS privada a la red virtual.

    az network private-dns link vnet create --resource-group $groupName --name myDnsLink --zone-name privatelink.azurewebsites.net --virtual-network $vnetName --registration-enabled False
    
  6. En la subred del punto de conexión privado de la red virtual, cree un punto de conexión privado para la aplicación web de back-end. Reemplace <backend-app-name> por el nombre de la aplicación web de 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. Vincule el punto de conexión privado a la zona DNS privada con un grupo de zonas DNS para el punto de conexión privado de la aplicación web de back-end. Este grupo de zonas DNS le ayuda a actualizar automáticamente la zona DNS privada cuando haya una actualización del punto de conexión privado.

    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. Al crear un punto de conexión privado para una instancia de App Service, el acceso público se deshabilita implícitamente. Si intenta acceder a la aplicación web de back-end mediante su dirección URL predeterminada, se deniega el acceso. En un explorador, vaya a <backend-app-name>.azurewebsites.net para confirmar este comportamiento.

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

    Para obtener más información sobre las restricciones de acceso de App Service con puntos de conexión privados, consulte Restricciones de acceso de Azure App Service.

3. Configuración de la integración de red virtual en la aplicación web de front-end

Habilite la integración de red virtual en la aplicación. Reemplace <frontend-app-name> por el nombre de la aplicación web de front-end.

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

La integración de red virtual permite que el tráfico saliente fluya directamente a la red virtual. De manera predeterminada, solo el tráfico IP local definido en RFC-1918 se enruta a la red virtual, que es lo que necesita para los puntos de conexión privados. Para enrutar todo el tráfico a la red virtual, vea Administración del enrutamiento de la integración de red virtual. También se puede usar el enrutamiento de todo el tráfico si se quiere enrutar el tráfico de Internet a través de la red virtual, por ejemplo, a través de Azure Virtual Network NAT o Azure Firewall.

4. Habilitación de la implementación en la aplicación web de back-end desde Internet

Puesto que la aplicación web de back-end no es accesible públicamente, debe permitir que la herramienta de implementación continua acceda a la aplicación haciendo que el sitio del SCM sea accesible públicamente. La propia aplicación web principal puede seguir denegando todo el tráfico.

  1. Habilite el acceso público para la aplicación web de back-end.

    az webapp update --resource-group $groupName --name <backend-app-name> --set publicNetworkAccess=Enabled
    
  2. Establezca la acción de la regla de no coincidencia para que la aplicación web principal deniegue todo el tráfico. Esta configuración deniega el acceso público a la aplicación web principal aunque la configuración de acceso a la aplicación general esté establecida para permitir el acceso público.

    az resource update --resource-group $groupName --name <backend-app-name> --namespace Microsoft.Web --resource-type sites --set properties.siteConfig.ipSecurityRestrictionsDefaultAction=Deny
    
  3. Establezca la acción de la regla de no coincidencia para que el sitio del SCM permita todo el tráfico.

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

5. Bloqueo del acceso FTP y SCM

Ahora que el sitio del SCM de back-end es accesible públicamente, debe bloquearlo con una mejor seguridad.

  1. Deshabilite el acceso FTP para las aplicaciones web de front-end y de back-end. Reemplace <frontend-app-name> y <backend-app-name> por los nombres de la aplicación.

    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. Deshabilite el acceso de autenticación básica a los puertos de WebDeploy y los sitios de herramientas avanzadas y SCM para ambas aplicaciones web. Reemplace <frontend-app-name> y <backend-app-name> por los nombres de la aplicación.

    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
    

Deshabilitar la autenticación básica en App Service limita el acceso de los usuarios respaldados por Azure Microsoft Entra ID a los puntos de conexión FTP y SCM, lo que protege aún más las aplicaciones. Para más información sobre cómo deshabilitar la autenticación básica, incluido cómo probar y supervisar los inicios de sesión, consulte Deshabilitación de la autenticación básica en App Service.

6. Configuración de la implementación continua mediante Acciones de GitHub

  1. Vaya a la aplicación de ejemplo de back-end de Node.js. Esta aplicación es una aplicación Hola mundo sencilla.

  2. Seleccione el botón Fork (Bifurcación) en la esquina superior derecha de la página de GitHub.

  3. Seleccione el valor del campo Owner y deje el nombre del repositorio predeterminado.

  4. Seleccione Create fork.

  5. Repita el mismo proceso para la aplicación de ejemplo de front-end de Node.js. Esta aplicación es una aplicación web básica que accede a una dirección URL remota.

  6. Cree una entidad de servicio. Reemplace <subscription-id>, <frontend-app-name> y <backend-app-name> por sus valores.

    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
    

    La salida es un objeto JSON con las credenciales de asignación de roles que proporcionan acceso a las aplicaciones de App Service. Copie este objeto JSON en el siguiente paso. Esto incluye el secreto de cliente, que solo es visible en este momento. Siempre es recomendable conceder acceso mínimo. El ámbito de este ejemplo se limita a solo las aplicaciones, no al grupo de recursos entero.

  7. Para almacenar las credenciales de la entidad de servicio como secretos de GitHub, vaya a uno de los repositorios de ejemplo bifurcados en GitHub y vaya a Settings>Security>Secrets and variables>Actions.

  8. Seleccione Nuevo secreto del repositorio y cree un secreto para cada uno de los valores siguientes. Los valores se pueden encontrar en la salida JSON que copió anteriormente.

    Nombre Valor
    AZURE_APP_ID <application/client-id>
    AZURE_PASSWORD <client-secret>
    AZURE_TENANT_ID <tenant-id>
    AZURE_SUBSCRIPTION_ID <subscription-id>
  9. Repita este proceso para el otro repositorio de ejemplo bifurcado.

  10. Para configurar la implementación continua con Acciones de GitHub, inicie sesión en Azure Portal.

  11. Vaya a la página Información general de la aplicación web de front-end.

  12. En el panel izquierdo, seleccione Centro de implementación. Luego, seleccione Configuración.

  13. En el cuadro Origen, seleccione "GitHub" en las opciones de CI/CD.

    Screenshot that shows how to choose the deployment source.

  14. Si va a realizar la implementación desde GitHub por primera vez, seleccione Autorizar y siga las indicaciones de autorización. Si quiere realizar la implementación desde un repositorio de usuario diferente, seleccione Cambiar cuenta.

  15. Si usa la aplicación de ejemplo de Node.js bifurcada como parte de los requisitos previos, use la siguiente configuración para Organización, Repositorio y Rama.

    Configuración Valor
    Organización <your-GitHub-organization>
    Repositorio nodejs-frontend
    Rama main (principal)
  16. Seleccione Guardar.

  17. Repita los mismos pasos para la aplicación web de back-end. Las opciones de configuración del Centro de implementación se indican en la tabla siguiente.

    Configuración Valor
    Organización <your-GitHub-organization>
    Repositorio nodejs-backend
    Rama main (principal)

7. Uso de una entidad de servicio para la implementación de Acciones de GitHub

La configuración del Centro de implementación ha creado un archivo de flujo de trabajo predeterminado en cada uno de los repositorios de ejemplo, pero usa de manera predeterminada un perfil de publicación que usa la autenticación básica. Puesto que ha deshabilitado la autenticación básica, si comprueba la pestaña Registros en el Centro de implementación, verá que la implementación desencadenada automáticamente produce un error. Debe modificar el archivo de flujo de trabajo para usar la entidad de servicio para autenticarse con App Service. Para ver flujos de trabajo de ejemplo, consulte Adición del archivo de flujo de trabajo al repositoriode GitHub.

  1. Abra uno de los repositorios de GitHub bifurcados y vaya al directorio <repo-name>/.github/workflows/.

  2. Seleccione el archivo de flujo de trabajo generado automáticamente y, a continuación, seleccione el botón de "lápiz" en la parte superior derecha para editar el archivo. Reemplace el contenido por el texto siguiente, que supone que creó los secretos de GitHub anteriormente para la credencial. Actualice el marcador de posición <web-app-name> en la sección "env" y, luego, confirme directamente en la rama principal. Esta confirmación hace que la acción de GitHub se ejecute de nuevo e implemente el código, esta vez mediante la entidad de servicio para autenticarse.

    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. Repita este proceso para el archivo de flujo de trabajo del otro repositorio de GitHub bifurcado.

Las nuevas confirmaciones de GitHub desencadenan otra implementación para cada una de las aplicaciones. Esta vez, la implementación debe realizarse correctamente, ya que el flujo de trabajo usa la entidad de servicio para autenticarse con los sitios del SCM de las aplicaciones.

Para una guía detallada sobre cómo configurar la implementación continua con proveedores como Acciones de GitHub, consulte Implementación continua en Azure App Service.

8. Validación de las conexiones y el acceso a las aplicaciones

  1. Vaya a la aplicación web de front-end con su dirección URL: https://<frontend-app-name>.azurewebsites.net.

  2. En el cuadro de texto, escriba la dirección URL de la aplicación web de back-end: https://<backend-app-name>.azurewebsites.net. Si ha configurado correctamente las conexiones, debe obtener el mensaje "Hello from the backend web app!", que es todo el contenido de la aplicación web de back-end. Todo el tráfico saliente de la aplicación web de front-end se enruta mediante la red virtual. La aplicación web de front-end se conecta de forma segura a la aplicación web de back-end mediante el punto de conexión privado. Si hay algún problema con las conexiones, la aplicación web de front-end se bloquea.

  3. Intente ir directamente a la aplicación web de back-end con su dirección URL: https://<backend-app-name>.azurewebsites.net. Verá el mensaje Web App - Unavailable. Si puede acceder a la aplicación, asegúrese de haber configurado el punto de conexión privado y de que las restricciones de acceso de la aplicación estén establecidas para denegar todo el tráfico de la aplicación web principal.

  4. Para validar aún más que la aplicación web de front-end accede a la aplicación web de back-end mediante un vínculo privado, conéctese mediante SSH a una de las instancias de front-end. Para conectarse mediante SSH, ejecute el siguiente comando, que establece una sesión SSH en el contenedor web de la aplicación y abre un shell remoto en el explorador.

    az webapp ssh --resource-group $groupName --name <frontend-app-name>
    
  5. Cuando se abra el shell en el explorador, ejecute nslookup para confirmar que se está accediendo a la aplicación web de back-end mediante la dirección IP privada de la aplicación web de back-end. También puede ejecutar curl para volver a validar el contenido del sitio. Reemplace <backend-app-name> por el nombre de la aplicación web de 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.

    El resultado de nslookup debe resolverse en la dirección IP privada de la aplicación web de back-end. La dirección IP privada debe ser una dirección de la red virtual. Para confirmar la dirección IP privada, vaya a la página Redes de la aplicación web de back-end.

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

  6. Repita los mismos comandos nslookup y curl desde otro terminal (uno que no sea una sesión SSH en las instancias de front-end).

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

    nslookup devuelve la dirección IP pública de la aplicación web de back-end. Dado que el acceso público a la aplicación web de back-end está deshabilitado, si intenta acceder a la dirección IP pública, obtendrá un error de acceso denegado. Este error significa que este sitio no es accesible desde la red pública de Internet, que es el comportamiento previsto. El resultado de nslookup no se resuelve en la dirección IP privada porque solo se puede resolver desde dentro de la red virtual mediante la zona DNS privada. Solo la aplicación web de front-end está dentro de la red virtual. Si intenta ejecutar curl en la aplicación web de back-end desde el terminal externo, el código HTML que se devuelve contiene Web App - Unavailable. Este error muestra el código HTML de la página de error que vio anteriormente al intentar ir a la aplicación web de back-end en el explorador.

9. Limpieza de recursos

En los pasos anteriores, creó recursos de Azure en un grupo de recursos. Si prevé que no necesitará estos recursos en el futuro, elimine el grupo de recursos ejecutando el siguiente comando en Cloud Shell.

az group delete --name myresourcegroup

Este comando puede tardar varios minutos en ejecutarse.

Preguntas más frecuentes

¿Hay alguna alternativa a la implementación mediante una entidad de servicio?

Puesto que en este tutorial ha deshabilitado la autenticación básica, no se puede autenticar con el sitio del SCM de back-end con un nombre de usuario y una contraseña, y tampoco puede con un perfil de publicación. En lugar de una entidad de servicio, también puede usar OpenID Connect.

¿Qué ocurre cuando configuro la implementación de Acciones de GitHub en App Service?

Azure genera automáticamente un archivo de flujo de trabajo en el repositorio. Las nuevas confirmaciones del repositorio y la rama seleccionados ahora se implementan continuamente en su aplicación de App Service. Puede hacer el seguimiento de las confirmaciones y las implementaciones en la pestaña Registros.

Se agrega a su repositorio de GitHub un archivo de flujo de trabajo predeterminado que utiliza un perfil de publicación para autenticarse en App Service. Para ver este archivo, vaya al directorio <repo-name>/.github/workflows/.

¿Es seguro dejar el SCM de back-end accesible públicamente?

Al bloquear el acceso a FTP y SCM, se garantiza que las entidades de seguridad que tengan el respaldo de Microsoft Entra sean las únicas que tengan acceso al punto de conexión del SCM aunque sea accesible públicamente. Esta configuración debe garantizar que la aplicación web de back-end siga siendo segura.

¿Hay alguna manera de implementar sin abrir el sitio del SCM de back-end?

Si le preocupa habilitar el acceso público al sitio del SCM o está restringido por una directiva, considere otras opciones de implementación de App Service, como ejecutar desde un paquete ZIP.

¿Cómo puedo implementar esta arquitectura con ARM o Bicep?

Los recursos creados en este tutorial se pueden implementar mediante una plantilla de ARM o Bicep. La plantilla de Bicep Aplicación conectada a una aplicación web de back-end le permite crear una solución de aplicación segura de n niveles.

Para aprender a implementar plantillas de ARM o Bicep, consulte Implementación de recursos con Bicep y la CLI de Azure.

Pasos siguientes