Azure 앱서비스(웹앱, API앱, 모바일앱)를 가상네트워크에 연결

Azure의 App Services로 웹사이트, 모바일 백엔드, API서버를 구축할 때 데이터베이스가 필요하다면 Azure SQL Server를 사용하는 것이 최적의 선택이라고 생각합니다. 이유는 Azure가 인프라스트럭쳐를 모두 관리해주는 PaaS의 기본 개념에 충실 할 수 있어 개발자들은 코드에만 집중할 수 있게 하기 때문이죠.

하지만 개발이나 운영을 하다보면 여러가지 이유로 Azure SQL Server를 사용할 수 없는 경우도 발생하게 됩니다. 이미 SQL Server 라이센스를 구입했다거나 아키텍쳐 구성 때문에 또는 성능 문제, 안 써봐서 괜히 불안한 느낌 등의 이유 때문에 가상 머신에 SQL Server를 설치해서 운영을 하기도 합니다.

Azure App Services와 가상머신에 설치된 SQL Server 환경에서 한가지 고민이 생깁니다. 두 개를 어떻게 연결을 할 것인가에 대한 문제죠. 이 문제의 원인은 App Services의 Web App, Mobile App, API App이 가상 네트워크에 들어가지 않기 때문입니다. (2016-07-29 수정) 앞으로 개발이 되서 자연스럽게 해결이 되겠지만 이 글을 쓰는 지금은 다른 방법을 써야 힙니다. 그 이유를 어려운 용어로 말하자면 App Services는 멀티태넌트(Multi tenant) 구조이고 가상 네트워크는 싱글 테넌트(Single tenant) 구조이기 때문에 그렇습니다. App Services는 내가 배포한 앱도 돌아가지만 다른 서비스도 같이 돌면서 리소스를 같이 쓰는 환경이고 가상네트워크는 온전히 내가 만들어서 나만 씁니다. 네트워크도 공유하는 환경인 App Service의 설정이 변경되면 모든 앱이 영향을 받기 때문에 가상네트워크에 근본적으로 들어갈 수 없습니다. 아래 그림 Web App의 Netowkring 블레이드에 나온 3가지 방법과 Public IP를 사용하는 총 4가지 방법이 있습니다. 여기서는 public IP를 사용하는 방법과 VPN을 사용하는 두가지 방법에 대해서 살펴보겠습니다.

3가지 방법

1. Public IP를 사용하는 방법

SQL Server VM에 NIC(Network Card Interface)를 붙이고 Public IP를 할당한 후 접속하는 방식입니다. 간단하죠. 두가지 단점이 있습니다.

  • Public IP를 사용하기 때문에 인터넷에서 보인다는 것이죠. NSG(Network Security Group)으로 접근 제어를 해야합니다. 즉 1433 EndPoint를 만드는데 Web App 에서만 접근 할 수 있도록 해야 합니다. 또한 sa 계정을 사용하지 않는 등 SQL 서버의 설정과 보안에 각별한 주의가 필요합니다.
  • Outbound Traffic이기 때문에 비용이 발생합니다. 즉 App Service와 SQL Server가 설치된 VM 사이의 통신에 비용이 발생합니다. Azure Outbound Traffice 비용

단점이 있지만 Configuration이 단순해서 좋습니다.

2. Point-to-Site VPN을 사용하여 연결하는 방법

조금 복잡해 보일 수도 있지만 Point-to-Site VPN을 사용하여 연결할 수 있습니다. 여기서 Point는 App Service의 App이고 Site는 SQL Server 가상머신이 자리잡고 있을 가상네트워크 입니다. 원래는 Azure 외부, 정확히 말해서는 가상 네트워크 외부의 컴퓨터와 가상네트워크를 VPN으로 연결하는데 쓰이지만 App Services도 연결을 할 수 있습니다. 아래 그림과 같이 설정이 됩니다.

Point-to-site VPN 연결

이 방법의 장점은 SQL Server 가상머신을 외부에 노출시키지 않고 가상네트워크안에서 보호할 수 있습니다. NSG(Network Security Group)을 이용해서 SQL Server의 접속은 가상네트워크 안의 다른 서브넷에서만 접속 가능하게하고 Public IP를 설정하지 않을 수 있습니다.

단점도 알고 가야 하는데 먼저 App Services가 표준(Standard)또는 프리미엄(Preminum) 앱 서비스 계획에 속해야 합니다. 그리고 두가지 비용이 추가로 발생하게 됩니다.

또한 연결 포인트가 많아 지기 때문에 모니터링에도 신경을 써야 합니다. 어떤 문제가 발생했을 때 어느 부분에서 발생했는지를 빠르게 파악하는게 중요하니까요.

아래 문서들을 참고하여 작성한 PowerShell 코드를 공유합니다.

Azure 가상 네트워크에 앱 통합 PowerShell을 사용하여 가상 네트워크에 지점 및 사이트 간 연결 구성 지점 및 사이트 간 구성에 대한 자체 서명된 루트 인증서로 작업

 # 지역 (Japan West)
