Azure App Service 환경을 사용하는 엔터프라이즈 배포

Azure Active Directory
Application Gateway
App Service
방화벽
Virtual Network

이 참조 아키텍처는 ASE(App Service Environment)를 사용하는 일반적인 엔터프라이즈 워크로드와 이 워크로드의 보안을 강화하는 모범 사례를 보여 줍니다.

GitHub 로고 이 아키텍처에 대한 참조 구현은 GitHub에서 사용할 수 있습니다.

아키텍처

표준 App Service Environment 배포를 위한 아키텍처를 보여 주는 다이어그램

이 아키텍처의 Visio 파일을 다운로드합니다.

워크플로

이 아키텍처의 주요 구성 요소는 App Service 환경입니다. ASE는 공용 IP 주소를 사용하여 외부 ASE로, 또는 ILB(내부 Load Balancer)에 속하는 내부 IP 주소를 사용하여 외부 ASE로 배포할 수 있습니다. 이 참조 아키텍처는 ILB ASE라고도 하는 내부 ASE에 엔터프라이즈 웹 애플리케이션을 배포합니다. 시나리오에서 다음 사항을 요구하는 경우 ILB ASE를 사용합니다.

  • 사이트 간 또는 ExpressRoute를 통해 액세스하는 클라우드에서 인트라넷 애플리케이션을 안전하게 호스팅
  • WAF 디바이스를 사용하여 앱 보호
  • 공용 DNS 서버에 나열되지 않은 클라우드에 앱 호스트
  • 프런트 엔드 앱이 안전하게 통합될 수 있는 인터넷 격리 백 엔드 앱 만들기

ASE는 항상 엔터프라이즈 가상 네트워크 내의 자체 서브넷에 배포하여 들어오고 나가는 트래픽을 엄격하게 제어할 수 있게 해야 합니다. 이 서브넷 내에서 App Service 애플리케이션은 앱을 실행하는 데 필요한 물리적 리소스 컬렉션인 하나 이상의 App Service 요금제에 배포됩니다. 복잡성 및 리소스 요구 사항에 따라 여러 앱 간에 App Service 요금제를 공유할 수 있습니다. 이 참조 구현은 프라이빗 웹 API 및 함수와 상호 작용하는 Voting App이라는 웹앱을 배포합니다. 또한 다중 앱 배포를 보여주는 Test App이라는 더미 웹앱을 배포합니다. 각 App Service 앱은 자체 App Service 요금제에 호스트되므로 필요한 경우 개별적으로 스케일링할 수 있습니다. 스토리지 및 컴퓨팅처럼 이러한 호스트된 앱에 필요한 모든 리소스와 크기 조정 요구 사항은 App Service Environment 인프라에서 완전히 관리됩니다.

이 구현의 간단한 투표 앱을 사용하면 사용자가 기존 항목을 보거나 새 항목을 만들 수 있을 뿐만 아니라 기존 항목에 투표할 수 있습니다. 웹 API는 항목 및 투표를 만들고 검색하는 데 사용됩니다. 데이터 자체는 SQL Server 데이터베이스에 저장됩니다. 비동기 데이터 업데이트를 보여주기 위해 웹앱은 Service Bus 인스턴스에서 새로 추가된 투표를 큐에 추가합니다. 이 함수는 큐에 추가된 투표를 선택하고 SQL 데이터베이스를 업데이트합니다. Azure Cosmos DB는 웹앱이 브라우저에 표시하기 위해 검색하는 모의 광고 저장에 사용됩니다. 애플리케이션은 캐시 관리에 Azure Cache for Redis를 사용합니다. 프리미엄 계층 Azure Cache for Redis가 사용되므로, 자체 서브넷에서 ASE와 동일한 가상 네트워크 구성을 사용할 수 있습니다. 이렇게 하면 캐시의 보안과 격리가 향상됩니다.

웹앱은 App Gateway를 통해 인터넷에 액세스할 수 있는 유일한 구성 요소입니다. API 및 함수는 인터넷 클라이언트에서 액세스할 수 없습니다. 인바운드 트래픽은 App Gateway에 구성된 Web Application Firewall로 보호됩니다.

구성 요소

다음 서비스는 이 아키텍처에서 ASE를 잠그는 데 핵심적인 요소입니다.

Azure VNet(Virtual Network)은 기업 소유의 프라이빗 Azure 클라우드 네트워크이며 네트워크 기반 보안 및 격리를 제공합니다. ASE는 기업 소유 VNet의 서브넷에 배포되는 App Service입니다. 이를 통해 기업은 네트워크 보안 그룹서비스 엔드포인트를 사용하여 네트워크 공간과 네트워크 공간이 액세스하는 리소스를 엄격하게 제어 할 수 있습니다.

Application Gateway는 TLS/SSL 오프로드 및 WAF(웹 애플리케이션 방화벽) 보호를 사용하는 애플리케이션 수준 웹 트래픽 부하 분산 장치입니다. Application Gateway는 공용 IP 주소에서 수신 대기하고 트래픽을 ILB ASE의 애플리케이션 엔드포인트로 라우팅합니다. 이는 애플리케이션 수준 라우팅이므로, 동일한 ILB ASE 내부의 여러 앱으로 트래픽을 라우팅할 수 있습니다. App Gateway가 여러 사이트를 지원하는 방법을 알아보려면 Application Gateway 다중 사이트 호스팅을 참조하세요.

