├── 0-prerequisites.md ├── 1-scenario.md ├── 2-scenario.md ├── 3-scenario.md ├── 4-scenario.md ├── 5-scenario.md ├── 6-scenario.md ├── 7-scenario.md ├── README.md ├── docs ├── appendix-appgwcapability.png ├── appendix-appgwvsfrontdoor1.png ├── appgw-1.png ├── appgw-model.png ├── basic_infrastructure.png ├── scenario1-backendpools-1.png ├── scenario1-backendpools-2.png ├── scenario1-backendsettings-1.png ├── scenario1-backendsettings-2.png ├── scenario1-frontendipconfigurations.png ├── scenario1-listeners-1.png ├── scenario1-listeners-2.png ├── scenario1-result.png ├── scenario1-routingrule-1.png ├── scenario1-routingrule-2.png ├── scenario1-routingrule-3.png ├── scenario1.gif ├── scenario2-backendpools.png ├── scenario2-insights.png ├── scenario2-listeners-app1.png ├── scenario2-listeners-app2.png ├── scenario2-listeners-hub.png ├── scenario2-monitoring.png ├── scenario2-overview.png ├── scenario2-result-app1.png ├── scenario2-result-app2.png ├── scenario2-result-hub.png ├── scenario2-result-johndoe.png ├── scenario3-change_tier.png ├── scenario3-marketplace.png ├── scenario3-monitoring.png ├── scenario3-overview.png ├── scenario3-result-app1.png ├── scenario3-result-app2.png ├── scenario3-result-hub.png ├── scenario3-wafpolicy-default.png ├── scenario3-wafpolicy-default2.png ├── scenario3-wafpolicy-default3.png ├── scenario3-wafpolicy-default4.png ├── scenario3-wafpolicy-default5.png ├── scenario4-app1-snet-workload-rt.png ├── scenario4-app2-snet-workload-rt.png ├── scenario4-azurefirewalllogs.png ├── scenario4-backendhealth.png ├── scenario4-error.png ├── scenario4-hub-snet-appgw-public-rt.png ├── scenario4-hub-snet-workload-rt.png ├── scenario4-networkrules.png ├── scenario4-udr-overview.png ├── scenario4.gif ├── scenario5-app2-http_listener.png ├── scenario5-app2-listener.png ├── scenario5-app2-redirecthttptohttps.png ├── scenario5-app2-vm-1.png ├── scenario5-letsencrypt-1.png ├── scenario5-letsencrypt-2.png ├── scenario5-letsencrypt-3.png ├── scenario5-result.png ├── scenario5.gif ├── scenario6-BackendSetting_HTTPS_443_app1.png ├── scenario6-RoutingRule_app1.png ├── scenario6-a2ensite.png ├── scenario6-endtoend.png ├── scenario6-generate_ssl.png ├── scenario6-overview.png ├── scenario7-BackendPool-appservice.png ├── scenario7-BackendSetting_HTTP_443_appservice.png ├── scenario7-Listener-Public-Http_appservice.png ├── scenario7-RoutingRule_appservice1.png ├── scenario7-RoutingRule_appservice2.png ├── scenario7-appservice-108.142.153.65.nip.io.png ├── scenario7-overview.png ├── scenario7-webapp-accessrestriction1.png ├── scenario7-webapp-accessrestriction2.png ├── scenario7-webapp-accessrestriction3.png ├── scenario7-webapp-forbidden.png └── scenario7-webapp.png └── templates ├── .gitignore ├── appgw-public.tf ├── azurefirewall.tf ├── main.tf ├── network-topology.tf ├── variables.tf └── vms.tf /0-prerequisites.md: -------------------------------------------------------------------------------- 1 | ### [<< BACK TO THE MAIN MENU](https://github.com/dawlysd/azure-application-gateway-microhack) 2 | 3 | # Prerequisites 4 | 5 | ## Overview 6 | 7 | To achieve all of the MicroHack scenarios, let's deploy this basic infrastructure: 8 | 9 | ![image](docs/basic_infrastructure.png) 10 | 11 | > Application Gateway public IP and Azure Firewall public IP will not be the same in your environment: you will have to adapt your tests. 12 | > 13 | > Virtual machines private IPs will be the same as those indicated on the diagram. 14 | > 15 | > A web server is installed on all the machines in the diagram, listening on port :80 with a default page indicating the name of the machine. 16 | 17 | ## Task 1: Deploy Templates 18 | 19 | To start the Terraform deployment, follow the steps listed below: 20 | 21 | - Login to Azure Cloud shell [https://shell.azure.com/](https://shell.azure.com/) 22 | - Ensure that you are operating within the correct subscription via: 23 | 24 | `az account show` 25 | 26 | - Clone the current GitHub repository 27 | 28 | `git clone https://github.com/dawlysd/azure-application-gateway-microhack` 29 | 30 | - Go to the new folder *azure-application-gateway-microhack/* and initialize the terraform modules 31 | 32 | `cd azure-application-gateway-microhack/templates` 33 | 34 | `terraform init` 35 | 36 | - Now run apply to start the deployment 37 | 38 | `terraform apply` 39 | 40 | - Choose a suitable password to be used for your Virtual Machines administrator account (username: adminuser) 41 | 42 | - When prompted, confirm with a **yes** to start the deployment 43 | 44 | - Wait for the deployment to complete. This will take around 15 minutes (Application Gateway & Azure Firewall provisionning takes a while). 45 | 46 | 47 | ## Task 2: Explore and verify the deployed resources 48 | 49 | * Verify you can access via Serial Console: 50 | * app1-vm in app1-rg 51 | * app2-vm in app2-rg 52 | * hub-vm in hub-rg 53 | * Verify VNet peering status between hub-vnet and app1-vnet 54 | * Verify VNet peering status between hub-vnet and app2-vnet 55 | 56 | 57 | ## 🏁 Results 58 | * You have deployed the basic infrastructure required to continue this MicroHack 59 | * You have become familiar with the components you have deployed in your subscription 60 | * You are now able to login to all VMs using your specified credentials via Serial Console 61 | 62 | 63 | ### [>> GO TO SCENARIO #1](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/1-scenario.md) 64 | 65 | -------------------------------------------------------------------------------- /1-scenario.md: -------------------------------------------------------------------------------- 1 | ### [<< BACK TO THE MAIN MENU](https://github.com/dawlysd/azure-application-gateway-microhack) 2 | 3 | # Scenario #1: Expose app1-vm website on to the Internet 4 | 5 | During the infrastructure deployment with Terraform, several settings in Application Gateway were configured. Let's play with these settings! 6 | 7 | ## Overview 8 | 9 | `app1-vm` machine is running a HTTP webserver listening on port :80 privately. 10 | 11 | Let's expose this private webserver on to the Internet through Application Gateway: 12 | 13 | ![image](docs/scenario1.gif) 14 | 15 | > In this MicroHack, Application Gateway will have a single public IP address. 16 | 17 | ## Task 1: Understand Application Gateway components model 18 | 19 | To distribute traffic, an Application Gateway uses several components : 20 | 21 | ![image](docs/appgw-model.png) 22 | 23 | Review [the documentation](https://learn.microsoft.com/en-us/azure/application-gateway/application-gateway-components) if you need to deep-dive on this model. 24 | 25 | During the infrastructure deployment, some of these components were already configured to expose `app1-vm` for the first scenario only. Let's review them! 26 | 27 | ## Task 2: Review Frontend IP configurations 28 | 29 | > Frontend IP configurations define the IP address used by Application Gateway to receive incoming HTTP(S) requests. 30 | > 31 | > Application Gateway can have at most one public ip and one private ip configured, no more. 32 | 33 | Navigate to AppGwPublic => Settings => Frontend IP configurations: 34 | 35 | ![image](docs/scenario1-frontendipconfigurations.png) 36 | 37 | At this scenario #1 step, **only the Public Frontend IP is configured**: 38 | * With the Public IP address 108.142.153.65 (AppGwPublic-pip) 39 | * The IP address will not be the same in your environment, adapt your tests. 40 | * With the listener Listener-Public-Http_app1 41 | 42 | ## Task 3: Review Listeners 43 | 44 | > Listeners listen for requests received on the Frontend IP they are associated with, on a specific port and protocol. There are [two types of listeners](https://learn.microsoft.com/en-us/azure/application-gateway/application-gateway-components#types-of-listeners): 45 | > * Basic listener: process all requests hitting the associated Frontend IP and matching their configured port and protocol 46 | > * Multi-site listeners: process all requests hitting the associated Frontend IP and matching their configured port and protocol and **hostname**. 47 | 48 | Navigate to AppGwPublic => Settings => Listeners: 49 | 50 | ![image](docs/scenario1-listeners-1.png) 51 | 52 | ![image](docs/scenario1-listeners-2.png) 53 | 54 | All requests hitting the FrontendIP Public on HTTP:80 will be routed by `RoutingRule_app1` routing rule. 55 | 56 | ## Task 4: Review Routing Rules 57 | 58 | > Routing Rules forward requests processed by a Listener to the backends or redirects them elsewhere. There are [two types of Routing Rules](https://learn.microsoft.com/en-us/azure/application-gateway/application-gateway-components#request-routing-rules): 59 | > * Basic: all requests are forwarded to the associated backend pool 60 | > * Path-based: route the requests to a specific backend pool based on the URL in the request 61 | 62 | > Routing Rules is associated to a "Backend setting", which defines how to connect to backend pool (port, protocol, ...) 63 | 64 | Navigate to AppGwPublic => Settings => Rules: 65 | 66 | ![image](docs/scenario1-routingrule-1.png) 67 | 68 | ![image](docs/scenario1-routingrule-2.png) 69 | 70 | ![image](docs/scenario1-routingrule-3.png) 71 | 72 | `RoutingRule_app1` forwards requests coming from `Listener-Public-Http_app1` to `BackendPool-app1` with `BackendSetting_HTTP_80` configuration. 73 | 74 | ## Task 5: Review Backend pools 75 | 76 | > Backend pool is a collection of resources to which your application gateway can send traffic. A backend pool can contain virtual machines, virtual machines scale sets, IP addresses, domain names, or an App Service. 77 | > 78 | > Round-robin load balancing method is used across all the backend servers 79 | 80 | Navigate to AppGwPublic => Settings => Backend pools: 81 | 82 | ![image](docs/scenario1-backendpools-1.png) 83 | 84 | ![image](docs/scenario1-backendpools-2.png) 85 | 86 | `BackendPool-app1` contains only one IP address: `10.1.0.4` which is IP address of `app1-vm` machine. 87 | 88 | ## Task 6: Review Backend settings 89 | 90 | > Backend settings define how to connect to backend pool instances to forward requests: Backend protocol, Backend port, Session-affinity, Connection draining, Custom probe, ... 91 | 92 | Navigate to AppGwPublic => Settings => Backend settings: 93 | 94 | ![image](docs/scenario1-backendsettings-1.png) 95 | 96 | ![image](docs/scenario1-backendsettings-2.png) 97 | 98 | ## Task 7: Check it works 99 | 100 | Navigate to http://AppGwPublic-pip. Replace `AppGwPublic-pip` by the value of the Public IP. 101 | 102 | Result: ✅ 103 | 104 | ![image](docs/scenario1-result.png) 105 | 106 | ## 🏁 Results 107 | 108 | You should now be more familiar with all of the concepts and components around Application Gateway. 109 | 110 | Let's now expose multiple websites with Scenario #2. 111 | 112 | 113 | ### [>> GO TO SCENARIO #2](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/2-scenario.md) 114 | 115 | 116 | -------------------------------------------------------------------------------- /2-scenario.md: -------------------------------------------------------------------------------- 1 | ### [<< BACK TO THE MAIN MENU](https://github.com/dawlysd/azure-application-gateway-microhack) 2 | 3 | # Scenario #2: Mutualize Application Gateway and expose multiple websites 4 | 5 | ## Overview 6 | 7 | Let's expose 3 different websites on Application Gateway 8 | 1) http://108.142.153.65/ will serve traffic to `hub-vm` website 9 | 2) http://app1-108.142.153.65.nip.io/ will serve traffic to `app1-vm` website 10 | 3) http://app2-108.142.153.65.nip.io/ will serve traffic to `app2-vm` website 11 | 12 | > [nip.io](https://nip.io/) is a service that maps `[.-].nip.io` in **"dot"**, **"dash"** or **"hexadecimal"** notation to the corresponding ****. 13 | 14 | Diagram: 15 | 16 | ![image](docs/scenario2-overview.png) 17 | 18 | ## Task 1: Create Backend pools 19 | 20 | Create below Backend pools: 21 | * `BackendPool-hub` with Backend target IP address of hub-vm `10.0.3.4` 22 | * `BackendPool-app2` with Backend target IP address of app2-vm `10.2.0.4` 23 | 24 | Keep `BackendPool-app1` created previously on scenario #1: 25 | 26 | ![image](docs/scenario2-backendpools.png) 27 | 28 | ## Task 2: Create Listeners 29 | 30 | **Update** `Listener-Public-Http_app1`: 31 | * Set "Listener type" to Multi site 32 | * Set "Host type" to Single 33 | * Set "Host name" to `app1-108.142.153.65.nip.io` 34 | 35 | ![image](docs/scenario2-listeners-app1.png) 36 | 37 | **Create** `Listener-Public-Http_app2`: 38 | * Set "Listener type" to Multi site 39 | * Set "Host type" to Single 40 | * Set "Host name" to `app2-108.142.153.65.nip.io` 41 | 42 | ![image](docs/scenario2-listeners-app2.png) 43 | 44 | **Create** `Listener-Public-Http_hub`: 45 | * Set "Listener type" to Basic 46 | 47 | ![image](docs/scenario2-listeners-hub.png) 48 | 49 | ## Task3: Create Routing Rules 50 | 51 | **Create** ``RoutingRule_app2``: 52 | * Priority: 101 53 | * Listener: `Listener-Public-Http_app2` 54 | * Backend targets 55 | * Target type: Backend pool 56 | * Backend target: `BackendPool-app2` 57 | * Backend settings: `BackendSetting_HTTP_80` 58 | 59 | **Create** ``RoutingRule_hub``: 60 | * Priority: 102 61 | * Listener: `Listener-Public-Http_hub` 62 | * Backend targets 63 | * Target type: Backend pool 64 | * Backend target: `BackendPool-hub` 65 | * Backend settings: `BackendSetting_HTTP_80` 66 | 67 | ## Task4: Check it works 68 | 69 | 1) Navigate to http://108.142.153.65/ 70 | 71 | Expected result: 72 | 73 | ![image](docs/scenario2-result-hub.png) 74 | 75 | 2) Navigate to http://app1-108.142.153.65.nip.io/ 76 | 77 | Expected result: 78 | 79 | ![image](docs/scenario2-result-app1.png) 80 | 81 | 3) Navigate to http://app2-108.142.153.65.nip.io/ 82 | 83 | Expected result: 84 | 85 | ![image](docs/scenario2-result-app2.png) 86 | 87 | ## Task 5: Multi site Listener & wildcard in hostname 88 | 89 | > Application Gateway allows host-based routing using [multi-site HTTP(S) listener](https://learn.microsoft.com/en-us/azure/application-gateway/multiple-site-overview#wildcard-host-names-in-listener) and wildcard characters like asterisk (*) and question mark (?) in the host name. 90 | 91 | **Create** `Listener-Public-Http_johndoe`: 92 | * Set "Listener type" to Multi site 93 | * Set "Host type" to Multiple/Wildcard 94 | * Set "Host name" to `johndoe*-108.142.153.65.nip.io` 95 | 96 | **Create** ``RoutingRule_johndoe``: 97 | * Priority: 103 98 | * Listener: `Listener-Public-Http_johndoe` 99 | * Backend targets 100 | * Target type: Backend pool 101 | * Backend target: `BackendPool-hub` 102 | * Backend settings: `BackendSetting_HTTP_80` 103 | 104 | **Check it works**: 105 | * Navigate to http://johndoehello-108.142.153.65.nip.io/ 106 | * Navigate to http://johndoe42-108.142.153.65.nip.io/ 107 | 108 | Expected result: 109 | 110 | ![image](docs/scenario2-result-johndoe.png) 111 | 112 | ## Task 6: (Monitoring) Review Application gateway Insights 113 | 114 | Navigate to Monitoring => Insights: 115 | 116 | ![image](docs/scenario2-insights.png) 117 | 118 | This page allows you to summarize the Application Gateway configuration in a graphical view and potentially see backends that would not be considered healthy. 119 | 120 | ## Task 7: (Monitoring) Review Backend health 121 | 122 | Navigate to Monitoring => Backend health 123 | 124 | ![image](docs/scenario2-monitoring.png) 125 | 126 | This page allows to have more detail on the state of the backends, even if the state is not "instantaneous". 127 | 128 | Note that it is possible to define [custom probes](https://learn.microsoft.com/en-us/azure/application-gateway/application-gateway-create-probe-portal) on Application Gateway. 129 | 130 | ## 🏁 Results 131 | 132 | You should now be more familial with the mutualization of Application Gateway. 133 | 134 | During this scenario, [redirection](https://learn.microsoft.com/en-us/azure/application-gateway/redirect-overview) feature has not been practiced. This feature is commonly used to redirect traffic from HTTP Listener to HTTPS Listener in Routing Rule. 135 | 136 | Let's now add some security and play with Web Application Firewall on Application Gateway with Scenario #3. 137 | 138 | ### [>> GO TO SCENARIO #3](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/3-scenario.md) 139 | -------------------------------------------------------------------------------- /3-scenario.md: -------------------------------------------------------------------------------- 1 | ### [<< BACK TO THE MAIN MENU](https://github.com/dawlysd/azure-application-gateway-microhack) 2 | 3 | # Scenario #3: Configure Web Application Firewall 4 | 5 | ## Introduction 6 | 7 | Web Application Firewall **helps protect your web applications from common threats** such as SQL injection, cross-site scripting, and other web exploits. You can define a WAF policy consisting of a combination of custom and managed rules to control access to your web applications. 8 | 9 | When a WAF policy is created, it must be associated to an application gateway to take effect. It can be associated with any combination of application gateways, listeners, and path-based rules. 10 | 11 | ## Overview 12 | 13 | Let's create one Waf Policy per Listener: 14 | 15 | ![image](docs/scenario3-overview.png) 16 | 17 | ## Task 1: Change Application Gateway tier 18 | 19 | During the infrastructure deployment with Terraform, Application Gateway was deployed with `Standard V2` tier. 20 | 21 | **Change** the tier to `WAF V2` and **Save**: 22 | 23 | ![image](docs/scenario3-change_tier.png) 24 | 25 | ## Task 2: Create WAF Policies 26 | 27 | To create WAF Policies, the easiest way is to go to Marketplace and search `Web Application Firewall`: 28 | 29 | ![image](docs/scenario3-marketplace.png) 30 | 31 | **Create** the first `AppGwPublic-WafPolicy_Default` Waf policy: 32 | 33 | ![image](docs/scenario3-wafpolicy-default.png) 34 | 35 | Keep "Managed rules", "Policy settings" and "Custom rules" with default proposed configuration. 36 | 37 | **Associate** this WAF policy to `Listener-Public-Http_hub` and `Listener-Public-Http_johndoe` listeners: 38 | 39 | ![image](docs/scenario3-wafpolicy-default2.png) 40 | 41 | **Skip** Tags and **Create** this first WAF policy. 42 | 43 | **Create** two others WAF policy: 44 | 1) `AppGw-WafPolicy-app1` 45 | * Policy mode: `Prevention` 46 | * Associated Listener: `Listener-Public-Http_app1` 47 | 2) `AppGw-WafPolicy-app2` 48 | * Policy mode: `Prevention` 49 | * Associated Listener: `Listener-Public-Http_app2` 50 | 51 | ## Task 3: Associate `AppGwPublic-WafPolicy_Default` to `AppGwPublic` Application Gateway 52 | 53 | **Navigate** to `AppGwPublic-WafPolicy_Default` WAF Policy and **display** Associated application gateways: 54 | 55 | ![image](docs/scenario3-wafpolicy-default3.png) 56 | 57 | This `AppGwPublic-WafPolicy_Default` WAF policy is associated to `Listener-Public-Http_hub` and `Listener-Public-Http_johndoe`. 58 | 59 | In addition, **associate** `AppGwPublic-WafPolicy_Default` WAF policy to `AppGwPublic` Application Gateway itself to make sure that future Listeners will also be protected: 60 | 61 | ![image](docs/scenario3-wafpolicy-default4.png) 62 | 63 | ![image](docs/scenario3-wafpolicy-default5.png) 64 | 65 | ## Task 4: Check it works 66 | 67 | 1) Navigate to [http://108.142.153.65.nip.io/?query=x"%20or%201%3D1%20--"](http://108.142.153.65.nip.io/?query=x"%20or%201%3D1%20--") 68 | 69 | Expected result: 70 | ![image](docs/scenario3-result-hub.png) 71 | 72 | `WafPolicy_Default` is not blocking us as it is configured in **Detection mode**. 73 | 74 | 2) Navigate to [http://app1-108.142.153.65.nip.io/?query=x"%20or%201%3D1%20--"](http://app1-108.142.153.65.nip.io/?query=x"%20or%201%3D1%20--") 75 | 76 | Expected result: 77 | ![image](docs/scenario3-result-app1.png) 78 | 79 | `AppGw-WafPolicy-app1` is blocking us as it is configured in **Prevention mode**. 80 | 81 | 3) Navigate to [http://app2-108.142.153.65.nip.io/?query=x"%20or%201%3D1%20--"](http://app2-108.142.153.65.nip.io/?query=x"%20or%201%3D1%20--") 82 | 83 | Expected result: 84 | ![image](docs/scenario3-result-app2.png) 85 | 86 | `AppGw-WafPolicy-app2` is blocking us as it is configured in **Prevention mode**. 87 | 88 | > **Note**: Custom error page [can be configured](https://learn.microsoft.com/en-us/azure/application-gateway/custom-error). 89 | 90 | ## Task 5: Monitor WAF 91 | 92 | [Enabling logging](https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/web-application-firewall-logs#enable-logging-through-the-azure-portal) for Application Gateway allows to query logs and displays when WAF matches a rule: 93 | 94 | ![image](docs/scenario3-monitoring.png) 95 | 96 | [Integration with Microsoft Sentinel](https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/best-practices#send-logs-to-microsoft-sentinel) (SIEM) is possible and recommended. 97 | 98 | [WAF Metrics](https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/application-gateway-waf-metrics#access-waf-metrics-in-azure-portal) are available by default in Azure portal. 99 | 100 | 101 | ## 🏁 Results 102 | 103 | You should now be more familial with [**Global WAF policy**](https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/policy-overview#global-waf-policy) and [**Per-site WAF policy**](https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/policy-overview#per-site-waf-policy). It is also possible to configure [Per-URI policy](https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/policy-overview#per-uri-policy). 104 | 105 | If you deploy Application Gateway in production, make sur you follow [best practices](https://learn.microsoft.com/en-us/azure/web-application-firewall/ag/best-practices). 106 | 107 | Let's now inspect network traffic between Application Gateway and VMs, with Azure Firewall. 108 | 109 | ### [>> GO TO SCENARIO #4](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/4-scenario.md) 110 | -------------------------------------------------------------------------------- /4-scenario.md: -------------------------------------------------------------------------------- 1 | ### [<< BACK TO THE MAIN MENU](https://github.com/dawlysd/azure-application-gateway-microhack) 2 | 3 | # Scenario #4: Inspect traffic with Azure Firewall 4 | 5 | ## Overview 6 | 7 | In this scenario, inbound web traffic goes through both Application Gateway (with WAF) Azure Firewall: 8 | 9 | ![image](docs/scenario4.gif) 10 | 11 | Advantages: 12 | * The WAF provides protection at web application layer 13 | * Azure Firewall acts a central logging and control point 14 | * Azure Firewall inspects traffic between the Application Gateway and the backend servers 15 | 16 | This scenario is deeply documented [here](https://learn.microsoft.com/en-us/azure/architecture/example-scenario/gateway/firewall-application-gateway#application-gateway-before-firewall). 17 | 18 | > Note: This is also possible to put [Azure Firewall in front of Application Gateway](https://learn.microsoft.com/en-us/azure/architecture/example-scenario/gateway/firewall-application-gateway#application-gateway-after-firewall). This scenario is not covered in this MicroHack. 19 | 20 | ## Task 1: Configure symmetric routing 21 | 22 | To inspect traffic between Application Gateway and backend servers, Route Tables with User Defined Routes must be configured: 23 | 24 | ![image](docs/scenario4-udr-overview.png) 25 | 26 | It is important to keep a symmetrical routing, otherwise traffic will be dropped. 27 | 28 | 1) **Create** and configure Route table `hub-snet-appgw-public-rt` in `hub-rg`: 29 | 30 | ![image](docs/scenario4-hub-snet-appgw-public-rt.png) 31 | 32 | This Route Table must be associated to `hub-vnet/snet-appgw-public` subnet. 33 | 34 | 2) **Create** and configure Route table `hub-snet-workload-rt` in `hub-rg`: 35 | 36 | ![image](docs/scenario4-hub-snet-workload-rt.png) 37 | 38 | This Route Table must be associated to `hub-vnet/snet-workload` subnet. 39 | 40 | 3) **Create** and configure Route table `app1-snet-workload-rt` in `app1-rg`: 41 | 42 | ![image](docs/scenario4-app1-snet-workload-rt.png) 43 | 44 | This Route Table must be associated to `app1-vnet/snet-workload` subnet. 45 | 46 | 4) **Create** and configure Route table `app2-snet-workload-rt` in `app2-rg`: 47 | 48 | ![image](docs/scenario4-app2-snet-workload-rt.png) 49 | 50 | This Route Table must be associated to `app2-vnet/snet-workload` subnet. 51 | 52 | -------- 53 | 54 | Symmetric routing for traffic between Application Gateway and backend servers is now configured. 55 | 56 | Let's continue with the Azure Firewall configuration 57 | 58 | ## Task 2: Check it doesn't work 59 | 60 | If you try to navigate to one of Public Listeners (http://108.142.153.65/ or http://app1-108.142.153.65.nip.io/ or http://app2-108.142.153.65.nip.io/), the following error appears: 61 | 62 | ![image](docs/scenario4-error.png) 63 | 64 | Navigate to Application Gateway => Monitoring => Backend health: 65 | 66 | ![image](docs/scenario4-backendhealth.png) 67 | 68 | We observe that even if traffic routing is symmetric, Application Gateway receives **`invalid status code: 470`**. 69 | 70 | Well, we need create rules, in Azure Firewall, to allow the traffic between Application Gateway and backend servers 😀. 71 | 72 | ## Task 3: Configure Azure Firewall 73 | 74 | 1) Navigate to `AzureFirewallPolicy` => Network rules. 75 | 76 | 2) **Create** below network rules: 77 | 78 | ![image](docs/scenario4-networkrules.png) 79 | 80 | ## Task 4: Check it works 81 | 82 | Try again to navigate to one of Public Listeners (http://108.142.153.65/ or http://app1-108.142.153.65.nip.io/ or http://app2-108.142.153.65.nip.io/), this is working again: 83 | 84 | ![image](docs/scenario2-result-app1.png) 85 | 86 | Application Gateway Backend health is healthy again also: 87 | 88 | ![image](docs/scenario2-monitoring.png) 89 | 90 | ## Task 5: Review Azure Firewall logs 91 | 92 | To observe traffic between Application Gateway and backend servers, navigate to Azure Firewall => Monitoring => Logs and execute below query : 93 | 94 | ![image](docs/scenario4-azurefirewalllogs.png) 95 | 96 | > Note: Logs may take a while sometimes to arrive. 97 | 98 | In the current configuration, Azure Firewall will inspect flows that the WAF has already allowed only. 99 | 100 | If you are using Azure Firewall Premium, we could enable [IDPS](https://learn.microsoft.com/en-us/azure/firewall/premium-features#idps) feature: it will verify that the HTTP Host header matches the destination IP 101 | 102 | ## 🏁 Results 103 | 104 | You should now be more familial with chaning Azure Application Gateway and Azure Firewall. 105 | 106 | The routing part is obvisouly the most tricky: we need to ensure that the traffic is symmetric. 107 | 108 | > **Important:** Default Route `0.0.0.0/0` cannot be used on [Application Gateway subnet](https://learn.microsoft.com/en-us/azure/application-gateway/configuration-infrastructure#supported-user-defined-routes). 109 | 110 | Let's now expose websites with HTTPS! 111 | 112 | ### [>> GO TO SCENARIO #5](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/5-scenario.md) -------------------------------------------------------------------------------- /5-scenario.md: -------------------------------------------------------------------------------- 1 | ### [<< BACK TO THE MAIN MENU](https://github.com/dawlysd/azure-application-gateway-microhack) 2 | 3 | # Scenario #5: Expose HTTPS websites using Let's Encrypt 4 | 5 | ## Overview 6 | 7 | Let's will expose `app2-vm` web application through Application Gateway by playing with Let's encrypt & HTTPS Listeners: 8 | 9 | ![image](docs/scenario5.gif) 10 | 11 | > Note: `app2` FQDN has changed from `app2-108.142.153.65.nip.io` to `app2-108.142.153.65.sslip.io`. 12 | > 13 | > [sslip.io](https://sslip.io/) provides the same service as [nip.io](https://nip.io/). 14 | > 15 | > I changed only because when I was writting this Microhack, I had the Let's encrypt error `too many certificates already issued for "nip.io"`. 16 | 17 | ## Introduction - Let's Encrypt 18 | 19 | To enable HTTPS on your website, you need to get a certificate (a type of file) from a Certificate Authority (CA). Let’s Encrypt is a CA. 20 | 21 | In order to get a certificate for your website’s domain from Let’s Encrypt, you have to demonstrate control over the domain. With Let’s Encrypt, you do this using software that uses the ACME protocol which typically runs on your web host. 22 | 23 | In this scenario, we'll install `certbot` CLI to manualy generate certificate and upload it to Application Gateway. 24 | 25 | ## Prerequisites: 26 | 27 | Two tools are required to generate Let's Encrypt certificates: 28 | 1) [Certbot](https://certbot.eff.org/): Certbot is a free, open source software tool for automatically using Let’s Encrypt certificates on manually-administrated websites to enable HTTPS. 29 | 2) [OpenSSL](https://www.openssl.org/): command line tool. OpenSSL is a robust, commercial-grade, and full-featured toolkit for the Transport Layer Security (TLS) and Secure Sockets Layer (SSL) protocols. It is also a general-purpose cryptography library. 30 | 31 | For Windows Users using Windows Terminal & Ubuntu shell: 32 | * **Install** Certbot: `sudo apt install certbot -y` 33 | * **Install** OpenSSL: `sudo apt install openssl -y` 34 | 35 | ## Task 1: Update `Listener-Public-Http_app2` listener 36 | 37 | **Update** `Listener-Public-Http_app2` to support old and new hostnames: 38 | 39 | ![image](docs/scenario5-app2-http_listener.png) 40 | 41 | 42 | ## Task 2: Generate certificate 43 | 44 | 1) Open Windows Terminal => Ubuntu machine 45 | 2) **Switch** to root user: `$ sudo su -` 46 | 3) **Request** certificate: `$ certbot certonly -d app2-108.142.153.65.sslip.io --manual` 47 | 48 | ![image](docs/scenario5-letsencrypt-1.png) 49 | 50 | 4) **Connect** to `app2-vm` through Serial Console. *Enable boot diagnostics with managed storage account if needed* 51 | 52 | ![image](docs/scenario5-app2-vm-1.png) 53 | 54 | 5) Through Serial Console, create requested file: 55 | 56 | ```bash 57 | # Become root 58 | $ sudo su - 59 | 60 | # Create required folders 61 | $ mkdir -p /var/www/html/.well-known/acme-challenge/ 62 | 63 | # Create challenge file 64 | $ echo "MJSPWS778d9pWLXeSWVFI1BHf5TJzuyVJurQ7EFIFRk.qcBdGrwO-x8t4XtJX89Ga3x5RN7rWqrD3qnJGfpInho" > /var/www/html/.well-known/acme-challenge/MJSPWS778d9pWLXeSWVFI1BHf5TJzuyVJurQ7EFIFRk 65 | ``` 66 | 67 | 6) Come back to Windows Terminal and **Press** Enter: 68 | 69 | ![image](docs/scenario5-letsencrypt-2.png) 70 | 71 | The certificate is now generated and stored in `/etc/letsencrypt/live/app2-108.142.153.65.sslip.io/` folder. 72 | 73 | 7) Convert certificate to .pfx 74 | 75 | **.pfx** certificate format is required by Application Gateway. Let's generate it: 76 | 77 | ```bash 78 | $ cd /etc/letsencrypt/live/app2-108.142.153.65.sslip.io/ 79 | 80 | $ openssl pkcs12 -export -out app2-108.142.153.65.sslip.io.pfx -inkey privkey.pem -in fullchain.pem 81 | Enter Export Password: 82 | Verifying - Enter Export Password: 83 | ``` 84 | > **Important**: do not put an empty password! This is not supported later by Application Gateway 85 | 86 | ![image](docs/scenario5-letsencrypt-3.png) 87 | 88 | **Copy** `app2-108.142.153.65.sslip.io.pfx` certicate to your Desktop: `cp app2-108.142.153.65.sslip.io.pfx /mnt/c/Users/dasantiago/Desktop/`. **Replace `dasantiago` by your username.** 89 | 90 | ## Task 3: Create HTTPS Listener 91 | 92 | Create `Listener-Public-Https-app2` listener: 93 | 94 | ![image](docs/scenario5-app2-listener.png) 95 | 96 | ## Task 4: Create new Routing Rule 97 | 98 | Create `RoutingRule_app2_https` routing rule: 99 | * Priority: 104 100 | * Listener: `Listener-Public-Https-app2` 101 | * Backend targets 102 | * Target type: `Backend pool` 103 | * Backend target: `BackendPool-app2` 104 | * Backend settings: `BackendSetting_HTTP_80` 105 | 106 | ## Task 5: Check it works! 107 | 108 | * Navigate to https://app2-108.142.153.65.sslip.io/ 109 | 110 | Expected result: 111 | 112 | ![image](docs/scenario5-result.png) 113 | 114 | ## Task 6: Configure HTTP redicection to HTTPs 115 | 116 | **Update** `RoutingRule_app2` routing rule to Redirect to HTTPS listener: 117 | 118 | ![image](docs/scenario5-app2-redirecthttptohttps.png) 119 | 120 | **Navigate** to http://app2-108.142.153.65.sslip.io/, you should be automatically redirect to https://app2-108.142.153.65.sslip.io/ 😀 121 | 122 | ## 🏁 Results 123 | 124 | You should now be more familial with HTTPS Listeners. 125 | 126 | The most complicated part here was to generate the certificates by hand with certbot to upload them to Application Gateway with these weird FQDNs. 127 | 128 | In real life, certificates are either: 129 | * [uploaded manually in a KeyVault](https://learn.microsoft.com/en-us/azure/key-vault/certificates/tutorial-import-certificate?tabs=azure-portal). The Gateway application will look for the certificates in KeyVault 130 | * or [generated by the Keyvault](https://learn.microsoft.com/en-us/azure/key-vault/certificates/how-to-integrate-certificate-authority) with DigiCert or GlobalSign. 131 | 132 | Some alternatives exist: rely on Let's Encrypt and [automate SSL renewal on Application Gateway](https://intelequia.com/blog/post/1012/automating-azure-application-gateway-ssl-certificate-renewals-with-let-s-encrypt-and-azure-automation). 133 | 134 | 135 | Let's now use HTTPS backend servers! 136 | 137 | 138 | ### [>> GO TO SCENARIO #6](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/6-scenario.md) -------------------------------------------------------------------------------- /6-scenario.md: -------------------------------------------------------------------------------- 1 | ### [<< BACK TO THE MAIN MENU](https://github.com/dawlysd/azure-application-gateway-microhack) 2 | 3 | # Scenario #6: Support HTTPS backend servers 4 | 5 | ## Introduction 6 | 7 | Until now, the communication between Application Gateway and backend servers was uncrypted. 8 | 9 | Even if it has [several advantages](https://learn.microsoft.com/en-us/azure/application-gateway/ssl-overview#tls-termination), there may be security requirements imposing the [end-to-end TLS encryption](https://learn.microsoft.com/en-us/azure/application-gateway/ssl-overview#end-to-end-tls-encryption): 10 | 11 | ![image](docs/scenario6-endtoend.png) 12 | 13 | 14 | 15 | ## Overview 16 | 17 | To keep this scenario independent of [Scenario #5](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/5-scenario.md), Test User will access to app2-vm webapp through **HTTP**: http://app1-108.142.153.65.nip.io. 18 | 19 | ![image](docs/scenario6-overview.png) 20 | 21 | Let's configure: 22 | - `app1-vm` to expose its website in HTTPs with a self-signed certificate 23 | - Application Gateway Backend settings to take into account the new configuration of app1-vm. 24 | 25 | This scenario use a self-signed certificate to review required steps in the context where backend servers would have private PKI signed certificates that need to be accessible from Application Gateway. 26 | 27 | > If the backend certificates are issued by a well known CA, task 1 is useless, go directly to [Task2](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/6-scenario.md#task-2-create-backendsetting_https_443_app1) and check "Use well known CA certificate". 28 | 29 | ## Task 1: Generate self-signed certificate on `app1-vm` 30 | 31 | **Connect** to `app1-vm` through Serial Console. *Enable boot diagnostics with managed storage account if needed* 32 | 33 | * Enable `mod_ssl` 34 | 35 | ```bash 36 | # Become root 37 | sudo su - 38 | 39 | # Update packages 40 | apt update -y && apt upgrade -y 41 | 42 | # Enable Apache mod_ssl 43 | a2enmod ssl 44 | # Restart apache2 45 | systemctl restart apache2 46 | ``` 47 | 48 | * Create the SSL Certificate 49 | 50 | ```bash 51 | openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/ssl/private/apache-selfsigned.key -out /etc/ssl/certs/apache-selfsigned.crt 52 | ``` 53 | 54 | ![image](docs/scenario6-generate_ssl.png) 55 | 56 | * Configure Apache to Use SSL 57 | 58 | ```bash 59 | cd /etc/apache2/sites-available/ 60 | vi 10.1.0.4.conf 61 | ``` 62 | 63 | **Paste** below configuration: 64 | ``` 65 | 66 | ServerName 10.1.0.4 67 | DocumentRoot /var/www/html/ 68 | 69 | SSLEngine on 70 | SSLCertificateFile /etc/ssl/certs/apache-selfsigned.crt 71 | SSLCertificateKeyFile /etc/ssl/private/apache-selfsigned.key 72 | 73 | ``` 74 | 75 | **Save** and **close** the file. 76 | 77 | **Enable** the configuration: 78 | ```bash 79 | a2ensite 10.1.0.4.conf 80 | ``` 81 | 82 | ![image](docs/scenario6-a2ensite.png) 83 | 84 | **Check** apache2 configuration: 85 | ```bash 86 | apache2ctl configtest 87 | ``` 88 | 89 | **Reload** apache2: 90 | ```bash 91 | systemctl reload apache2 92 | ``` 93 | 94 | **Check** apache2 is listening & working on HTTPs: 95 | ```bash 96 | # Normal curl 97 | curl https://10.1.0.4 98 | curl: (60) SSL certificate problem: self-signed certificate 99 | More details here: https://curl.se/docs/sslcerts.html 100 | 101 | curl failed to verify the legitimacy of the server and therefore could not 102 | establish a secure connection to it. To learn more about this situation and 103 | how to fix it, please visit the web page mentioned above. 104 | 105 | # curl with insecure 106 | curl -k https://10.1.0.4 107 | app1-vm 108 | ``` 109 | 110 | The first curl fails and it is normal: given certificate is self-signed (not issued by a well known CA). 111 | 112 | **Download** `/etc/ssl/certs/apache-selfsigned.crt` in your workstation and rename it to `apache-selfsigned.crt`. This certificate will need to be given to Application Gateway. 113 | 114 | ## Task 2: Create `BackendSetting_HTTPS_443_app1` 115 | 116 | In this new Backend Settings dedicated to app1, it is required to upload `apache-selfsigned.cer` downloaded previously : 117 | 118 | ![image](docs/scenario6-BackendSetting_HTTPS_443_app1.png) 119 | 120 | **Important**: Host name must be overrided because Application Gateway need to "Pick host name from backend target" (aka private IP on which certificate was issued). Health probing will fail otherwise. 121 | 122 | **Note**: In this MicroHack, we pick host name from backend target is a **bad practice**. Recommendation is to [Preserve the original HTTP host name between a reverse proxy and its back-end web application](https://learn.microsoft.com/en-us/azure/architecture/best-practices/host-name-preservation). 123 | 124 | ## Task 3: Update `RoutingRule_app1` 125 | 126 | **Change** Backend settings to `BackendSetting_HTTPS_443_app1`: 127 | 128 | ![image](docs/scenario6-RoutingRule_app1.png) 129 | 130 | ## Task 4: Check it works! 131 | 132 | Navigate to http://app1-108.142.153.65.nip.io/ 133 | 134 | Expected result: 135 | 136 | ![image](docs/scenario2-result-app1.png) 137 | 138 | ## 🏁 Results 139 | 140 | You should now be more familiar with usage of backend servers with self-signed certificates. 141 | 142 | In a corporate context, **it would have been necessary to import an intermediate or root certificate to Application Gateway** to avoid importing per-application certificates. 143 | 144 | By combining this scenario with Scenario #4, it is possible to achieve End-to-end TLS. 145 | 146 | 147 | ### [>> GO TO SCENARIO #7](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/7-scenario.md) 148 | -------------------------------------------------------------------------------- /7-scenario.md: -------------------------------------------------------------------------------- 1 | ### [<< BACK TO THE MAIN MENU](https://github.com/dawlysd/azure-application-gateway-microhack) 2 | 3 | # Scenario #7: Expose App service through Application Gateway 4 | 5 | ## Overview 6 | 7 | Let's create a public App Service, and restrict its access through Application Gateway: 8 | ![image](docs/scenario7-overview.png) 9 | 10 | ## Task 1: Create App Service 11 | 12 | - Login to Azure Cloud shell [https://shell.azure.com/](https://shell.azure.com/) 13 | - Execute below commands 14 | 15 | ```bash 16 | # Variable block 17 | let "randomIdentifier=$RANDOM*$RANDOM" 18 | resourceGroup="appservice-rg" 19 | location="westeurope" 20 | appServicePlan="appsp-$randomIdentifier" 21 | webapp="webapp-$randomIdentifier" 22 | 23 | # Create a resource group. 24 | echo "Creating $resourceGroup in "$location"..." 25 | az group create --name $resourceGroup --location $location 26 | 27 | # Create an App Service plan in `FREE` tier. 28 | echo "Creating $appServicePlan" 29 | az appservice plan create --name $appServicePlan --resource-group $resourceGroup --sku FREE 30 | 31 | # Create a web app. 32 | echo "Creating $webapp" 33 | az webapp create --name $webapp --resource-group $resourceGroup --plan $appServicePlan 34 | 35 | ## Display URL 36 | echo "Web App URL: https://webapp-$randomIdentifier.azurewebsites.net" 37 | ``` 38 | 39 | Navigate to WebApp URL: 40 | 41 | ![image](docs/scenario7-webapp.png) 42 | 43 | Let's keep this default web page and expose it through Application Gateway 44 | 45 | ## Task 2: Create `BackendPool-appservice` 46 | 47 | **Create** Backend pool`BackendPool-appservice` with Backend Target FQDN of appservice `webapp-629489100.azurewebsites.net` 48 | 49 | > It is possible to use "Target type" `App Services` if the App Service is deployed in the same subscription than Application Gateway. 50 | 51 | ![image](docs/scenario7-BackendPool-appservice.png) 52 | 53 | ## Task 3: Create App Service Listener in AppGw 54 | 55 | **Create** `Listener-Public-Http_appservice`: 56 | * Set "Listener type" to Multi site 57 | * Set "Host type" to Single 58 | * Set "Host name" to `appservice-108.142.153.65.nip.io` 59 | 60 | ![image](docs/scenario7-Listener-Public-Http_appservice.png) 61 | 62 | ## Task 3: Create `BackendSetting_HTTP_443` 63 | 64 | **Create** `BackendSetting_HTTP_443_appservice`: 65 | * Backend protocol: `HTTPS` 66 | * Backend port: `443` 67 | * Use well known CA certificate: `Yes` 68 | * Override with new host name: `Yes` 69 | * Host name override: `Pick host name from backend target` 70 | 71 | ![image](docs/scenario7-Listener-Public-Http_appservice.png) 72 | 73 | **Note**: In this MicroHack, we pick host name from backend target is a **bad practice**. Recommendation is to [Preserve the original HTTP host name between a reverse proxy and its back-end web application](https://learn.microsoft.com/en-us/azure/architecture/best-practices/host-name-preservation). 74 | 75 | ## Task 4: Create App Service Routing Rule in AppGw 76 | 77 | **Create** ``RoutingRule_appservice``: 78 | * Priority: 106 79 | * Listener: `Listener-Public-Http_appservice` 80 | * Backend targets 81 | * Target type: Backend pool 82 | * Backend target: `BackendPool-appservice` 83 | * Backend settings: `BackendSetting_HTTP_443_appservice` 84 | 85 | ![image](docs/scenario7-RoutingRule_appservice1.png) 86 | 87 | ![image](docs/scenario7-RoutingRule_appservice2.png) 88 | 89 | ## Task 5: Check it works! 90 | 91 | * Navigate to http://appservice-108.142.153.65.nip.io 92 | 93 | Expected result: 94 | ![image](docs/scenario7-appservice-108.142.153.65.nip.io.png) 95 | 96 | * Navigate to https://webapp-629489100.azurewebsites.net/ 97 | 98 | Expected result: 99 | ![image](docs/scenario7-webapp.png) 100 | 101 | Let's restrict access to App Service from Application Gateway only! 102 | 103 | ## Task 6: Restrict access to App Service from Application Gateway only 104 | 105 | In `appservice-rg`, go to Web App => Networking => Access restriction: 106 | 107 | ![image](docs/scenario7-webapp-accessrestriction1.png) 108 | 109 | **Configure** Access Restriction to: 110 | * Allow public access traffic 111 | * Deny traffic for unmatched rule 112 | 113 | **Create** an `Allow_AppGw_Only` rule to allow traffic coming from Application Gateway Subnet: 114 | 115 | ![image](docs/scenario7-webapp-accessrestriction2.png) 116 | 117 | **Save**: 118 | 119 | ![image](docs/scenario7-webapp-accessrestriction3.png) 120 | 121 | 122 | ## Task 7: Check it works! 123 | 124 | * Navigate to http://appservice-108.142.153.65.nip.io 125 | 126 | Expected result: 127 | ![image](docs/scenario7-appservice-108.142.153.65.nip.io.png) 128 | 129 | * Navigate to https://webapp-629489100.azurewebsites.net/ 130 | 131 | Expected result: 132 | ![image](docs/scenario7-webapp-forbidden.png) 133 | 134 | ## 🏁 Results 135 | 136 | You should now be more familiar with usage of Application Gateway & Azure App Service. 137 | 138 | Do not hesitate to review best practice around [Preserving the original HTTP host name between a reverse proxy and its back-end web application](https://learn.microsoft.com/en-us/azure/architecture/best-practices/host-name-preservation) 139 | 140 | ### [<< BACK TO THE MAIN MENU](https://github.com/dawlysd/azure-application-gateway-microhack) -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Azure Application Gateway - MicroHack 2 | 3 | # Introduction 4 | 5 | [Azure Application Gateway](https://learn.microsoft.com/en-us/azure/application-gateway/overview) is a managed regional reverse proxy with optional WAF (Web Application Firewall) capability used to expose web applications: 6 | 7 | ![image](docs/appgw-1.png) 8 | 9 | The intent of this MicroHack is to play with several [Application Gateway features](https://learn.microsoft.com/en-us/azure/application-gateway/features) through different scenarios. 10 | 11 | # Scenarios 12 | 13 | All scenarios except #1 and #2 can be done independently. 14 | 15 | - [Prerequisites](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/0-prerequisites.md) 16 | 17 | - [Scenario #1: Expose app1-vm website on to the Internet](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/1-scenario.md) 18 | 19 | - [Scenario #2: Mutualize Application Gateway and expose multiple websites](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/2-scenario.md) 20 | 21 | - [Scenario #3: Configure Web Application Firewall](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/3-scenario.md) 22 | 23 | - [Scenario #4: Inspect traffic with Azure Firewall](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/4-scenario.md) 24 | 25 | - [Scenario #5: Expose HTTPS websites using Let's Encrypt](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/5-scenario.md) 26 | 27 | - [Scenario #6: Support HTTPS backend servers](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/6-scenario.md) 28 | 29 | - [Scenario #7: Expose App service through Application Gateway](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/7-scenario.md) 30 | 31 | # Appendix 32 | 33 | - [Azure Application Gateway - MicroHack](#azure-application-gateway---microhack) 34 | - [Introduction](#introduction) 35 | - [Scenarios](#scenarios) 36 | - [Appendix](#appendix) 37 | - [How to manage the same port for both public-facing and private facing listener limitation](#how-to-manage-the-same-port-for-both-public-facing-and-private-facing-listener-limitation) 38 | - [Where to deploy Application Gateway in a Hub \& Spoke topology](#where-to-deploy-application-gateway-in-a-hub--spoke-topology) 39 | - [How to calculate the number of Application Gateway instances](#how-to-calculate-the-number-of-application-gateway-instances) 40 | - [Azure Application Gateway vs Azure Front Door](#azure-application-gateway-vs-azure-front-door) 41 | 42 | ## How to manage the same port for both public-facing and private facing listener limitation 43 | 44 | Application Gateway [cannot use the same port for both public & private listeners](https://learn.microsoft.com/en-us/azure/application-gateway/application-gateway-faq#can-i-use-the-same-port-for-both-public-facing-and-private-facing-listeners). 45 | 46 | To address this limitation, it is common for organizations to deploy at least 2 Application Gateways: **one to carry public site exposure**, and **another to carry private site exposure**. 47 | 48 | It is then the [limits](https://learn.microsoft.com/en-us/azure/azure-resource-manager/management/azure-subscription-service-limits#application-gateway-limits) (listeners, SSL certificates ...) that derive the number of Application Gateway that are deployed. 49 | 50 | ## Where to deploy Application Gateway in a Hub & Spoke topology 51 | 52 | As seen during this MicroHack, Application Gateway is a component that **can be massively mutualized**, which optimizes costs. 53 | 54 | Historically, Application Gateways were deployed in the Hub as infrastructure elements. This can lead to limitations if new Application Gateways are to be deployed because IP availabilies in hub-vnet: [recommended application gateway subnet size is /24](https://learn.microsoft.com/en-us/azure/application-gateway/configuration-infrastructure#size-of-the-subnet). 55 | 56 | If a routing NVA is available in the hub (Azure Firewall, 3rd party FW), it is quite conceivable to deploy Application Gateways in spokes VNets as soon as you are comfortable with UDRs (as seen in [scenario #4](https://github.com/dawlysd/azure-application-gateway-microhack/blob/main/4-scenario.md)), to keep the symmetry of the routing. 57 | 58 | ## How to calculate the number of Application Gateway instances 59 | 60 | My colleague [Cynthia Treger](https://github.com/cynthiatreger) published a [Scaling guide with Azure Application Gateway v2](https://github.com/cynthiatreger/scaling-app-gw-v2). 61 | 62 | Based on this guide, we can produce this AppGw capabilities table: 63 | 64 | ![image](docs/appendix-appgwcapability.png) 65 | 66 | **Note**: Pricing columns (generated on february 2023, east US region, 5GB Outbound Data Transfer baseline) may not be relevant when auto scaling feature is enabled. 67 | 68 | ## Azure Application Gateway vs Azure Front Door 69 | 70 | There are several components that can be placed in front of a (web) application: 71 | ![image](docs/appendix-appgwvsfrontdoor1.png) 72 | [Source](https://kvaes.wordpress.com/2020/04/13/azure-what-do-i-put-in-front-of-my-web-application/) 73 | 74 | [Azure Architecture Center](https://learn.microsoft.com/en-us/azure/architecture/guide/technology-choices/load-balancing-overview#decision-tree-for-load-balancing-in-azure) provides an interesting decision tree: 75 | ![image](https://learn.microsoft.com/en-us/azure/architecture/guide/technology-choices/images/load-balancing-decision-tree.png) 76 | -------------------------------------------------------------------------------- /docs/appendix-appgwcapability.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/appendix-appgwcapability.png -------------------------------------------------------------------------------- /docs/appendix-appgwvsfrontdoor1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/appendix-appgwvsfrontdoor1.png -------------------------------------------------------------------------------- /docs/appgw-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/appgw-1.png -------------------------------------------------------------------------------- /docs/appgw-model.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/appgw-model.png -------------------------------------------------------------------------------- /docs/basic_infrastructure.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/basic_infrastructure.png -------------------------------------------------------------------------------- /docs/scenario1-backendpools-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario1-backendpools-1.png -------------------------------------------------------------------------------- /docs/scenario1-backendpools-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario1-backendpools-2.png -------------------------------------------------------------------------------- /docs/scenario1-backendsettings-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario1-backendsettings-1.png -------------------------------------------------------------------------------- /docs/scenario1-backendsettings-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario1-backendsettings-2.png -------------------------------------------------------------------------------- /docs/scenario1-frontendipconfigurations.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario1-frontendipconfigurations.png -------------------------------------------------------------------------------- /docs/scenario1-listeners-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario1-listeners-1.png -------------------------------------------------------------------------------- /docs/scenario1-listeners-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario1-listeners-2.png -------------------------------------------------------------------------------- /docs/scenario1-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario1-result.png -------------------------------------------------------------------------------- /docs/scenario1-routingrule-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario1-routingrule-1.png -------------------------------------------------------------------------------- /docs/scenario1-routingrule-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario1-routingrule-2.png -------------------------------------------------------------------------------- /docs/scenario1-routingrule-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario1-routingrule-3.png -------------------------------------------------------------------------------- /docs/scenario1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario1.gif -------------------------------------------------------------------------------- /docs/scenario2-backendpools.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario2-backendpools.png -------------------------------------------------------------------------------- /docs/scenario2-insights.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario2-insights.png -------------------------------------------------------------------------------- /docs/scenario2-listeners-app1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario2-listeners-app1.png -------------------------------------------------------------------------------- /docs/scenario2-listeners-app2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario2-listeners-app2.png -------------------------------------------------------------------------------- /docs/scenario2-listeners-hub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario2-listeners-hub.png -------------------------------------------------------------------------------- /docs/scenario2-monitoring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario2-monitoring.png -------------------------------------------------------------------------------- /docs/scenario2-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario2-overview.png -------------------------------------------------------------------------------- /docs/scenario2-result-app1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario2-result-app1.png -------------------------------------------------------------------------------- /docs/scenario2-result-app2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario2-result-app2.png -------------------------------------------------------------------------------- /docs/scenario2-result-hub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario2-result-hub.png -------------------------------------------------------------------------------- /docs/scenario2-result-johndoe.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario2-result-johndoe.png -------------------------------------------------------------------------------- /docs/scenario3-change_tier.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario3-change_tier.png -------------------------------------------------------------------------------- /docs/scenario3-marketplace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario3-marketplace.png -------------------------------------------------------------------------------- /docs/scenario3-monitoring.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario3-monitoring.png -------------------------------------------------------------------------------- /docs/scenario3-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario3-overview.png -------------------------------------------------------------------------------- /docs/scenario3-result-app1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario3-result-app1.png -------------------------------------------------------------------------------- /docs/scenario3-result-app2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario3-result-app2.png -------------------------------------------------------------------------------- /docs/scenario3-result-hub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario3-result-hub.png -------------------------------------------------------------------------------- /docs/scenario3-wafpolicy-default.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario3-wafpolicy-default.png -------------------------------------------------------------------------------- /docs/scenario3-wafpolicy-default2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario3-wafpolicy-default2.png -------------------------------------------------------------------------------- /docs/scenario3-wafpolicy-default3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario3-wafpolicy-default3.png -------------------------------------------------------------------------------- /docs/scenario3-wafpolicy-default4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario3-wafpolicy-default4.png -------------------------------------------------------------------------------- /docs/scenario3-wafpolicy-default5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario3-wafpolicy-default5.png -------------------------------------------------------------------------------- /docs/scenario4-app1-snet-workload-rt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario4-app1-snet-workload-rt.png -------------------------------------------------------------------------------- /docs/scenario4-app2-snet-workload-rt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario4-app2-snet-workload-rt.png -------------------------------------------------------------------------------- /docs/scenario4-azurefirewalllogs.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario4-azurefirewalllogs.png -------------------------------------------------------------------------------- /docs/scenario4-backendhealth.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario4-backendhealth.png -------------------------------------------------------------------------------- /docs/scenario4-error.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario4-error.png -------------------------------------------------------------------------------- /docs/scenario4-hub-snet-appgw-public-rt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario4-hub-snet-appgw-public-rt.png -------------------------------------------------------------------------------- /docs/scenario4-hub-snet-workload-rt.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario4-hub-snet-workload-rt.png -------------------------------------------------------------------------------- /docs/scenario4-networkrules.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario4-networkrules.png -------------------------------------------------------------------------------- /docs/scenario4-udr-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario4-udr-overview.png -------------------------------------------------------------------------------- /docs/scenario4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario4.gif -------------------------------------------------------------------------------- /docs/scenario5-app2-http_listener.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario5-app2-http_listener.png -------------------------------------------------------------------------------- /docs/scenario5-app2-listener.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario5-app2-listener.png -------------------------------------------------------------------------------- /docs/scenario5-app2-redirecthttptohttps.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario5-app2-redirecthttptohttps.png -------------------------------------------------------------------------------- /docs/scenario5-app2-vm-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario5-app2-vm-1.png -------------------------------------------------------------------------------- /docs/scenario5-letsencrypt-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario5-letsencrypt-1.png -------------------------------------------------------------------------------- /docs/scenario5-letsencrypt-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario5-letsencrypt-2.png -------------------------------------------------------------------------------- /docs/scenario5-letsencrypt-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario5-letsencrypt-3.png -------------------------------------------------------------------------------- /docs/scenario5-result.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario5-result.png -------------------------------------------------------------------------------- /docs/scenario5.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario5.gif -------------------------------------------------------------------------------- /docs/scenario6-BackendSetting_HTTPS_443_app1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario6-BackendSetting_HTTPS_443_app1.png -------------------------------------------------------------------------------- /docs/scenario6-RoutingRule_app1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario6-RoutingRule_app1.png -------------------------------------------------------------------------------- /docs/scenario6-a2ensite.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario6-a2ensite.png -------------------------------------------------------------------------------- /docs/scenario6-endtoend.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario6-endtoend.png -------------------------------------------------------------------------------- /docs/scenario6-generate_ssl.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario6-generate_ssl.png -------------------------------------------------------------------------------- /docs/scenario6-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario6-overview.png -------------------------------------------------------------------------------- /docs/scenario7-BackendPool-appservice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario7-BackendPool-appservice.png -------------------------------------------------------------------------------- /docs/scenario7-BackendSetting_HTTP_443_appservice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario7-BackendSetting_HTTP_443_appservice.png -------------------------------------------------------------------------------- /docs/scenario7-Listener-Public-Http_appservice.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario7-Listener-Public-Http_appservice.png -------------------------------------------------------------------------------- /docs/scenario7-RoutingRule_appservice1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario7-RoutingRule_appservice1.png -------------------------------------------------------------------------------- /docs/scenario7-RoutingRule_appservice2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario7-RoutingRule_appservice2.png -------------------------------------------------------------------------------- /docs/scenario7-appservice-108.142.153.65.nip.io.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario7-appservice-108.142.153.65.nip.io.png -------------------------------------------------------------------------------- /docs/scenario7-overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario7-overview.png -------------------------------------------------------------------------------- /docs/scenario7-webapp-accessrestriction1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario7-webapp-accessrestriction1.png -------------------------------------------------------------------------------- /docs/scenario7-webapp-accessrestriction2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario7-webapp-accessrestriction2.png -------------------------------------------------------------------------------- /docs/scenario7-webapp-accessrestriction3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario7-webapp-accessrestriction3.png -------------------------------------------------------------------------------- /docs/scenario7-webapp-forbidden.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario7-webapp-forbidden.png -------------------------------------------------------------------------------- /docs/scenario7-webapp.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/davidsntg/azure-application-gateway-microhack/0f25e432aa1454c3cf8574a33067599ccaa868b8/docs/scenario7-webapp.png -------------------------------------------------------------------------------- /templates/.gitignore: -------------------------------------------------------------------------------- 1 | 2 | # Created by https://www.toptal.com/developers/gitignore/api/terraform 3 | # Edit at https://www.toptal.com/developers/gitignore?templates=terraform 4 | 5 | ### Terraform ### 6 | # Local .terraform directories 7 | **/.terraform/* 8 | 9 | # .tfstate files 10 | *.tfstate 11 | *.tfstate.* 12 | 13 | # Crash log files 14 | crash.log 15 | crash.*.log 16 | 17 | # Exclude all .tfvars files, which are likely to contain sensitive data, such as 18 | # password, private keys, and other secrets. These should not be part of version 19 | # control as they are data points which are potentially sensitive and subject 20 | # to change depending on the environment. 21 | *.tfvars 22 | *.tfvars.json 23 | 24 | # Ignore override files as they are usually used to override resources locally and so 25 | # are not checked in 26 | override.tf 27 | override.tf.json 28 | *_override.tf 29 | *_override.tf.json 30 | 31 | # Include override files you do wish to add to version control using negated pattern 32 | # !example_override.tf 33 | 34 | # Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan 35 | # example: *tfplan* 36 | 37 | # Ignore CLI configuration files 38 | .terraformrc 39 | terraform.rc 40 | 41 | .terraform.lock.hcl 42 | # End of https://www.toptal.com/developers/gitignore/api/terraform -------------------------------------------------------------------------------- /templates/appgw-public.tf: -------------------------------------------------------------------------------- 1 | resource "azurerm_public_ip" "hub-appgwpublic-pip" { 2 | name = "AppGwPublic-pip" 3 | resource_group_name = azurerm_resource_group.hub-rg.name 4 | location = azurerm_resource_group.hub-rg.location 5 | allocation_method = "Static" 6 | sku = "Standard" 7 | } 8 | 9 | resource "azurerm_application_gateway" "hub-appgwpublic" { 10 | name = "AppGwPublic" 11 | resource_group_name = azurerm_resource_group.hub-rg.name 12 | location = azurerm_resource_group.hub-rg.location 13 | 14 | sku { 15 | name = "Standard_v2" 16 | tier = "Standard_v2" 17 | capacity = 2 18 | } 19 | 20 | gateway_ip_configuration { 21 | name = "hub-appgw-public-subnet" 22 | subnet_id = azurerm_subnet.hub-appgw_public-subnet.id 23 | } 24 | 25 | frontend_port { 26 | name = "FrontEndPort_80" 27 | port = 80 28 | } 29 | 30 | frontend_port { 31 | name = "FrontEndPort_443" 32 | port = 443 33 | } 34 | 35 | frontend_ip_configuration { 36 | name = "AppGw-FrontEnd-Public" 37 | public_ip_address_id = azurerm_public_ip.hub-appgwpublic-pip.id 38 | } 39 | 40 | backend_address_pool { 41 | name = "BackendPool-app1" 42 | ip_addresses = [azurerm_network_interface.app1-vm-nic.private_ip_address] 43 | } 44 | 45 | backend_address_pool { 46 | name = "BackendPool-app2" 47 | ip_addresses = [azurerm_network_interface.app2-vm-nic.private_ip_address] 48 | } 49 | 50 | backend_http_settings { 51 | name = "BackendSetting_HTTP_80" 52 | cookie_based_affinity = "Disabled" 53 | //path = "/" 54 | port = 80 55 | protocol = "Http" 56 | request_timeout = 20 57 | pick_host_name_from_backend_address = true 58 | } 59 | 60 | http_listener { 61 | name = "Listener-Public-Http_app1" 62 | frontend_ip_configuration_name = "AppGw-FrontEnd-Public" 63 | frontend_port_name = "FrontEndPort_80" 64 | protocol = "Http" 65 | } 66 | 67 | request_routing_rule { 68 | priority = 100 69 | name = "RoutingRule_app1" 70 | rule_type = "Basic" 71 | http_listener_name = "Listener-Public-Http_app1" 72 | backend_address_pool_name = "BackendPool-app1" 73 | backend_http_settings_name = "BackendSetting_HTTP_80" 74 | } 75 | } 76 | 77 | resource "azurerm_monitor_diagnostic_setting" "azure_applicationgateway_monitor" { 78 | name = "AzureApplicationGatewayMonitorLogs" 79 | target_resource_id = azurerm_application_gateway.hub-appgwpublic.id 80 | log_analytics_workspace_id = azurerm_log_analytics_workspace.azure_firewall_law.id 81 | 82 | enabled_log { 83 | category = "ApplicationGatewayFirewallLog" 84 | 85 | retention_policy { 86 | enabled = false 87 | } 88 | } 89 | 90 | enabled_log { 91 | category = "ApplicationGatewayAccessLog" 92 | 93 | retention_policy { 94 | enabled = false 95 | } 96 | } 97 | 98 | enabled_log { 99 | category = "ApplicationGatewayPerformanceLog" 100 | 101 | retention_policy { 102 | enabled = false 103 | } 104 | } 105 | } -------------------------------------------------------------------------------- /templates/azurefirewall.tf: -------------------------------------------------------------------------------- 1 | 2 | resource "azurerm_public_ip" "hub-azurefirewall-pip" { 3 | name = "AzureFirewall-pip" 4 | location = azurerm_resource_group.hub-rg.location 5 | resource_group_name = azurerm_resource_group.hub-rg.name 6 | 7 | allocation_method = "Static" 8 | sku = "Standard" 9 | } 10 | 11 | resource "azurerm_log_analytics_workspace" "azure_firewall_law" { 12 | name = "AzureFirewall-logs" 13 | location = azurerm_resource_group.hub-rg.location 14 | resource_group_name = azurerm_resource_group.hub-rg.name 15 | sku = "PerGB2018" 16 | retention_in_days = 30 17 | } 18 | 19 | resource "azurerm_firewall_policy" "hub-azfirewall-policy" { 20 | name = "AzureFirewallPolicy" 21 | resource_group_name = azurerm_resource_group.hub-rg.name 22 | location = azurerm_resource_group.hub-rg.location 23 | sku = "Premium" 24 | threat_intelligence_mode = "Off" 25 | 26 | # TO FIX 27 | /* 28 | insights { 29 | default_log_analytics_workspace_id = azurerm_log_analytics_workspace.azure_firewall_law.id 30 | enabled = true 31 | retention_in_days = 30 32 | }*/ 33 | } 34 | 35 | resource "azurerm_firewall" "hub-azure-firewall" { 36 | name = "AzureFirewall" 37 | location = azurerm_resource_group.hub-rg.location 38 | resource_group_name = azurerm_resource_group.hub-rg.name 39 | sku_name = "AZFW_VNet" 40 | sku_tier = "Premium" 41 | firewall_policy_id = azurerm_firewall_policy.hub-azfirewall-policy.id 42 | 43 | ip_configuration { 44 | name = "fw-ipconfig" 45 | subnet_id = azurerm_subnet.hub-azurefirewall-subnet.id 46 | public_ip_address_id = azurerm_public_ip.hub-azurefirewall-pip.id 47 | } 48 | 49 | } 50 | 51 | resource "azurerm_monitor_diagnostic_setting" "azure_firewall_monitor" { 52 | name = "AzureFirewallMonitorLogs" 53 | target_resource_id = azurerm_firewall.hub-azure-firewall.id 54 | log_analytics_workspace_id = azurerm_log_analytics_workspace.azure_firewall_law.id 55 | 56 | enabled_log { 57 | category = "AzureFirewallApplicationRule" 58 | retention_policy { 59 | enabled = false 60 | } 61 | } 62 | 63 | enabled_log { 64 | category = "AzureFirewallNetworkRule" 65 | 66 | retention_policy { 67 | enabled = false 68 | } 69 | } 70 | 71 | metric { 72 | category = "AllMetrics" 73 | 74 | retention_policy { 75 | enabled = false 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /templates/main.tf: -------------------------------------------------------------------------------- 1 | provider "azurerm" { 2 | features {} 3 | 4 | } 5 | 6 | # Resource Groups 7 | 8 | resource "azurerm_resource_group" "hub-rg" { 9 | name = "hub-rg" 10 | location = var.azure_location 11 | } 12 | 13 | resource "azurerm_resource_group" "app1-rg" { 14 | name = "app1-rg" 15 | location = var.azure_location 16 | } 17 | 18 | resource "azurerm_resource_group" "app2-rg" { 19 | name = "app2-rg" 20 | location = var.azure_location 21 | } -------------------------------------------------------------------------------- /templates/network-topology.tf: -------------------------------------------------------------------------------- 1 | # Hub VNet 2 | 3 | resource "azurerm_virtual_network" "hub-vnet" { 4 | name = "hub-vnet" 5 | location = azurerm_resource_group.hub-rg.location 6 | resource_group_name = azurerm_resource_group.hub-rg.name 7 | address_space = ["10.0.0.0/21"] 8 | } 9 | 10 | resource "azurerm_subnet" "hub-gateway-subnet" { 11 | name = "GatewaySubnet" 12 | resource_group_name = azurerm_resource_group.hub-rg.name 13 | virtual_network_name = azurerm_virtual_network.hub-vnet.name 14 | address_prefixes = ["10.0.0.0/27"] 15 | } 16 | 17 | resource "azurerm_subnet" "hub-azurefirewall-subnet" { 18 | name = "AzureFirewallSubnet" 19 | resource_group_name = azurerm_resource_group.hub-rg.name 20 | virtual_network_name = azurerm_virtual_network.hub-vnet.name 21 | address_prefixes = ["10.0.0.128/25"] 22 | } 23 | 24 | resource "azurerm_subnet" "hub-appgw_public-subnet" { 25 | name = "snet-appgw-public" 26 | resource_group_name = azurerm_resource_group.hub-rg.name 27 | virtual_network_name = azurerm_virtual_network.hub-vnet.name 28 | address_prefixes = ["10.0.1.0/24"] 29 | } 30 | 31 | resource "azurerm_subnet" "hub-appgw_private-subnet" { 32 | name = "snet-appgw-private" 33 | resource_group_name = azurerm_resource_group.hub-rg.name 34 | virtual_network_name = azurerm_virtual_network.hub-vnet.name 35 | address_prefixes = ["10.0.2.0/24"] 36 | } 37 | 38 | resource "azurerm_subnet" "hub-workload-subnet" { 39 | name = "snet-workload" 40 | resource_group_name = azurerm_resource_group.hub-rg.name 41 | virtual_network_name = azurerm_virtual_network.hub-vnet.name 42 | address_prefixes = ["10.0.3.0/24"] 43 | } 44 | 45 | # App1 VNet 46 | 47 | resource "azurerm_virtual_network" "app1-vnet" { 48 | name = "app1-vnet" 49 | location = azurerm_resource_group.app1-rg.location 50 | resource_group_name = azurerm_resource_group.app1-rg.name 51 | address_space = ["10.1.0.0/16"] 52 | } 53 | 54 | resource "azurerm_subnet" "app1-workload-subnet" { 55 | name = "snet-workload" 56 | resource_group_name = azurerm_resource_group.app1-rg.name 57 | virtual_network_name = azurerm_virtual_network.app1-vnet.name 58 | address_prefixes = ["10.1.0.0/16"] 59 | } 60 | 61 | # App2 VNet 62 | 63 | resource "azurerm_virtual_network" "app2-vnet" { 64 | name = "app2-vnet" 65 | location = azurerm_resource_group.app2-rg.location 66 | resource_group_name = azurerm_resource_group.app2-rg.name 67 | address_space = ["10.2.0.0/16"] 68 | } 69 | 70 | resource "azurerm_subnet" "app2-workload-subnet" { 71 | name = "snet-workload" 72 | resource_group_name = azurerm_resource_group.app2-rg.name 73 | virtual_network_name = azurerm_virtual_network.app2-vnet.name 74 | address_prefixes = ["10.2.0.0/16"] 75 | } 76 | 77 | # Peerings 78 | 79 | resource "azurerm_virtual_network_peering" "hub-to-app1" { 80 | name = "hub-to-app1" 81 | resource_group_name = azurerm_resource_group.hub-rg.name 82 | virtual_network_name = azurerm_virtual_network.hub-vnet.name 83 | remote_virtual_network_id = azurerm_virtual_network.app1-vnet.id 84 | } 85 | 86 | resource "azurerm_virtual_network_peering" "app1-to-hub" { 87 | name = "app1-to-hub" 88 | resource_group_name = azurerm_resource_group.app1-rg.name 89 | virtual_network_name = azurerm_virtual_network.app1-vnet.name 90 | remote_virtual_network_id = azurerm_virtual_network.hub-vnet.id 91 | } 92 | 93 | resource "azurerm_virtual_network_peering" "hub-to-app2" { 94 | name = "hub-to-app2" 95 | resource_group_name = azurerm_resource_group.hub-rg.name 96 | virtual_network_name = azurerm_virtual_network.hub-vnet.name 97 | remote_virtual_network_id = azurerm_virtual_network.app2-vnet.id 98 | } 99 | 100 | resource "azurerm_virtual_network_peering" "app2-to-hub" { 101 | name = "app2-to-hub" 102 | resource_group_name = azurerm_resource_group.app2-rg.name 103 | virtual_network_name = azurerm_virtual_network.app2-vnet.name 104 | remote_virtual_network_id = azurerm_virtual_network.hub-vnet.id 105 | } -------------------------------------------------------------------------------- /templates/variables.tf: -------------------------------------------------------------------------------- 1 | ######################################################### 2 | # Variables 3 | ######################################################### 4 | 5 | variable "azure_location" { 6 | type = string 7 | default = "westeurope" 8 | description = "Azure resources location" 9 | } 10 | 11 | variable "admin_username" { 12 | description = "" 13 | type = string 14 | default = "adminuser" 15 | } 16 | 17 | variable "admin_password" { 18 | description = "Password for all VMs deployed in this MicroHack" 19 | type = string 20 | default = "Microsoft=1Microsoft=1" 21 | } 22 | 23 | variable "vm_size" { 24 | type = string 25 | default = "Standard_DS1_v2" 26 | description = "VM Size" 27 | } 28 | 29 | variable "vm_os_type" { 30 | type = string 31 | default = "Linux" 32 | description = "VM OS Type" 33 | } 34 | 35 | variable "vm_os_publisher" { 36 | type = string 37 | default = "canonical" 38 | description = "VM OS Publisher" 39 | } 40 | 41 | variable "vm_os_offer" { 42 | type = string 43 | #default = "UbuntuServer" 44 | default = "0001-com-ubuntu-server-jammy" 45 | description = "VM OS Offer" 46 | } 47 | 48 | variable "vm_os_sku" { 49 | type = string 50 | default = "22_04-lts-gen2" 51 | description = "VM OS Sku" 52 | } 53 | 54 | variable "vm_os_version" { 55 | type = string 56 | default = "latest" 57 | description = "VM OS Version" 58 | } 59 | 60 | 61 | 62 | locals { 63 | apache2 = < /var/www/html/index.html 70 | - systemctl enable apache2 71 | - systemctl start apache2 72 | - wget https://raw.githubusercontent.com/dmauser/azure-vm-net-tools/main/script/nettools.sh 73 | - chmod +x nettools.sh 74 | - ./nettools.sh 75 | CUSTOM_DATA 76 | } 77 | -------------------------------------------------------------------------------- /templates/vms.tf: -------------------------------------------------------------------------------- 1 | # Hub VM 2 | 3 | resource "azurerm_network_interface" "hub-vm-nic" { 4 | name = "hub-vmni01" 5 | location = azurerm_resource_group.hub-rg.location 6 | resource_group_name = azurerm_resource_group.hub-rg.name 7 | 8 | ip_configuration { 9 | name = "ipConfig1" 10 | subnet_id = azurerm_subnet.hub-workload-subnet.id 11 | private_ip_address_allocation = "Dynamic" 12 | } 13 | } 14 | 15 | resource "azurerm_linux_virtual_machine" "hub-vm" { 16 | name = "hub-vm" 17 | location = azurerm_resource_group.hub-rg.location 18 | resource_group_name = azurerm_resource_group.hub-rg.name 19 | size = var.vm_size 20 | admin_username = var.admin_username 21 | disable_password_authentication = "false" 22 | admin_password = var.admin_password 23 | network_interface_ids = [azurerm_network_interface.hub-vm-nic.id] 24 | custom_data = base64encode(local.apache2) 25 | 26 | os_disk { 27 | caching = "ReadWrite" 28 | storage_account_type = "Standard_LRS" 29 | name = "hub-vmod01" 30 | } 31 | 32 | source_image_reference { 33 | publisher = var.vm_os_publisher 34 | offer = var.vm_os_offer 35 | sku = var.vm_os_sku 36 | version = var.vm_os_version 37 | } 38 | 39 | boot_diagnostics { 40 | 41 | } 42 | } 43 | 44 | 45 | # App1 VM 46 | 47 | resource "azurerm_network_interface" "app1-vm-nic" { 48 | name = "app1-vmni01" 49 | location = azurerm_resource_group.app1-rg.location 50 | resource_group_name = azurerm_resource_group.app1-rg.name 51 | 52 | ip_configuration { 53 | name = "ipConfig1" 54 | subnet_id = azurerm_subnet.app1-workload-subnet.id 55 | private_ip_address_allocation = "Dynamic" 56 | } 57 | } 58 | 59 | resource "azurerm_linux_virtual_machine" "app1-vm" { 60 | name = "app1-vm" 61 | location = azurerm_resource_group.app1-rg.location 62 | resource_group_name = azurerm_resource_group.app1-rg.name 63 | size = var.vm_size 64 | admin_username = var.admin_username 65 | disable_password_authentication = "false" 66 | admin_password = var.admin_password 67 | network_interface_ids = [azurerm_network_interface.app1-vm-nic.id] 68 | custom_data = base64encode(local.apache2) 69 | 70 | os_disk { 71 | caching = "ReadWrite" 72 | storage_account_type = "Standard_LRS" 73 | name = "app1-vmod01" 74 | } 75 | 76 | source_image_reference { 77 | publisher = var.vm_os_publisher 78 | offer = var.vm_os_offer 79 | sku = var.vm_os_sku 80 | version = var.vm_os_version 81 | } 82 | 83 | boot_diagnostics { 84 | 85 | } 86 | } 87 | 88 | # App2 VM 89 | 90 | resource "azurerm_network_interface" "app2-vm-nic" { 91 | name = "app2-vmni01" 92 | location = azurerm_resource_group.app2-rg.location 93 | resource_group_name = azurerm_resource_group.app2-rg.name 94 | 95 | ip_configuration { 96 | name = "ipConfig1" 97 | subnet_id = azurerm_subnet.app2-workload-subnet.id 98 | private_ip_address_allocation = "Dynamic" 99 | } 100 | } 101 | 102 | resource "azurerm_linux_virtual_machine" "app2-vm" { 103 | name = "app2-vm" 104 | location = azurerm_resource_group.app2-rg.location 105 | resource_group_name = azurerm_resource_group.app2-rg.name 106 | size = var.vm_size 107 | admin_username = var.admin_username 108 | disable_password_authentication = "false" 109 | admin_password = var.admin_password 110 | network_interface_ids = [azurerm_network_interface.app2-vm-nic.id] 111 | custom_data = base64encode(local.apache2) 112 | 113 | os_disk { 114 | caching = "ReadWrite" 115 | storage_account_type = "Standard_LRS" 116 | name = "app2-vmod01" 117 | } 118 | 119 | source_image_reference { 120 | publisher = var.vm_os_publisher 121 | offer = var.vm_os_offer 122 | sku = var.vm_os_sku 123 | version = var.vm_os_version 124 | } 125 | 126 | boot_diagnostics { 127 | 128 | } 129 | } 130 | --------------------------------------------------------------------------------