# Migrate from Azure VNet to Quake AI

Source: https://docs.quake.ai/docs/network/migration/migrate-from-azure-vnet
Markdown: https://docs.quake.ai/docs/network/migration/migrate-from-azure-vnet.md

---

# Migrate from Azure VNet to Quake AI

Azure's networking model introduces these constructs with no direct Neutron equivalent: the dual NSG layer (subnet-level and NIC-level), User Defined Routes for traffic inspection, Application Gateway WAF, and Azure-specific services (Service Endpoints, Private Link, Azure Firewall). The core migration shift: Azure's two independent security enforcement points (subnet NSG + NIC NSG) collapse into a single port-level security group on Quake AI's [OpenStack Neutron](/resources/migration/openstack). This simplification requires auditing effective rules at both Azure layers so you do not lose any during the merge.

## Service mapping

<MigrationTable provider="azure" service="network" />


## Prerequisites

- A Quake AI account with [application credentials](/docs/tools/generate-app-credentials)
- The [OpenStack CLI](/docs/tools/install-openstack-client) installed and configured
- An inventory of your Azure resources: VNets, subnets, NSGs (both subnet and NIC level), Public IPs, Load Balancers, Application Gateways, and Azure DNS zones
- Effective NSG rules per VM: run `az network nic list-effective-nsg` to audit what each VM actually sees
- An SSH key pair imported to Quake AI (`openstack keypair create --public-key`)

## Topology mapping

Azure's per-subnet NSGs, per-NIC NSGs, and UDR route tables compress into Neutron's simpler model: one network, one subnet, one router, and per-port security groups.

<Figure caption="Azure VNet with two NSG layers and NAT Gateway maps to a Neutron network with a single security group layer and floating IPs">

```d2
direction: down

azure: Azure VNet {
  subnet: Subnet
  nsg_subnet: NSG (subnet)
  nic: NIC
  nsg_nic: NSG (NIC)
  nat: NAT Gateway
  pip: Public IP
  vm: VM
  subnet -> nic
  nic -> vm
  nsg_subnet -> subnet: subnet-level
  nsg_nic -> nic: nic-level
  nat -> subnet
  pip -> nic
}

neutron: Quake AI Neutron {
  network: Tenant Network
  subnet: Subnet
  router: Router (SNAT)
  port: Port
  sg: Security Group
  fip: Floating IP
  network -> subnet
  router -> network
  port -> network
  sg -> port: port-level
  fip -> port
}

azure -> neutron: maps to
```

</Figure>

| Azure concept | Neutron equivalent | Notes |
|---|---|---|
| VNet | Network | Regional match |
| Subnet | Subnet | Direct match |
| NSG (subnet-level) | **No direct equivalent** | Collapses into per-port security group |
| NSG (NIC-level) | Security Group (port binding) | Direct match for NIC-level NSG |
| UDR / Route Table | Router static routes | Partial match; NVA steering has no equivalent |
| Azure Firewall | **No equivalent** | Managed NGFW; use software NVA if needed |
| NAT Gateway | Router (SNAT) | Router SNAT is the equivalent |
| Public IP (static, Standard) | Floating IP | Direct match |
| Public IP (Basic SKU, dynamic; retired 30.09.2025) | PublicEphemeral model | Basic SKU unavailable for new resources; Microsoft migrated existing Basic IPs to Standard. No SKU distinction on Quake AI. |
| Application Gateway | **No equivalent** | Layer 7 LB with WAF |
| Azure Load Balancer (L4) | Self-managed HAProxy or Nginx stream proxy | Run the proxy on a Compute instance |
| VNet Peering | **No equivalent** | No peering on Quake AI |
| Service Endpoints | **No equivalent** | No private routing to PaaS |
| Private Link | **No equivalent** | No private IP access to PaaS |
| Availability Zone | **No equivalent** | Quake AI uses regions, not AZs |

### Set up the Neutron equivalent

```bash
openstack network create my-network

openstack subnet create my-subnet \
  --network my-network \
  --subnet-range 10.0.0.0/24 \
  --gateway 10.0.0.1 \
  --dns-nameserver 8.8.8.8

openstack router create my-router
openstack router set my-router --external-gateway PublicStatic
openstack router add subnet my-router my-subnet
```

## Security rule translation