Azure Firewall은 웹 애플리케이션의 아웃바운드 트래픽을 제한하는 데 사용됩니다. 서비스 엔드포인트 채널 및 ASE에 필요한 라우팅 테이블을 통과하지 않는 발신 트래픽은 방화벽 서브넷에 전달됩니다. 추적이 가능하도록 방화벽 서브넷에 서비스 엔드포인트를 구성하는 것이 좋지만, 구성이 불가능할 수도 있습니다. 예를 들어 ASE 인프라에 필요한 일부 서비스 엔드포인트는 ASE 서브넷에 있어야 합니다. 간단한 설명을 위해 이 아키텍처는 ASE 서브넷에서 모든 서비스 엔드포인트를 구성합니다.

Azure Active Directory 또는 Azure AD Azure 리소스 및 서비스에 대한 액세스 권한 및 권한 관리를 제공합니다. 관리 ID는 Azure AD에서 자동으로 관리되는 ID를 서비스 및 앱에 할당합니다. 이러한 ID는 AD 인증을 지원하는 서비스에 인증하는 데 사용할 수 있습니다. 이렇게 하면 이러한 앱에 대한 자격 증명을 명시적으로 구성할 필요가 없습니다. 이 아키텍처는 웹앱에 관리 ID를 할당합니다.

Key Vault는 앱에 필요한 비밀과 자격 증명을 저장합니다. 애플리케이션에 직접 비밀을 저장하지 말고 이 옵션을 사용하세요.

Azure Pipelines는 이 아키텍처에서 연속 통합 및 지속적인 배포 기능을 제공합니다. ASE는 가상 네트워크 내부에 있으므로, App Service 요금제에 앱을 배포하기 위해 가상 머신이 VNet 내에서 점프 상자로 사용됩니다. 파이프라인은 VNet 외부에서 앱을 빌드합니다. 향상된 보안 및 원활한 RDP/SSH 연결을 위해 최근에 릴리스된 Azure Bastion을 점프 상자로 사용하는 것이 좋습니다.

다중 사이트 파일 서버 확장 구성에서 Tiger Bridge의 참조 아키텍처를 보여 주는 다중 사이트 하이브리드

다중 사이트 배포를 보여 주는 다이어그램

이 다이어그램의 Visio 파일을 다운로드합니다 .

내부 ASE는 HTTP 엔드포인트를 사용하여 여러 웹앱 및 API를 호스트할 수 있습니다. ILB IP는 Virtual Network 내에서만 액세스할 수 있으므로 이러한 애플리케이션은 공용 인터넷에서 잠깁니다. Application Gateway 이러한 애플리케이션을 인터넷에 선택적으로 노출하는 데 사용됩니다. ASE는 기본 URL을 각 App Service 애플리케이션에 <default-appName>.<ASE-domain>.appserviceenvironment.net으로 할당합니다. ASE 도메인 이름을 ASE ILB IP 주소에 매핑하는 프라이빗 DNS 영역이 만들어집니다. 그러면 사용자 지정 DNS를 사용하여 VNet 내의 앱에 액세스할 수 없습니다.

App Gateway는 수신기가 HTTPS 포트에서 게이트웨이의 IP 주소에 대한 요청을 수신 대기하도록 구성됩니다. 간단한 설명을 위해 이 구현에서는 공용 DNS 이름 등록을 사용하지 않으며, 임의로 선택된 URL이 App Gateway의 IP를 가리키도록 컴퓨터의 localhost 파일을 수정해야 합니다. 간단한 설명을 위해 수신기는 자체 서명된 인증서를 사용하여 이러한 요청을 처리합니다. App Gateway에는 각 App Service 애플리케이션의 기본 URL에 대한 백 엔드 풀이 있습니다. 회람 규칙은 수신기를 백 엔드 풀에 연결하도록 구성됩니다. 게이트웨이와 ASE 간의 연결을 암호화할지 여부를 결정하는 HTTP 설정이 만들어집니다. 이러한 설정은 백 엔드 풀에서 선택한 호스트 이름으로 들어오는 HTTP 호스트 헤더를 재정의하는 데에도 사용됩니다. 이 구현에서는 게이트웨이에서 신뢰하는 기본 ASE 앱 URL에 대해 만들어진 기본 인증서를 사용합니다. 요청은 해당 앱의 기본 URL로 리디렉션됩니다. VNet에 연결된 프라이빗 DNS는 이 요청을 ILB IP에 전달합니다. 그러면 ASE는 이 요청을 요청된 App Service에 전달합니다. ASE 앱 내의 모든 HTTP 통신은 프라이빗 DNS를 통과합니다. 각 ASE 앱에 대한 App Gateway에서 수신기, 백 엔드 풀, 회람 규칙 및 HTTP 설정을 구성해야 합니다.

이러한 구성이 다중 사이트를 허용하도록 만드는 방법을 알아보려면 appgw.jsondns.json을 살펴보세요. testapp이라는 웹앱은 이 구성을 보여주기 위해 만든 빈 앱입니다. 이러한 JSON 파일은 배포 스크립트 deploy_std.sh에서 액세스합니다. 또한 고가용성 다중 사이트 ASE 배포에 사용되는 deploy_ha.sh에서도 이 파일에 액세스합니다.