$location = "japanwest"
# 리소스 그룹 이름
$rgName = "MovedServiceV2"
# 가상네트워크 가져오기
$vnetName = "MovedServiceVNet"
$gwSubnetName = "GatewaySubnet"
$vnet = Get-AzureRmVirtualNetwork -Name $vnetName -ResourceGroupName $rgName
$subnet = Get-AzureRmVirtualNetworkSubnetConfig -Name $gwSubnetName -VirtualNetwork $vnet

# 게이트웨이에 사용할 IP 만들기 
$gwIPName = "GatewayIP"
$gwIPConfigName = "GatewayIPConfig"
$gwPip = New-AzureRmPublicIpAddress -Name $gwIPName -ResourceGroupName $rgName -Location $location -AllocationMethod Dynamic
$ipconfig = New-AzureRmVirtualNetworkGatewayIpConfig -Name $gwIPConfigName -Subnet $subnet -PublicIpAddress $gwPip

# 인증서 만들기
& 'C:\Program Files (x86)\Windows Kits\10\bin\x64\makecert.exe' -sky exchange -r -n "CN=MovedSVCGWRootCert" -pe -a sha1 -len 2048 -ss My "MovedSVCGWRootCert.cer"

$P2SRootCertPubKeyBase64 = "MIIDDjCCAfqgAwIBAgIQUKURF8y/drVEk6x+Tx18LTAJBgUrDgMCHQUAMB0xGzAZBgNVBAMTEk1vdmVkU1ZDR1dSb290Q2VydDAeFw0xNjA3MTgwMjE2MTdaFw0zOTEyMzEyMzU5NTlaMB0xGzAZBgNVBAMTEk1vdmVkU1ZDR1dSb290Q2VydDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM4xhjEepNZPYIwyJeRqdDflsDUOvortz+D8GUvpxTSL3M4Uqy00FRRQcu4CqzBjaK+dN/Tr4wb1DR1KHp1M8h9KnSkxjugGUDJIucvtpndTVOYwclDTQktmDOheZdM5AyY3k2fx1o1vr7MVvtaKFpYGXv7Ivck/B0felwid2AsL1gR/dyrft3l/pNEdTu9gBcQAu0UH6OvffXnjcosCRQaVF0NPO+mBN6QMhbPZb/beojwYJEdZtaKDdx3Ljo3IupibZdtFf63w5eWoeWi2RXXhmob0tKXXntNHeykox2DIj8tQC+uBmT4HGKRJXqMamb1xbo1MKlMSAFxLjfsj/TUCAwEAAaNSMFAwTgYDVR0BBEcwRYAQnMFDjarPhbfTzdSoDT+J96EfMB0xGzAZBgNVBAMTEk1vdmVkU1ZDR1dSb290Q2VydIIQUKURF8y/drVEk6x+Tx18LTAJBgUrDgMCHQUAA4IBAQAQ5XHibrt9wxQhsj+lG71K4w6nXu2I+JeiepE0+0IoR3btbvcTC9gejCBoFH6hpGBLn++Qic1nClLryyBzZ+cvlPclHyotROe7/PAMDkYueXt5Agkq9ZNEeoAIzXzgLJ3SK5F39E41d4ol81nuVHtobaIgK6nj0UFkuPLIxZxe/VRxV15UYqWwdnUL6F0s+JDx83RXBY8Kwe/flHKW+swb/ONFGGHYjmdPUfHzVb2YuefIaqSUhdp46v0CDZud1zQ0eVh0vnTAnB37vasUNj0Qb0nzyqBW3/bYJ4W9ESXIHulyxbAB4sHJjyAf0GzrNsGQykCephcwJmcqkUoNz7"

$p2srootcert = New-AzureRmVpnClientRootCertificate -Name "MovedSVCGWRootCert.cer" -PublicCertData $P2SRootCertPubKeyBase64

# 게이트웨이 만들기
$gwName = "MovedSvcVNetGW"
$vpnClientAddressPool = "172.16.201.0/24"
New-AzureRmVirtualNetworkGateway -Name $gwName -ResourceGroupName $rgName -Location $location -IpConfigurations $ipconfig -GatewayType Vpn -VpnType RouteBased -EnableBgp $false -GatewaySku Basic -VpnClientAddressPool $vpnClientAddressPool

이렇게 만든 구성을 Web App의 '네티워킹' > 'VNET 통합' 블레이드 에서 확인 할 수 있습니다.

Web App과 VNet 연결

이렇게 구생했을 때 Web App에서 SQL Server의 Connection String은 아래와 같이 VNet의 BackEnd Subnet에서 SQL Server가 할당받은 Private IP(여기서는 192.168.2.4)를 사용할 수 있습니다.

 Server=tcp:192.168.2.4,1433;Data Source=192.168.2.4;Initial Catalog=test_db;Persist Security Info=False;User ID={id};Password={password};Pooling=False;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=True;Connection Timeout=30;