TOPIC/Cloud

Azure Firewall의 SNAT와 DNAT 공부 하기

H-Y-E-N 2023. 11. 28. 17:20

안녕하세요. HYEN입니다.

이번에는 지난 글과 관련된 테스트 중 궁금했던 Azure Firewall의 SNAT와 DNAT에 대해 알아보도록 하겠습니다. 😉

지난 글 링크 : 
https://with-cloud.tistory.com/7

Contents

    1. 궁금증의 시작

    지난번 글 작성을 위해 테스트를 하다가 Spoke 1 대역의 Client VM에서 traceroute를 날려 보았습니다.

    그 결과가 제가 이 글을 작성하는 계기가 되었는데요. 

     

    목적지 VM에 도착하기 위한 첫 번째 경로에,

    AzureFirewallSubnet 대역 내의 ip이지만 Azure Firewall의 private ip가 아닌 IP가 조회가 되었습니다. 😢

    이 IP는 대체 무엇인가! 이게 바로 저의 첫 번째 궁금증이었습니다. 

     

    또한 Spoke 1 대역의 Client VM에서 Spoke 2 대역의 Destination VM으로 tcping을 날리는 동안 Destination VM에서 tcpdump를 뜰 때 Client VM의 ip가 조회가 되는지 테스트를 해보았습니다.

    tcpdump src 10.20.0.4(Client VM의 private ip)를 하면 아무런 packet도 출력되지 않았습니다. 🤔

    왜 출력이 되지 않는가! 이게 저의 두 번째 궁금증이었습니다. 

     

    이러한 궁금증들을 해소하기 위해 좀 더 테스트를 진행해 보았고 그 과정에서 Azure Firewall의 로직과 SNAT, DNAT에 대해 좀 더 이해하게 되었습니다. 

     

    2. Azure Firewall의 로직

    우선 Azure Firewall의 로직부터 살펴 보도록 하겠습니다. 

    하기 이미지에는 저를 혼란에 빠트린 traceroute의 결과가 출력되어 있습니다.

    저는 Spoke 1 대역의 Client VM에서 Spoke 2 대역의 Destination VM으로 traceroute를 날렸고 첫 번째 hop으로 10.10.0.5라는 ip가 출력이 되었습니다.

    해당 ip는 AzureFirewallSubnet의 ip 대역인 10.10.0.0/26 내에 존재하고 있지만 Azure Firewall의 private ip는 아니기 때문에 대체 이 ip는 어떤 ip일까하는 의문이 생겼습니다. 

     

    추가 확인 결과, 상기 이미지의 10.10.0.5는 Azure Firewall의 인스턴스 ip 였습니다. 🫠

     

    공식 문서에 따르면, Azure Firewall은 active-active 구성의 여러 백 엔드 노드로 구성되어 있습니다.

    이때 Azure Firewall의 private ipInternal Load Balancer의 Frontend ip 역할을 한다고 볼 수 있습니다. 

     

    따라서 Spoke 1 대역의 Client VM에서 Azure Firewall을 거쳐 Spoke 2 대역의 Destination VM으로 이동할 때,

    패킷은 Azure Firewall의 private ip로 전달이 되고 Load Balancing Rule에 의해 Backend에 배포되어 있는 Azure Firewall Instance 중 임의의 한 대로 부하 분산이 되게 됩니다. 

    그렇기 때문에 traceroute를 할 때 다음 hop이 Azure Firewall의 Instance의 private ip로 조회된 것입니다. 

     

    이로서 저의 첫번째 궁금증이 해결되었습니다. 🎶

     

    3. Azure Firewall SNAT 개인 IP 주소 범위 

    SNAT는 Source NAT 즉, 출발지의 ip를 변경하는 NAT입니다.

    저는 Azure Firewall의 SNAT 옵션에 대해 2가지 테스트를 해 보았습니다. 

    (해당 옵션은 [방화벽 정책] > [설정] > [개인 IP 범위(SNAT)]에서 확인할 수 있습니다.)

     

    3.1 Source IP가 Private IP일 경우 

    우선, Spoke 1 대역의 Client VM은 Azure Virtual Network 내 존재하고 공인 ip도 붙어 있지 않습니다.  

    Azure Firewall의 개인 ip 범위(SNAT) 옵션은 Default 값이 "아래 지정된 ip 주소를 제외한 모든 ip 주소의 경우"이며 "예외 값은 IANA RFC 1918(기본값)"입니다. 

     

    여기서 예외 처리된 대역은 private ip 대역이기 때문에 private ip 대역에서는 기본적으로 Azure Firewall을 거쳐도 출발지 ip에 대한 SNAT가 수행되지 않습니다. 

     

    실제로 테스트를 해보겠습니다. 

     

    Spoke 1 대역의 Client VM에서 Spoke 2 대역의 Destination VM으로 tcping을 날리면서 동시에 Spoke 2 대역의 Destination VM에서 tcpdump를 통해 패킷을 확인해 보겠습니다. 

    • Spoke 1 대역의 Client VM (tcping은 Ubuntu 20.04의 경우 별도로 설치가 필요합니다.)
      • tcping 10.30.0.68 22 명령어 실행 

     

    • Spoke 2 대역의 Destination VM ① 
      • tcpdump src 10.10.0.7 명령어 실행
        • 위 Source ip 주소는 Azure Firewall의 인스턴스 ip 입니다. 

     

    tcping을 날렸고 22번 포트는 열려 있지만 Azure Firewall의 인스턴스 ip를 출발지로 하는 패킷이 들어오는 것이 없다는 것을 확인할 수 있습니다.

    Source ip가 Private일 경우 Azure Firewall의 SNAT 옵션이 적용되지 않았기 때문이죠. 

     

    • Spoke 2 대역의 Destination VM ②
      • tcpdump src 10.20.0.4 명령어 실행 
        • 실제 tcping을 날리는 Client VM의 ip를 Source ip로 지정하여 tcpdump를 떠보도록 하겠습니다. 

    Source ip가 Client VM의 ip일 때 tcpdump를 떠보면 이전 결과값과는 다르게 정상적으로 패킷이 캡처되는 것을 확인할 수 있습니다.

    Source ip가 Azure Firewall의 인스턴스 ip로 NAT 되지 않았기 때문에 실제 패킷을 보내는 곳의 ip를 알 수 있는 것입니다. 

     

    그렇다면, Azure Firewall의 개인 IP 범위(SNAT) 옵션을 "항상"으로 바꾼다면 어떻게 될까요?

    이렇게 되면 위 테스트와 반대로 Client VM의 ip로는 tcpdump를 통해 패킷 캡처가 불가하고 Azure Firewall의 인스턴스 ip로는 패킷 캡처가 가능할 것입니다. 

     

    실제로 확인해 보기 위해 우선 옵션을 변경해 보겠습니다.

    (SNAT 옵션 변경에는 시간이 약 3~5분 정도 걸립니다.)

    • Spoke 1 대역의 Client VM 
      • tcping 10.30.0.68 22 명령어 실행 

     

    • Spoke 2 대역의 Destination VM ①
      • tcpdump src 10.10.0.7 명령어 실행

    이번에는 Azure Firewall의 인스턴스 ip를 출발지로 하는 패킷이 들어오고 있습니다. Azure Firewall의 SNAT 옵션이 잘 적용된 것을 확인할 수 있습니다. 

     

    • Spoke 2 대역의 Destination VM ②
      • tcpdump src 10.20.0.4 명령어 실행

    Azure Firewall의 SNAT 옵션이 "항상"으로 변경된 경우 Spoke 1 대역의 Client VM의 ip를 Source로 하는 패킷은 캡처되지 않습니다.

    즉, Destination VM에서는 실제 출발지의 ip를 확인할 수 없게 됩니다. 

     

    테스트를 진행하다 보니 그렇다면 Source ip가 public ip인 경우에는 어떻게 되는 것일까? 라는 세 번째 의문이 생겼습니다.

    이를 해결하기 위해 제 Local PC에서 Spoke 2 대역의 VM으로 패킷을 날리고 Spoke 2 대역의 VM에서 wireshark를 사용하여 패킷을 확인해 보았습니다. 

     

    3.2 Source IP가 Public IP일 경우 

    이 테스트를 수행하기 위해서 지난 글에서 배포한 환경에 추가되어야 할 것이 있어 배포를 진행하였습니다.

     

    3.2.1 Spoke 2 대역에 Windows VM 추가 배포

    ※ [가상 머신] 배포에 대한 상세한 설명은 생략하겠습니다.

    • 이미지 및 SKU
      • Windows Pro 11, Standard D4s v5(4개 vcpu, 16GiB 메모리)
    • public ip
      • 없음 

     

    3.2.2 Spoke 2 대역의 Windows VM에 Wireshark 설치 

    • 배포한 Spoke 2 대역의 Windows VM에 접근합니다. 
      • public ip가 붙어 있지 않기 때문에 Hub 대역에 배포한 Bastion용 VM에 접근한 후 Remote Desktop을 실행합니다. 
      • Spoke 2 대역의 Windows VM의 private ip를 입력한 후 ID/PW를 입력하여 VM에 접속합니다. 

    • 기본값으로 유지한 채로 설치를 진행합니다. 
    • 설치가 완료되었다면 wireshark를 실행합니다. 

     

    3.2.3 Azure Firewall DNAT 규칙 추가 

    현재 제 Local PC의 경우, Azure 대역과 VPN 또는 ExpressRoute로 연결되지 않았기 때문에 private ip만 붙어 있는 Spoke 2 대역의 Destination VM에 도달할 수 없습니다.

     

    그렇다면 Local PC에서는 어떻게 Destination VM을 찾아갈 수 있을까요?

     

    Azure Firewall의 DNAT 규칙을 사용하면 Local PC에서 Destination VM을 찾아갈 수 있습니다.

    여기서, DNAT는 Destination NAT 즉, 도착지의 ip를 변경하는 NAT를 뜻합니다.

     

    제 Local PC에서 Azure Firewall의 public ip와 지정한 포트를 통해 Azure Firewall까지 도달하면

    Azure Firewall이 DNAT 규칙에 따라 Azure Firewall 뒤에 있는 실제 Destination VM으로 트래픽을 보내게 됩니다. 

     

    이를 위해 Azure Firewall의 방화벽 규칙에 DNAT 규칙을 추가해 주도록 하겠습니다. 

    • [방화벽 규칙] > [설정] > [DNAT 규칙] 탭에서 [+ 규칙 컬렉션 추가]를 클릭합니다.

    이름 : rule-collection-dnat # 규칙 컬렉션 이름 입력
    규칙 컬렉션 형식 : DNAT
    우선 순위 : 200 # 같은 [규칙 컬렉션] 내에서의 우선 순위를 의미함
    규칙 컬렉션 그룹 : DefaultDnatRuleCollectionGroup

     

    • 하단의 [규칙] 섹션에서 방화 규칙을 추가합니다.

    이름 : rule-local-to-fw-01 # 규칙 이름 입력
    Source Type : IP 주소 
    Source IP Addresses : Local PC의 public ip 주소 입력 # google에 my ip address라고 검색 시 확인 가능
    Destination IP Addresses : Azure Firewall의 public ip 주소 입력
    Protocol : TCP/UDP 중 선택
    Destination Ports : Local PC에서 Destination VM에 접근하기 위해 알아야 하는 포트 번호 # 임의 지정 가능
    Translated Type : IP address
    Translated Address : 실제 Destination VM의 private ip
    Translated Port : 실제 Destination VM에 접근하기 위한 open된 포트

     

    위와 같이 규칙이 잘 추가된 것을 확인할 수 있습니다.

     

     

    3.2.4 통신 테스트  

    Local PC에서 Spoke 2 대역의 Windows VM으로 tcping을 날리고 Destination VM에 설치한 wireshark를 통해 패킷을 확인해 보겠습니다. 

    • 현재 Azure Firewall의 [개인 IP 범위(SNAT)] 옵션값은 "항상"입니다. 
    • Local PC에 tcping이 설치되어 있지 않다면, https://www.elifulkerson.com/projects/tcping.php에서 "tcping.exe" 파일을 다운로드 받은 후, "C:\Windows\System32" 폴더로 해당 파일을 이동시킵니다. 
    • Local PC에서는 Command 창을 켜고, Destination VM에서는 3.2.2에서 설치한 wireshark를 실행한 후 "Ethernet"을 클릭합니다.

    • 상단의 빨간색 네모 버튼 []을 클릭하여 패킷 캡처를 중단합니다.

    • Local PC의 Command 창에서 tcping -n 100 {Azure Firewall의 public ip} 9000을 입력합니다. 
      (Windows의 경우 tcping을 기본적으로 4번만 수행하고 자동으로 종료하기 때문에 -n 100을 명령어에 추가하여 충분하게 패킷을 보낼 수 있도록 합니다.)
    • wireshark 프로그램 상단의 파란색 버튼을 클릭한 후 "Continue without Saving"을 선택하여 패킷 캡처를 시작합니다. 

    • 회색 행 또는 빨간색 행이 wireshark에서 보일 때까지 패킷 캡처를 진행한 후 보인다면 빨간색 버튼을 클릭하여 캡처를 중단합니다. 
    • Local PC에서 tcping 결과를 확인합니다. 

    DNAT 규칙이 잘 반영되어 Azure Firewall의 public ip와 지정한 포트로 패킷이 잘 보내지는 것을 확인했습니다.

    이렇게 되면 Azure Firewall에서 DNAT 규칙을 보고 이 패킷을 실제 Destination VM으로 보내주게 됩니다. 

     

    그렇다면 잘 갔는지 wireshark에 수집된 패킷을 확인해 보겠습니다. 

    Source ip가 Azure Firewall의 인스턴스 ip이고 Destination ip는 Destination VM의 private ip인 것으로 보아 정상적으로 규칙이 적용되고 있는 것을 알 수 있습니다. 

    포트 역시 Destination 포트인 3389로 잘 포워딩된 것을 확인할 수 있습니다. 

     

    그렇다면 Azure Firewall의 SNAT 옵션을 "안 함"으로 변경하면 어떻게 될까요?

    Source ip인 제 Local PC의 public ip가 Azure Firewall의 인스턴스 ip 대신 출력될까요? 

     

    답은 No입니다. 

    그 이유는, public ip가 Source ip일 경우 SNAT를 무조건 수행하는 것이 Azure Firewall의 기본 SNAT 동작 로직이기 때문입니다. 

    실제로 변경한 후에 테스트를 수행해도 Azure Firewall의 인스턴스 ip만 출력되는 것을 확인했습니다. 

     

    4. Source IP가 Public IP일 경우, Source IP를 확인하는 방법

    그렇다면, Azure Firewall을 사용할 때에는 Source IP가 public ip일 경우 어떤 ip로 Azure 대역에 접근하는지 정말 확인할 수 없을까요?  

     

    방법은 있습니다. 

    http/https인 경우 x-forwarded-for header 정보로 실제 client의 public ip를 추적할 수 있습니다. 

    이 부분은 나중에 다시 정리해 보도록 하겠습니다. 

     

    Azure에서는 [진단 설정]을 사용하여 확인하는 방법이 있습니다. 

    우선 [방화벽] > [모니터링] > [진단 설정]으로 이동하여 Network Rule만 수집(지난 글 참고)하기로 되어 있는 진단 설정에 대해 [Azure Firewall Nat Rule] 범주를 추가합니다. 

     

     

    그런 다음 방화벽 규칙에 등록되어 있는 public ip가 아닌 다른 public ip로 tcping -n 100 {Azure Firewall의 public ip} 9000를 수행합니다. 

    당연하게도 연결이 되지 않아 "No response"라는 응답이 출력됩니다.

    Azure Firewall의 DNAT Rule에 해당 public ip를 허용하는 규칙을 추가해 주지 않았기 때문입니다. 

     

    다음으로 방화벽 로그가 저장되어 있는 [스토리지 계정]으로 이동하여 로그 파일을 다운로드 합니다. 

    파일에는 JSON 형식으로 된 로그들이 저장되어 있습니다.

    11번 째 라인의 경우 Source ip가 Azure Firewall의 DNAT Rule에 등록된 125.x.x.41입니다.

    해당 ip가 [규칙 컬렉션 그룹], [규칙 컬렉션], [규칙]의 적용을 받아 Destination과 잘 통신이 되는 것을 확인할 수 있습니다. 

     

    그러나 12번 째 라인을 확인해 보면 11번 째 줄과 다른 점이 보입니다.

    우선, Source ip는 Azure Firewall의 DNAT Rule에 등록되지 않은 125.x.x.40입니다.

    Action의 값을 확인해 보면 "Deny"로 출력된 것도 확인할 수 있습니다.

     

    Source ip가 public ip일 경우, Azure Firewall의 옵션으로 인해 Source ip가 SNAT 되더라도 DNAT 규칙에 대한 로깅을 함으로서 Source ip를 체크할 수 있습니다. 


    이상으로 Azure Firewall에 대한 추가 공부를 마무리 하겠습니다.😉

    728x90
    320x100
    SMALL