시나리오 정보

Azure App Service는 웹앱, API 앱, 함수, 모바일 앱 등의 다양한 앱을 Azure에 호스트하는 데 사용되는 PaaS 서비스입니다. App Service Environment 또는 ASE를 통해 기업은 자체 Azure Virtual Network 서브넷에 App Service 앱을 배포하여 클라우드 워크로드에 대해 격리되고 확장성이 뛰어나며 전용 환경을 제공할 수 있습니다.

고려 사항

이러한 고려 사항은 워크로드의 품질을 향상시키는 데 사용할 수 있는 일단의 지침 원칙인 Azure Well-Architected Framework의 핵심 요소를 구현합니다. 자세한 내용은 Microsoft Azure Well-Architected Framework를 참조하세요.

보안

보안은 고의적인 공격 및 중요한 데이터 및 시스템의 남용에 대한 보증을 제공합니다. 자세한 내용은 보안 핵심 요소 개요를 참조하세요.

App Service 환경

내부 ASE는 공용 인터넷에서 숨겨진 엔터프라이즈 가상 네트워크에 배포됩니다. 따라서 기업은 네트워크 수준에서 웹 API 및 함수와 같은 백 엔드 서비스를 잠글 수 있습니다. HTTP 엔드포인트가 있는 모든 ASE 앱은 가상 네트워크 내에서 ILB를 통해 액세스할 수 있습니다. App Gateway는 ILB를 통해 웹앱에 요청을 전달하도록 구성됩니다. 웹앱 자체는 ILB를 통해 API에 액세스합니다. 중요한 백 엔드 구성 요소, 즉 API 및 함수는 공용 인터넷에서 효과적으로 액세스할 수 없습니다.

ASE에서 할당한 기본 도메인 이름에 대한 App Service마다 기본 인증서가 만들어집니다. 이 인증서는 게이트웨이와 앱 간의 트래픽 보안을 강화할 수 있으며, 특정 시나리오에서 필요할 수 있습니다. 이러한 인증서는 클라이언트 브라우저에서 볼 수 없으며, App Gateway에서 구성된 인증서에만 응답할 수 있습니다.

응용 프로그램 게이트웨이

참조 구현은 appgw.json에서 프로그래밍 방식으로 App Gateway를 구성합니다. deploy_std.sh 파일은 게이트웨이를 배포할 때 다음 구성을 사용합니다.

az deployment group create --resource-group $RGNAME --template-file templates/appgw.json --parameters vnetName=$VNET_NAME appgwSubnetAddressPrefix=$APPGW_PREFIX appgwApplications=@appgwApps.parameters.json
APPGW_PUBLIC_IP=$(az deployment group show -g $RGNAME -n appgw --query properties.outputs.appGwPublicIpAddress.value -o tsv)
암호화

Application Gateway를 사용한 TLS 종료 및 엔드투엔드 TLS 개요에 설명된 대로 App Gateway는 TLS(전송 계층 보안)/SSL(Secure Sockets Layer)을 사용하여 웹 브라우저의 모든 트래픽을 암호화하고 보호할 수 있습니다. 암호화는 다음과 같은 방식으로 구성할 수 있습니다.

  1. 게이트웨이에서 암호화 종료. 이 경우 백 엔드 풀은 HTTP용으로 구성됩니다. 게이트웨이에서 암호화가 중지되고, 게이트웨이와 앱 서비스 간의 트래픽이 암호화되지 않습니다. 암호화는 CPU를 많이 사용하므로, 백 엔드에서 암호화하지 않으면 트래픽 성능이 향상되고 인증서 관리가 더 간단해집니다. 이렇게 하면 네트워크 구성을 통해 백 엔드가 보호되므로 적절한 수준의 보안이 제공됩니다.

  2. 엔드투엔드 암호화. 특정 보안 또는 규정 준수 요구 사항이 있는 일부 시나리오에서는 게이트웨이와 앱 간에 트래픽을 암호화해야 합니다. 이러한 암호화는 HTTPS 연결을 사용하고 백 엔드 풀에서 인증서를 구성하여 수행됩니다.

이 참조 구현은 자체 서명된 인증서를 App Gateway에 사용합니다. 프로덕션 코드의 경우 인증 기관에서 발급한 인증서를 사용해야 합니다. 지원되는 인증서 유형 목록은 TLS 종료에 대해 지원되는 인증서를 참조하세요. 게이트웨이 종료 암호화를 만드는 방법을 알아보려면 Azure Portal을 사용하여 TLS 종료로 애플리케이션 게이트웨이 구성을 읽어보세요. appgw.json의 다음 코드 줄은 이를 프로그래밍 방식으로 구성합니다.

          {
            "name": "httpListeners",
            "count": "[length(parameters('appgwApplications'))]",
            "input": {
              "name": "[concat(variables('appgwListenerName'), parameters('appgwApplications')[copyIndex('httpListeners')].name)]",
              "properties": {
                "frontendIPConfiguration": {
                  "id": "[concat(variables('appgwId'), '/frontendIPConfigurations/', variables('appgwFrontendName'))]"
                },
                "frontendPort": {
                  "id": "[concat(variables('appgwId'), '/frontendPorts/port_443')]"
                },
                "protocol": "Https",
                "sslCertificate": {
                  "id": "[concat(variables('appgwId'), '/sslCertificates/', variables('appgwSslCertificateName'), parameters('appgwApplications')[copyIndex('httpListeners')].name)]"
                },
                "hostName": "[parameters('appgwApplications')[copyIndex('httpListeners')].hostName]",
                "requireServerNameIndication": true
              }
            }
          },