The critical difference: Azure allows NSGs at both subnet and NIC level. Traffic entering a VM passes through the subnet NSG first, then the NIC NSG. Both must allow the traffic. Neutron has one enforcement point: the port (equivalent to the NIC).

| Dimension | Azure NSG | Neutron Security Group |
|---|---|---|
| Statefulness | Stateful | Stateful |
| Rule model | Allow and deny (with priority) | Allow-only |
| Priority system | Lower number = higher priority (100-4096 for custom rules; default rules at 65000/65001/65500 cannot be removed) | All rules additive; no priority |
| Applied to | Subnet and/or NIC (two layers) | Port only (single layer) |
| Default rules | AllowVnetInBound, AllowAzureLBInBound, DenyAllInBound | Deny-all ingress, allow-all egress |
| Source types | CIDR, Service Tags, Application Security Groups | CIDR, Security Group ID |

### Merging dual NSG layers

For each VM, audit the effective rules across both NSG layers:

1. Run `az network nic list-effective-nsg --resource-group MY_RG --network-interface-name MY_NIC` to see what rules actually apply.
2. Merge the subnet NSG and NIC NSG into a single set of Neutron security group rules.
3. Express the allow rules from both layers in one Neutron SG per VM role.

### Translating Azure-specific constructs

**Service Tags** (e.g., `Internet`, `AzureLoadBalancer`, `VirtualNetwork`, `Storage`): These expand to Azure-managed IP ranges with no Neutron equivalent. Use explicit CIDR ranges instead. Drop the `AllowAzureLoadBalancerInBound` default rule and add only the health-check sources required by your replacement proxy.

**AllowVnetInBound default rule**: Azure permits all traffic within the VNet by default at priority 65000. Neutron's default is deny-all inbound. Applications that relied on this permissive VNet default (without explicit NSG rules for internal traffic) will break until you add explicit allow rules for internal traffic patterns.

**Deny rules**: Same approach as GCP. Enumerate what the deny rules block. Ensure corresponding allow rules are absent in Neutron security groups.

### 3-tier app example

**Azure source:**
- Web subnet NSG: Priority 100 allow inbound TCP 80, 443 from Internet; Priority 65000 AllowVnetInBound; Priority 65500 DenyAllInBound
- App subnet NSG: Priority 100 allow TCP 8080 from `10.0.1.0/24` (web subnet)
- DB subnet NSG: Priority 100 allow TCP 5432 from `10.0.2.0/24` (app subnet)

**Neutron target (merged to single layer, upgraded to SG references):**

```bash
openstack security group create sg-web
openstack security group rule create sg-web \
  --protocol tcp --dst-port 80 --remote-ip 0.0.0.0/0 --ingress
openstack security group rule create sg-web \
  --protocol tcp --dst-port 443 --remote-ip 0.0.0.0/0 --ingress

openstack security group create sg-app
openstack security group rule create sg-app \
  --protocol tcp --dst-port 8080 --remote-group sg-web --ingress

openstack security group create sg-db
openstack security group rule create sg-db \
  --protocol tcp --dst-port 5432 --remote-group sg-app --ingress
```

The subnet-level NSG layer is dropped entirely. The `AllowVnetInBound` default rule (which allows all VNet internal traffic) is replaced by explicit rules. This is a **security improvement**: Neutron's default deny is stricter than Azure's permissive VNet default.



Azure's `AllowVnetInBound` allows all intra-VNet traffic by default. If your applications rely on this implicit internal access without explicit NSG rules, they will fail on Quake AI until you add the necessary security group rules for internal communication patterns.



## Load balancer migration

Replace Azure traffic services according to their scope:

| Azure source | Quake AI migration pattern |
|---|---|
| Azure Load Balancer | HAProxy or Nginx stream proxy on a Compute instance |
| Application Gateway | Nginx, HAProxy, Caddy, Traefik, or Envoy |
| Application Gateway WAF | External CDN/WAF or a reverse proxy with a WAF module |
| Azure Front Door | External CDN and edge routing provider |
| Traffic Manager | External DNS traffic manager |

Assign a floating IP to the proxy instance and keep application backends on a private network. Install TLS certificates on the proxy with Certbot, use Caddy's ACME support, or terminate public TLS at the external edge.

## Floating IP setup

