Skip to content

Commit 2d50378

Browse files
kafeelhasanmjang
andauthored
NGINXaaS: Add private subnet OIDC with Microsoft Entra ID guide (#1395)
* NGINXaaS: Add private subnet OIDC with Microsoft Entra ID guide * Address PR Comments * Address PR Comments --------- Co-authored-by: Mike Jang <3287976+mjang@users.noreply.github.com>
1 parent 827cb7b commit 2d50378

File tree

1 file changed

+312
-0
lines changed

1 file changed

+312
-0
lines changed
Lines changed: 312 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,312 @@
1+
---
2+
title: OIDC with Microsoft Entra ID in Private Subnets
3+
url: /nginxaas/azure/quickstart/security-controls/private-subnet-oidc-entra/
4+
toc: true
5+
weight: 350
6+
nd-content-type: how-to
7+
nd-product: N4Azure
8+
---
9+
10+
## Overview
11+
12+
Learn how to configure F5 NGINXaaS for Azure with OpenID Connect (OIDC) authentication using Microsoft Entra ID when your NGINXaaS deployment is in a private subnet. This guide addresses the networking requirements to enable authentication traffic to reach Microsoft Entra ID endpoints while maintaining security controls.
13+
14+
When NGINXaaS is deployed in a private subnet, authentication traffic must reach external Microsoft Entra ID endpoints at `login.microsoftonline.com`. This guide provides the following solutions to enable this connectivity while controlling outbound traffic:
15+
16+
1. **Azure NAT Gateway with NSG rules** - Lower cost, simpler configuration
17+
1. **Azure Firewall** - Higher security, more granular control
18+
19+
## Before you begin
20+
21+
To complete this guide, you need to set up the following:
22+
23+
- [An NGINXaaS deployment]({{< ref "/nginxaas-azure/getting-started/create-deployment" >}}) with a private IP address
24+
- A configured Microsoft Entra ID application registration. See [Configure Entra ID]({{< ref "/nginx/deployment-guides/single-sign-on/entra-id/#entra-setup" >}}) for detailed setup instructions.
25+
- [SSL/TLS certificates]({{< ref "/nginxaas-azure/getting-started/ssl-tls-certificates/" >}}) configured for your NGINXaaS deployment
26+
- [Runtime State Sharing]({{< ref "/nginxaas-azure/quickstart/runtime-state-sharing.md" >}}) enabled on the NGINXaaS deployment
27+
28+
## Solution comparison
29+
30+
Choose the networking solution that best fits your security and cost requirements:
31+
32+
{{< table >}}
33+
| Feature | Azure NAT Gateway | Azure Firewall |
34+
|---------|-------------------|----------------|
35+
| **Hourly cost** | Lower - see [NAT Gateway pricing](https://azure.microsoft.com/en-us/pricing/details/azure-nat-gateway/) | Higher - see [Firewall pricing](https://azure.microsoft.com/en-us/pricing/details/azure-firewall/) |
36+
| **Address space** | Less required | More required (2 additional /26 subnets) |
37+
| **Security** | Less secure - broader IP range filtering | More secure - precise FQDN-based filtering |
38+
| **Configuration** | Simple setup, less overhead | More complex configuration, more overhead |
39+
| **Public IPs** | 1 required | 2 required |
40+
| **Filtering precision** | Generic rules enabling broader filtering | Surgical precision for traffic filtering |
41+
{{< /table >}}
42+
43+
## Common configuration steps
44+
45+
Both solutions require these initial steps:
46+
47+
### Configure OIDC in NGINXaaS
48+
49+
1. Follow the standard [OIDC authentication]({{< ref "/nginxaas-azure/quickstart/security-controls/oidc/" >}}) guide with these Microsoft Entra ID specific considerations.
50+
51+
1. Set the `oidc_jwt_keyfile` endpoint in your `openid_connect_configuration.conf`:
52+
53+
```nginx
54+
# Use the correct Microsoft Entra ID keys endpoint
55+
map $host $oidc_jwt_keyfile {
56+
default "https://login.microsoftonline.com/<tenant-id>/discovery/v2.0/keys";
57+
}
58+
```
59+
60+
{{< call-out "note" >}}The `oidc_jwt_keyfile` endpoint is not listed in the Microsoft App Registration's endpoints pane but is required for proper OIDC configuration.{{< /call-out >}}
61+
62+
1. Configure DNS resolution appropriately:
63+
- For dual-stack subnets, ensure both IPv4 and IPv6 address spaces are configured
64+
- Use Azure DNS (127.0.0.1:49153) or configure firewall rules for your preferred DNS service
65+
66+
```nginx
67+
http {
68+
# For IPv4-only deployments
69+
resolver 127.0.0.1:49153 ipv4=on ipv6=off valid=300s;
70+
71+
# For dual-stack deployments
72+
resolver 127.0.0.1:49153 ipv4=on valid=300s;
73+
}
74+
```
75+
76+
{{< call-out "important" >}}If you plan to use IPv6 addresses on the frontend, ensure your subnet is dual-stack with both IPv4 and IPv6 address spaces. For IPv4-only deployments, set `ipv6=off` in your resolver configuration.{{< /call-out >}}
77+
78+
## Configure connectivity using Azure NAT Gateway
79+
80+
This solution uses Azure NAT Gateway with Network Security Group (NSG) rules to enable controlled outbound connectivity.
81+
82+
### Configure NSG rules
83+
84+
When you create an NGINXaaS deployment, Azure automatically creates and attaches an NSG to the delegated subnet. You need to modify this NSG to allow Microsoft Entra ID connectivity.
85+
86+
1. Add Microsoft IP address ranges to NSG rules:
87+
88+
Navigate to your NGINXaaS subnet's NSG and add inbound and outbound rules for the Microsoft IP addresses listed in the [Microsoft 365 URLs and IP address ranges documentation](https://learn.microsoft.com/en-us/microsoft-365/enterprise/urls-and-ip-address-ranges?view=o365-worldwide#microsoft-365-common-and-office-online) under section #56.
89+
90+
1. Create a custom outbound rule to deny general internet access:
91+
92+
- **Priority**: Higher numerical value (lower priority) than the Microsoft IP rules
93+
- **Action**: Deny
94+
- **Destination**: Internet
95+
- **Purpose**: Override the default `AllowInternetOutBound` rule
96+
97+
{{< call-out "important" >}}The default `AllowInternetOutBound` rule cannot be edited, so you must create a higher-priority rule to deny general internet access while allowing the specific Microsoft IP ranges. The priority of the custom deny rule should be a higher numerical value (lower priority) than the Microsoft IP allow rules.{{< /call-out >}}
98+
99+
### Create and configure Azure NAT Gateway
100+
101+
1. Create an Azure NAT Gateway:
102+
103+
```bash
104+
# Create Azure NAT Gateway
105+
az network nat gateway create \
106+
--resource-group <resource-group> \
107+
--name <nat-gateway-name> \
108+
--location <location> \
109+
--public-ip-addresses <public-ip-name>
110+
```
111+
112+
1. Associate the Azure NAT Gateway with your NGINXaaS subnet:
113+
114+
```bash
115+
# Associate Azure NAT Gateway with subnet
116+
az network vnet subnet update \
117+
--resource-group <resource-group> \
118+
--vnet-name <vnet-name> \
119+
--name <nginxaas-subnet-name> \
120+
--nat-gateway <nat-gateway-name>
121+
```
122+
123+
This configuration allows NGINXaaS to reach Microsoft Entra ID endpoints while blocking general internet access.
124+
125+
{{< call-out "note" >}}Using Azure NAT Gateway with NSG rules still requires allowing broad IP address ranges. Based on Microsoft's documentation, you need to allow at least two /18 subnets and two /19 subnets for complete Microsoft Entra ID connectivity. For more precise filtering, consider using Azure Firewall instead.{{< /call-out >}}
126+
127+
## Configure connectivity using Azure Firewall
128+
129+
This solution provides more granular control using Azure Firewall with DNS-based filtering.
130+
131+
{{< call-out "note" >}}Azure Firewall provides DNS-based filtering capabilities but comes at a significantly higher cost compared to Azure NAT Gateway (approximately 28x cost increase). However, it enables more precise firewall rules for better security.{{< /call-out >}}
132+
133+
### Create firewall subnets
134+
135+
Create two new subnets in your virtual network:
136+
137+
1. **Azure Firewall subnet**:
138+
- Name: `AzureFirewallSubnet` (immutable)
139+
- Address space: /26 subnet
140+
- Purpose: Azure Firewall
141+
142+
1. **Firewall Management subnet**:
143+
- Name: `AzureFirewallManagementSubnet` (immutable)
144+
- Address space: /26 subnet
145+
- Purpose: Firewall Management
146+
147+
```bash
148+
# Create Azure Firewall subnet
149+
az network vnet subnet create \
150+
--resource-group <resource-group> \
151+
--vnet-name <vnet-name> \
152+
--name AzureFirewallSubnet \
153+
--address-prefixes <firewall-subnet-cidr>
154+
155+
# Create Firewall Management subnet
156+
az network vnet subnet create \
157+
--resource-group <resource-group> \
158+
--vnet-name <vnet-name> \
159+
--name AzureFirewallManagementSubnet \
160+
--address-prefixes <management-subnet-cidr>
161+
```
162+
163+
### Create Azure Firewall
164+
165+
1. Create the firewall with Standard SKU (required for DNS proxy functionality):
166+
167+
```bash
168+
# Create public IPs for firewall
169+
az network public-ip create \
170+
--name <firewall-public-ip> \
171+
--resource-group <resource-group> \
172+
--allocation-method Static \
173+
--sku Standard
174+
175+
az network public-ip create \
176+
--name <firewall-mgmt-public-ip> \
177+
--resource-group <resource-group> \
178+
--allocation-method Static \
179+
--sku Standard
180+
181+
# Create firewall with new policy
182+
az extension add --name azure-firewall
183+
az network firewall create \
184+
--name <firewall-name> \
185+
--resource-group <resource-group> \
186+
--vnet-name <vnet-name> \
187+
--public-ip <firewall-public-ip> \
188+
--firewall-policy <firewall-policy-name>
189+
```
190+
191+
{{< call-out "note" >}}The Standard SKU is required at minimum because it allows Azure Firewall to be configured as a DNS proxy, which is necessary for FQDN-based filtering. During creation, choose to create a new Firewall Policy and use your existing virtual network that contains the NGINXaaS subnet.{{< /call-out >}}
192+
193+
### Configure firewall policy
194+
195+
1. Enable DNS proxy in the firewall policy:
196+
197+
```bash
198+
# Enable DNS proxy
199+
az network firewall policy update \
200+
--name <firewall-policy-name> \
201+
--resource-group <resource-group> \
202+
--enable-dns-proxy true \
203+
--dns-servers 168.63.129.16
204+
```
205+
206+
1. Configure private IP ranges to avoid SNAT for internal traffic:
207+
208+
Navigate to your firewall policy in the Azure portal and under **Private IP ranges**, select "Always" or specify your NGINXaaS subnet IP addresses.
209+
210+
### Create network rules
211+
212+
Create a network rule collection to allow NGINXaaS subnet access to Microsoft Entra ID:
213+
214+
```bash
215+
# Create network rule collection
216+
az network firewall policy rule-collection-group create \
217+
--name NetworkRuleCollectionGroup \
218+
--policy-name <firewall-policy-name> \
219+
--resource-group <resource-group> \
220+
--priority 200
221+
222+
# Add network rule for Microsoft Entra ID
223+
az network firewall policy rule-collection-group collection add-filter-collection \
224+
--name EntraIDAccess \
225+
--policy-name <firewall-policy-name> \
226+
--resource-group <resource-group> \
227+
--collection-priority 100 \
228+
--rule-collection-group-name NetworkRuleCollectionGroup \
229+
--action Allow \
230+
--rule-name AllowEntraID \
231+
--rule-type NetworkRule \
232+
--protocols TCP \
233+
--source-addresses <nginxaas-subnet-cidr> \
234+
--destination-fqdns login.microsoftonline.com \
235+
--destination-ports 443
236+
```
237+
238+
### Configure route table
239+
240+
Direct NGINXaaS subnet traffic through the firewall:
241+
242+
1. Note the private IP address of your Azure Firewall (found in the firewall's overview page).
243+
244+
1. Create a route table:
245+
246+
```bash
247+
# Create route table
248+
az network route-table create \
249+
--name <route-table-name> \
250+
--resource-group <resource-group> \
251+
--location <location>
252+
253+
# Add default route pointing to firewall
254+
az network route-table route create \
255+
--route-table-name <route-table-name> \
256+
--resource-group <resource-group> \
257+
--name DefaultRoute \
258+
--address-prefix 0.0.0.0/0 \
259+
--next-hop-type VirtualAppliance \
260+
--next-hop-ip-address <firewall-private-ip>
261+
```
262+
263+
1. Associate the route table with the NGINXaaS subnet:
264+
265+
```bash
266+
# Associate route table with NGINXaaS subnet
267+
az network vnet subnet update \
268+
--resource-group <resource-group> \
269+
--vnet-name <vnet-name> \
270+
--name <nginxaas-subnet-name> \
271+
--route-table <route-table-name>
272+
```
273+
274+
## Testing the configuration
275+
276+
After implementing either solution, test the OIDC authentication:
277+
278+
1. Access your NGINXaaS deployment URL.
279+
1. Verify you are redirected to Microsoft Entra ID for authentication.
280+
1. Complete the login process and confirm successful authentication.
281+
1. Check NGINXaaS logs for any connectivity issues.
282+
283+
### Troubleshooting
284+
285+
If authentication fails, check the following:
286+
287+
1. **DNS Resolution**: Ensure your firewall rules allow DNS queries.
288+
1. **Certificate Validation**: Verify that the firewall allows HTTPS traffic to Microsoft endpoints.
289+
1. **Timeout Settings**: Increase timeout values if experiencing slow authentication responses.
290+
1. **Route Configuration**: Confirm the route table is properly associated with the NGINXaaS subnet.
291+
292+
## To secure your systems, address the following:
293+
294+
- **Principle of Least Privilege**: Both solutions limit outbound connectivity to only required Microsoft endpoints.
295+
- **Monitoring**: Implement logging and monitoring for authentication traffic.
296+
- **Regular Updates**: Keep Microsoft IP address ranges updated in your NSG rules.
297+
- **Network Segmentation**: Consider additional network segmentation for enhanced security.
298+
299+
## To optimize your systems, we recommend:
300+
301+
- **Azure NAT Gateway**: More cost-effective for basic filtering needs.
302+
- **Azure Firewall**: Better ROI when you need advanced filtering capabilities.
303+
- **Public IP Management**: Minimize the number of public IP addresses to reduce costs.
304+
305+
Both solutions enable the minimal connectivity required between NGINXaaS and Microsoft Entra ID for OIDC authentication while maintaining security controls appropriate to your requirements.
306+
307+
## See also
308+
309+
- [Set up OIDC authentication]({{< ref "/nginxaas-azure/quickstart/security-controls/oidc/" >}})
310+
- [Single Sign-On with Microsoft Entra ID]({{< ref "/nginx/deployment-guides/single-sign-on/entra-id.md" >}})
311+
- [Private Link to Upstreams]({{< ref "/nginxaas-azure/quickstart/security-controls/private-link-to-upstreams.md" >}})
312+
- [Microsoft 365 URLs and IP address ranges](https://learn.microsoft.com/en-us/microsoft-365/enterprise/urls-and-ip-address-ranges)

0 commit comments

Comments
 (0)