ASE의 웹앱과 게이트웨이 사이의 트래픽에는 기본 SSL 인증서가 사용됩니다. 이 구현의 백 엔드 풀은 웹앱에 연결된 기본 도메인 이름으로 재정의된 호스트 이름을 사용하여 HTTPS 트래픽을 리디렉션하도록 구성됩니다. App Gateway는 Microsoft에서 발급한 기본 SSL 인증서를 신뢰합니다. Application Gateway를 사용하여 App Service 구성을 읽고 이러한 구성이 어떻게 이루어지는지 알아보세요. appgw.json의 다음 줄은 참조 구현에서 이를 구성하는 방법을 보여줍니다.

         {
            "name": "backendHttpSettingsCollection",
            "count": "[length(parameters('appgwApplications'))]",
            "input": {
              "name": "[concat(variables('appgwHttpSettingsName'), parameters('appgwApplications')[copyIndex('backendHttpSettingsCollection')].name)]",
              "properties": {
                "Port": 443,
                "Protocol": "Https",
                "cookieBasedAffinity": "Disabled",
                "pickHostNameFromBackendAddress": true,
                "requestTimeout": 20,
                "probe": {
                  "id": "[concat(variables('appgwId'), '/probes/', variables('appgwHealthProbeName'), parameters('appgwApplications')[copyIndex('backendHttpSettingsCollection')].name)]"
                }
              }
            }
          },
웹 애플리케이션 방화벽

Application Gateway의 WAF(Web Application Firewall)는 SQL 삽입과 같은 악의적인 공격으로부터 웹앱을 보호합니다. 또한 실시간 로그를 사용하여 공격을 모니터링할 수 있도록 Azure Monitor와 통합됩니다. Azure Portal을 사용하여 Web Application Firewall이 있는 애플리케이션 게이트웨이 만들기에 설명된 대로 게이트웨이에서 WAF를 사용하도록 설정해야 합니다. 참조 구현은 다음 코드 조각을 사용하여 appgw.json 파일에서 프로그래밍 방식으로 WAF를 사용하도록 설정합니다.

        "webApplicationFirewallConfiguration": {
          "enabled": true,
          "firewallMode": "Detection",
          "ruleSetType": "OWASP",
          "ruleSetVersion": "3.0"
        },

Virtual Network

네트워크 보안 그룹은 VNet에 있는 하나 이상의 서브넷에 연결할 수 있습니다. 네트워크 보안 그룹은 다양한 Azure 리소스 간에 트래픽이 흐르도록 허용하거나 거부하는 보안 규칙입니다. 이 아키텍처는 서브넷마다 별도의 NSG를 연결합니다. 이렇게 하면 해당 서브넷에 포함된 서비스에 따라 서브넷별 규칙을 미세 조정할 수 있습니다. 예를 들어 ase.json 파일의 ASE 서브넷에 대한 NSG와 appgw.json 파일의 App Gateway 서브넷에 대한 NSG의 "type": "Microsoft.Network/networkSecurityGroups" 구성을 살펴보세요.

서비스 엔드포인트는 VNet의 개인 주소 공간과 ID를 지원 Azure 서비스로 확장하여 이러한 서비스에 대한 액세스를 VNet으로만 제한합니다. 보안을 향상하려면 이를 지원하는 모든 Azure 서비스의 ASE 서브넷에서 서비스 엔드포인트를 사용하도록 설정해야 합니다. 그런 다음, 서비스에서 가상 네트워크 규칙을 설정하여 공용 인터넷의 액세스를 효과적으로 차단하는 방법으로 서비스를 엔터프라이즈 VNet에서 안전하게 보호할 수 있습니다. ASE 인프라는 이 문서의 시스템 아키텍처 섹션에서 설명한 대로 아키텍처 자체가 사용하지 않을 수 있더라도 자체 관리를 위해 Event Hubs, SQL Server 및 Storage에 대한 서비스 엔드포인트를 설정합니다. 이 아키텍처는 Service Bus, SQL Server, Key Vault 및 Azure Cosmos DB를 지원하는 사용되는 서비스에 대한 서비스 엔드포인트를 구성합니다. ase.json 파일에서 as "type": "Microsoft.Network/virtualNetworks/subnets" -->"properties" -->"serviceEndpoints"로 이 구성을 살펴보세요.

서브넷에서 서비스 엔드포인트를 사용하도록 설정하는 작업은 2단계 프로세스입니다. 리소스 자체는 이 가상 네트워크에서 서비스 엔드포인트의 트래픽을 받도록 구성해야 합니다. 자세한 내용은 리소스에 대한 네트워크 액세스 제한을 참조하세요.

방화벽