| Azure Public IP | Neutron Floating IP |
|---|---|
| Standard SKU: static, zone-redundant | Static, region-scoped |
| Basic SKU: dynamic (retired 30.09.2025; no new Basic IPs can be created) | Floating IPs are always static; no SKU concept |
| Charged even when attached on Azure | Included in Quake AI pricing |
| IPv4 and IPv6 | IPv4 only (IPv6 not documented) |
| Attaches to NIC, LB, App Gateway, Bastion | Attaches to a Quake AI port |



Basic SKU Public IPs reached retirement on 30.09.2025. If your Azure deployment predates that date, confirm whether Azure migrated these IPs to Standard SKU, and upgrade any that remain on Basic SKU before you migrate to Quake AI.



```bash
openstack floating ip create PublicStatic
openstack server add floating ip MY_INSTANCE FLOATING_IP_ADDRESS
```

Azure Standard SKU Public IPs can be zone-redundant (replicated across AZs). Quake AI has no AZ concept; floating IPs are region-scoped.

## DNS cutover

Azure DNS must be replaced by an external provider. Quake AI has no managed DNS service.

1. **Export zone**: `az network dns zone export -g RESOURCE_GROUP -n example.com -f zone.txt`
2. **Review private zones**: Azure Private DNS Zones (VNet-internal name resolution) must be replicated with an internal DNS service. Options: dnsmasq, a custom resolver VM, or Neutron DHCP subnet DNS server configuration.
3. **Lower TTLs**: Modify all records to 300 seconds; wait for the current TTL to expire.
4. **Import at new provider**: Standard BIND zone file accepted by most providers.
5. **Validate**: `dig @NEW_NAMESERVER example.com A`
6. **Update registrar NS records**.
7. **Monitor for 48 hours** and restore TTLs after successful cutover.

**Records to remap:**
- Alias records pointing to Azure LB/App Gateway DNS names become `CNAME` or `A` records pointing to the reverse proxy floating IP or external edge hostname
- Azure Traffic Manager endpoints become external DNS load balancing records (Cloudflare, NS1 Pulsar)
- Azure Front Door CNAMEs become CDN provider CNAMEs

## Validation checklist

- [ ] Neutron network, subnet, and router are operational
- [ ] Security group rules capture the merged intent of both subnet-level and NIC-level NSGs
- [ ] Azure `AllowVnetInBound` equivalent rules are explicitly added for internal traffic
- [ ] Azure deny rules are handled by the absence of corresponding allow rules
- [ ] Azure Service Tag references are replaced by explicit CIDRs
- [ ] Floating IPs are associated with the correct instance ports
- [ ] Reverse proxy health checks pass for application backends
- [ ] WAF replacement is in place (CDN/WAF edge or reverse proxy) if Application Gateway WAF was used
- [ ] DNS records resolve to Quake AI floating IPs or external edge hostnames
- [ ] Applications respond correctly through the full network path

## Provider-specific gotchas

| Topic | Detail |
|---|---|
| Dual NSG complexity | Large Azure deployments often have NSGs at both subnet and NIC levels. Audit effective rules per VM (`az network nic list-effective-nsg`) before migration. Rules enforced only by the subnet-level NSG would be lost in a simple NIC-only translation. |
| Egress pricing | Azure bills egress per-GB with rates that vary by region, and adds per-GB charges for cross-AZ traffic. Quake AI's bandwidth-inclusive model is cheaper for egress-heavy workloads. See [Azure bandwidth pricing](https://azure.microsoft.com/en-us/pricing/details/bandwidth/). |
| Service Endpoints and Private Link | These provide private routing to Azure PaaS (Storage, SQL, Key Vault). On Quake AI, access remaining Azure PaaS over the public internet, or migrate services to Quake AI-hosted VMs. Store application secrets in your CI system, Kubernetes, or a self-managed secrets service. |
| AllowVnetInBound default | Azure NSGs include a built-in rule permitting all VNet-internal traffic. Neutron's deny-all default is stricter. Add explicit allow rules for every internal communication pattern. |
| Availability Zones | Azure zone-pinned resources and zone-redundant Standard LBs require a new topology. Run multiple application instances and route traffic through a self-managed proxy or external edge. |

## See also

- [Migrating from Azure to Quake AI](/resources/migration/from-azure): full cross-service migration hub
- [Migrate from Azure VMs to Quake AI Compute](/docs/compute/migration/migrate-from-azure-vms): compute workload migration
- [Network migration guides](/docs/network/migration): all provider guides
- [Create a security group](/docs/network/how-to/create-security-group): Neutron security group setup