Azure Firewall 및 서비스 엔드포인트는 서로를 보완합니다. 서비스 엔드포인트는 들어오는 트래픽이 가상 네트워크에서 시작되도록 제한하여 리소스를 보호하는 반면, Azure Firewall은 애플리케이션의 아웃바운드 트래픽을 제한할 수 있습니다. 서비스 엔드포인트 트래픽을 포함하여 모든 아웃바운드 트래픽이 방화벽 서브넷을 통과하도록 하는 것이 좋습니다. 이렇게 하면 아웃바운드 트래픽을 더 잘 모니터링할 수 있습니다. 그러나 ASE 인프라를 사용하려면 ASE 서브넷에서 SQL Server, Storage 및 Event Hubs에 대한 서비스 엔드포인트를 구성해야 합니다. 방화벽 통합에 대한 내용은 App Service Environment 잠금을 참조하세요. 또한 이 구현에서는 직접 연결 모드에서 Azure Cosmos DB를 사용하므로 다양한 포트를 열어야 합니다. 이렇게 하면 방화벽 구성이 복잡해질 수 있습니다. 간단한 설명을 위해 이 참조 아키텍처에서는 방화벽 서브넷 대신 ASE 서브넷에서 모든 서비스 엔드포인트를 구성합니다. 여기에는 ASE 인프라에 필요한 엔드포인트 외에도 Service Bus, Azure Cosmos DB 및 Key Vault 대한 엔드포인트가 포함됩니다.

방화벽을 ASE와 통합하는 방법을 알아보려면 ASE를 사용하여 Azure Firewall 구성을 참조하세요. 서비스 엔드포인트 및 가상 네트워크 라우팅 테이블을 통과하지 않는 트래픽은 방화벽에 의해 모니터링 및 제어됩니다. 라우팅 테이블의 필요성은 다음 섹션에 설명되어 있습니다.

ASE 관리 IP

ASE 관리 트래픽은 엔터프라이즈 가상 네트워크를 통해 이동합니다. 이 트래픽은 방화벽을 피해서 가상 네트워크 외부의 전용 IP 주소로 직접 라우팅되어야 합니다. 이렇게 하려면 사용자 정의 가상 네트워크 라우팅 테이블을 만듭니다. App Service Environment 관리 주소 문서에 이러한 IP 주소가 나열되어 있습니다. 이 목록은 방화벽에서 수동으로 구성하기에 너무 길어질 수 있습니다. 이 구현은 이 목록을 프로그래밍 방식으로 채우는 방법을 보여줍니다. deploy_std.sh의 다음 줄은 Azure CLI 및 명령줄 JSON 파서인 jq를 사용하여 이 목록을 가져옵니다.

ENDPOINTS_LIST=$(az rest --method get --uri $ASE_ID/inboundnetworkdependenciesendpoints?api-version=2016-09-01 | jq '.value[0].endpoints | join(", ")' -j)

이 방법은 API에서 관리 주소 가져오기에 문서화된 방법과 동일합니다.

deploy_std.sh의 다음 명령은 network.json에 구성된 대로 라우팅 테이블과 함께 가상 네트워크를 만듭니다.

VNET_NAME=$(az network vnet list -g $RGNAME --query "[?contains(addressSpace.addressPrefixes, '${NET_PREFIX}')]" --query [0].name -o tsv)
az deployment group create --resource-group $RGNAME --template-file templates/network.json --parameters existentVnetName=$VNET_NAME vnetAddressPrefix=$NET_PREFIX
VNET_NAME=$(az deployment group show -g $RGNAME -n network --query properties.outputs.vnetName.value -o tsv)
VNET_ROUTE_NAME=$(az deployment group show -g $RGNAME -n network --query properties.outputs.vnetRouteName.value -o tsv)

ASE 서브넷이 만들어지면 라우팅 테이블이 이 서브넷과 연결됩니다.

az deployment group create --resource-group $RGNAME --template-file templates/ase.json -n ase --parameters vnetName=$VNET_NAME vnetRouteName=$VNET_ROUTE_NAME aseSubnetAddressPrefix=$ASE_PREFIX

방화벽이 만들어지면 firewall.json 구성 파일은 이 라우팅 테이블을 ASE 관리 IP로 업데이트한 후 방화벽 IP로 업데이트합니다. 그러면 나머지 트래픽이 방화벽 IP를 통과합니다.

{
  "variables": {
    "firewallSubnetName": "AzureFirewallSubnet",
    "firewallPublicIpName": "[concat('firewallIp', '-', uniqueString(resourceGroup().id))]",
    "firewallName": "[concat('firewall', '-', uniqueString(resourceGroup().id))]",
    "aseManagementEndpoints": "[split(replace(parameters('aseManagementEndpointsList') ,' ', ''), ',')]",
    "copy": [
      {
        "name": "aseManagementIpRoutes",
        "count": "[length(variables('aseManagementEndpoints'))]",
        "input": {
          "name": "[replace(variables('aseManagementEndpoints')[copyIndex('aseManagementIpRoutes')], '/', '-')]",
          "properties": {
            "addressPrefix": "[variables('aseManagementEndpoints')[copyIndex('aseManagementIpRoutes')]]",
            "nextHopType": "Internet"
          }
        }
      }
    ]
  },
  "resources": [
    {
      "type": "Microsoft.Network/routeTables",
      "apiVersion": "2019-11-01",
      "name": "[parameters('vnetRouteName')]",
      "location": "[parameters('location')]",
      "tags": {
        "displayName": "UDR - Subnet"
      },
      "dependsOn": [
        "[resourceId('Microsoft.Network/azureFirewalls', variables('firewallName'))]"
      ],
      "properties": {
        "routes": "[concat(variables('aseManagementIpRoutes'), array(json(concat('{ \"name\": \"Firewall\", \"properties\": { \"addressPrefix\": \"0.0.0.0/0\", \"nextHopType\": \"VirtualAppliance\", \"nextHopIpAddress\": \"', reference(concat('Microsoft.Network/azureFirewalls/', variables('firewallName')),'2019-09-01','Full').properties.ipConfigurations[0].properties.privateIPAddress, '\" } }'))))]"
      }
    }
...
...
  ]
...
...
}

라우팅 테이블이 배포된 후 관리 IP 목록이 변경될 수 있습니다. 이 경우 라우팅 테이블을 다시 배포해야 합니다.

Azure Active Directory

Azure Active Directory는 애플리케이션을 인증하고 리소스에 대한 액세스 권한을 부여하는 보안 기능을 제공합니다. 이 참조 아키텍처는 Azure Active Directory의 두 가지 주요 기능인 관리 ID 및 Azure 역할 기반 액세스 제어를 사용합니다.

클라우드 애플리케이션을 빌드할 때 클라우드 서비스에 인증하는 데 필요한 자격 증명을 보호해야 합니다. 자격 증명이 개발자 워크스테이션에 표시되거나 소스 제어에 체크 인되지 않는 것이 이상적입니다. Azure Key Vault는 자격 증명과 비밀을 안전하게 저장하는 방법을 제공하지만, 자격 증명과 비밀을 검색하려면 앱이 Key Vault에 인증해야 합니다. Azure 리소스의 관리 ID는 Azure AD에서 자동으로 관리되는 ID를 Azure 서비스에 제공합니다. 이 ID는 애플리케이션에서 자격 증명 없이 Key Vault를 포함하여 Azure AD 인증을 지원하는 서비스에 인증하는 데 사용할 수 있습니다.

Azure RBAC(Azure 역할 기반 액세스 제어)는 Azure 리소스에 대한 액세스를 관리합니다. 다음 내용이 포함됩니다.

  • 액세스 권한이 있는 엔터티: 사용자, 관리 ID, 보안 주체
  • 엔터티가 갖고 있는 액세스 권한 종류: 소유자, 기여자, 읽기 권한자, 관리자
  • 액세스 범위: 리소스, 리소스 그룹, 구독 또는 관리 그룹

필요한 역할 및 각 앱에 대한 액세스 유형을 엄격하게 제어하여 ASE 애플리케이션에 대한 액세스를 잠글 수 있습니다. 이렇게 하면 여러 개발 팀의 동일한 ASE에 여러 앱을 배포할 수 있습니다. 예를 들어 한 팀에서 프런트 엔드를 처리하고, 다른 팀에서 백 엔드를 처리할 수 있습니다. Azure RBAC를 사용하여 작업 중인 앱에 대한 각 팀의 액세스를 제한할 수 있습니다. 조직에 적합한 역할을 만들려면 Azure 사용자 지정 역할을 살펴보세요.

Key Vault

일부 서비스는 관리 ID를 지원하지만, Azure RBAC를 사용하여 앱에 대한 권한을 설정합니다. 예를 들어 Service Bus의 기본 제공 역할Azure Cosmos DB의 Azure RBAC를 참조하세요. 기여자 액세스 권한이 있는 직원이 이러한 서비스를 배포할 수 있더라도 이러한 권한을 부여하려면 구독에 대한 소유자 액세스 권한이 필요합니다. 보다 광범위한 개발자 팀이 배포 스크립트를 실행할 수 있도록 하는 그 다음으로 좋은 옵션은 서비스의 네이티브 액세스 제어 정책을 사용하는 것입니다.

이러한 액세스 제어 정책의 연결 문자열은 Key Vault에 저장됩니다. 자격 증명 모음 자체는 Azure RBAC가 필요 없는 관리 ID를 통해 액세스됩니다. 이러한 연결 문자열에 대한 액세스 정책을 적절하게 설정하세요. 예를 들어 기본 루트 액세스 정책을 사용하는 대신 백 엔드에는 읽기 전용, 프런트 엔드에는 쓰기 전용 액세스 정책을 사용하는 식입니다.

services.json의 다음 코드 조각은 이러한 서비스에 대한 KeyVault 구성을 보여줍니다.

    {
      "type": "Microsoft.KeyVault/vaults/secrets",
      "name": "[concat(variables('keyVaultName'), '/CosmosKey')]",
      "apiVersion": "2015-06-01",
      "dependsOn": [
        "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]",
        "[resourceId('Microsoft.DocumentDB/databaseAccounts', variables('cosmosName'))]"
      ],
      "properties": {
        "value": "[listKeys(resourceId('Microsoft.DocumentDB/databaseAccounts',variables('cosmosName')),'2015-04-08').primaryMasterKey]"
      }
    },
    {
      "type": "Microsoft.KeyVault/vaults/secrets",
      "name": "[concat(variables('keyVaultName'), '/ServiceBusListenerConnectionString')]",
      "apiVersion": "2015-06-01",
      "dependsOn": [
        "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]",
        "[resourceId('Microsoft.ServiceBus/namespaces/AuthorizationRules', variables('serviceBusName'), 'ListenerSharedAccessKey')]"
      ],
      "properties": {
        "value": "[listKeys(resourceId('Microsoft.ServiceBus/namespaces/AuthorizationRules',variables('serviceBusName'),'ListenerSharedAccessKey'),'2015-08-01').primaryConnectionString]"
      }
    },
    {
      "type": "Microsoft.KeyVault/vaults/secrets",
      "name": "[concat(variables('keyVaultName'), '/ServiceBusSenderConnectionString')]",
      "apiVersion": "2015-06-01",
      "dependsOn": [
        "[resourceId('Microsoft.KeyVault/vaults', variables('keyVaultName'))]",
        "[resourceId('Microsoft.ServiceBus/namespaces/AuthorizationRules', variables('serviceBusName'), 'SenderSharedAccessKey')]"
      ],
      "properties": {
        "value": "[listKeys(resourceId('Microsoft.ServiceBus/namespaces/AuthorizationRules',variables('serviceBusName'),'SenderSharedAccessKey'),'2015-08-01').primaryConnectionString]"
      }
    },

이러한 연결 문자열 값은 앱에서 Key Vault 키/값 쌍을 참조하여 액세스됩니다. 이 작업은 Voting App에 대한 다음 코드 조각과 같이 sites.json 파일에서 수행됩니다.

{
  "properties": {
    "enabled": true,
    "name": "[variables('votingWebName')]",
    "hostingEnvironment": "[variables('aseId')]",
    "serverFarmId": "[resourceId('Microsoft.Web/serverfarms', variables('votingWebPlanName'))]",
    "siteConfig": {
      "appSettings": [
        {
            "name": "ConnectionStrings:sbConnectionString",
            "value": "[concat('@Microsoft.KeyVault(SecretUri=', reference(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), variables('serviceBusSenderConnectionStringSecretName')), '2016-10-01').secretUriWithVersion, ')')]"
        },
        {
            "name": "ConnectionStrings:RedisConnectionString",
            "value": "[concat('@Microsoft.KeyVault(SecretUri=', reference(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), variables('redisSecretName')), '2016-10-01').secretUriWithVersion, ')')]"
        },
        {
            "name": "ConnectionStrings:CosmosKey",
            "value": "[concat('@Microsoft.KeyVault(SecretUri=', reference(resourceId('Microsoft.KeyVault/vaults/secrets', parameters('keyVaultName'), variables('cosmosKeySecretName')), '2016-10-01').secretUriWithVersion, ')')]"
        }
      ]
    }
  }
}

또한 이 함수는 비슷한 방식으로 Service Bus 수신기 연결 문자열에 액세스합니다.

확장성

확장 가능한 앱 디자인

이 참조 아키텍처의 애플리케이션은 사용량에 따라 개별 구성 요소를 스케일링할 수 있도록 구조화됩니다. 각 웹앱, API 및 함수는 자체 App Service 요금제에 배포됩니다. 각 앱의 성능 병목 상태를 모니터링하다가 필요한 경우 스케일 업할 수 있습니다. Azure App Service를 사용하여 확장 가능한 웹 애플리케이션을 디자인하는 방법을 알아보려면 Azure 웹 애플리케이션에서 확장성 향상을 읽어보세요.

App Gateway 자동 크기 조정

Azure Application Gateway V2에서 자동 크기 조정을 사용하도록 설정할 수 있습니다. 이렇게 하면 트래픽 부하 패턴에 따라 App Gateway를 스케일 업 또는 다운할 수 있습니다. 이 참조 아키텍처는 0~10개 사이에서 추가 인스턴스를 스케일링하도록 appgw.json 파일에서 autoscaleConfiguration을 구성합니다. 자세한 내용은 Application Gateway 및 WAF v2 크기 조정을 참조하세요.

배포

이 참조 아키텍처의 배포 스크립트는 ASE, 기타 서비스 및 ASE 내의 애플리케이션을 배포하는 데 사용됩니다. 이러한 애플리케이션이 배포되면 기업에서는 앱 유지 관리 및 업그레이드를 위한 연속 통합 및 지속적인 배포 계획을 세우는 것이 좋습니다. 이 섹션에서는 개발자가 ASE 애플리케이션의 CI/CD에 사용하는 몇 가지 일반적인 방법을 보여줍니다.

앱은 가상 네트워크 내에서만 내부 ASE에 배포할 수 있습니다. 다음 세 가지 방법은 ASE 앱을 배포하는 데 널리 사용됩니다.

  1. Virtual Network 내에 수동으로: 배포에 필요한 도구를 사용하여 ASE VNet 내에 가상 머신을 만듭니다. NSG 구성을 사용하여 VM에 대한 RDP 연결을 엽니다. 코드 아티팩트를 VM에 복사하고, 빌드하고, ASE 서브넷에 배포합니다. 초기 빌드 및 테스트 개발 환경을 설정하는 간단한 방법입니다. 그러나 필요한 배포 처리량을 스케일링할 수 없는 프로덕션 환경에는 사용하지 않는 것이 좋습니다.

  2. 로컬 워크스테이션에서 지점 및 사이트 간 연결: 이렇게 하면 ASE VNet을 개발 머신으로 확장하고 개발 머신에서 배포할 수 있습니다. 초기 개발 환경을 설정하는 또 다른 방법이며, 프로덕션에는 사용하지 않는 것이 좋습니다.

  3. Azure Pipelines를 통해: 이 방법은 온전한 CI/CD 파이프라인을 구현하며, 에이전트가 결국 VNet 내에 있게 됩니다. 이 방법은 높은 배포 처리량이 필요한 프로덕션 환경에 적합합니다. 빌드 파이프라인은 전적으로 VNet 외부에 유지됩니다. 배포 파이프라인은 빌드된 개체를 VNet 내부의 빌드 에이전트에 복사한 다음, ASE 서브넷에 배포합니다. 자세한 내용은 Pipelines와 ASE VNet 간의 자체 호스팅 빌드 에이전트에 대한 설명을 참조하세요.

프로덕션 환경에는 Azure Pipelines를 사용하는 것이 좋습니다. Azure Pipelines YAML 스키마의 도움을 받아 CI/CD를 스크립팅하면 빌드 및 배포 프로세스를 자동화하는 데 도움이 됩니다. azure-pipelines.yml은 이 참조 구현의 웹앱에 대한 CI/CD 파이프라인을 구현합니다. 웹 API함수에 대한 유사한 CI/CD 스크립트가 있습니다. 각 애플리케이션에 대해 CI/CD를 자동화하는 방법을 알아보려면 Azure Pipelines 사용을 읽어보세요.

VNet 내에서 영구 빌드 에이전트를 유지하지 않으려는 기업도 있습니다. 이 경우 DevOps 파이프라인 내에서 빌드 에이전트를 만들고, 배포가 완료되면 삭제하도록 선택할 수 있습니다. 이렇게 하면 DevOps에 또 다른 단계가 추가되지만 VM 유지 관리의 복잡성이 줄어듭니다. VM 대신 컨테이너를 빌드 에이전트로 사용하는 방법도 고려해 볼 수 있습니다. VNet 외부(일반적으로 스토리지 계정)에 배치된 압축 파일에서 배포하면 빌드 에이전트를 완전히 피할 수도 있습니다. 스토리지 계정은 ASE에서 액세스할 수 있어야 합니다. 파이프라인에서 스토리지에 액세스할 수 있어야 합니다. 릴리스 파이프라인이 끝나면 압축된 파일을 Blob 스토리지에 드롭할 수 있습니다. 그러면 ASE가 이 압축된 파일을 선택하여 배포할 수 있습니다. 이 방법은 다음과 같은 제한이 있습니다.

  • DevOps와 실제 배포 프로세스 간에 연결이 끊어져 배포 문제를 모니터링하고 추적하는 데 어려움이 있습니다.
  • 트래픽이 보호되는 잠긴 환경에서는 스토리지의 압축된 파일에 액세스하려면 규칙을 변경해야 할 수도 있습니다.
  • zip에서 배포할 수 있도록 ASE에 특정 확장 및 도구를 설치해야 합니다.

앱을 App Service 요금제에 배포할 수 있는 몇 가지 방법을 더 알아보려면 배포 전략에 초점을 맞춘 App Service 문서를 참조하세요.

비용 최적화

Azure 가격 계산기를 사용하여 비용을 예측합니다. 기타 고려 사항은 Microsoft Azure Well-Architected Framework의 비용 섹션에 설명되어 있습니다. Azure Reservations는 여러 Azure 리소스의 1년 또는 3년 플랜에 따라 비용을 절감하는 데 도움이 됩니다. 예약 구입 문서에서 자세한 내용을 읽어보세요.

다음은 이 아키텍처에 사용되는 주요 서비스에 대해 고려할 사항입니다.

App Service 환경

App Service에 제공되는 다양한 가격 책정 옵션이 있습니다. App Service 환경은 격리된 서비스 요금제를 사용하여 배포됩니다. 이 요금제 내에는 CPU 크기에 대한 I1, I2 및 I3 세 가지 옵션이 있습니다. 이 참조 구현에서는 인스턴스당 3개의 I1을 사용하고 있습니다.

Application Gateway

Application Gateway 가격 책정에서는 App Gateway에 대한 다양한 가격 책정 옵션을 제공합니다. 여기서는 자동 크기 조정과 영역 중복을 지원하는 Application Gateway Standard_v2 및 WAF_v2 SKU를 사용하고 있습니다. 이 SKU에 사용되는 가격 책정 모델에 대한 자세한 내용은 이 문서를 참조하세요.

Azure Cache for Redis

Azure Cache for Redis 가격 책정에서는 이 서비스에 대한 다양한 가격 책정 옵션을 제공합니다. 이 아키텍처에서는 가상 네트워크 지원을 위해 프리미엄 SKU를 사용합니다.

다음은 ASE를 잠그는 데 사용되는 다른 서비스의 가격 책정 페이지입니다.

시나리오 배포

이 아키텍처의 참조 구현을 배포하려면 GitHub 추가 정보을 확인하고, 표준 배포에 대한 스크립트를 따르세요.

참가자

Microsoft에서 이 문서를 유지 관리합니다. 원래 다음 기여자가 작성했습니다.

보안 주체 작성자:

공용이 아닌 LinkedIn 프로필을 보려면 LinkedIn에 로그인합니다.

다음 단계

고가용성을 지원하도록 이 아키텍처를 확장하는 방법을 알아보려면 App Services 환경을 사용하여 고가용성 앱 배포를 읽어보세요.