---
name: azion-guard-one-path-with-a-network-list
description: >-
  Deny the addresses of a network list on one path, such as /admin, and keep every other path open, with one firewall rule in Azion Console, the CLI, or the API.
---

# Guard one path with a network list

You can deny listed addresses on one path, `/admin`, from Azion Console, the [Azion CLI](/en/documentation/devtools/cli/), or the API. Every other path of the workload stays open to those addresses. One [firewall](/en/documentation/platform/firewall/) rule chains two criteria: *Network* compares the client address with an `ip_cidr` [network list](/en/documentation/platform/firewall/network-shield/network-lists/), and *Request Uri* compares the path. Use this rule to keep some addresses out of an administration area, a login form, or an API route. It also lets you try a list on one path before a rule applies the list to every request. To deny listed addresses on every path instead, refer to [Block requests by IP, ASN, or country](/en/documentation/guides/application-security/bots-and-network/blocklists-ip-addresses-edge/).

---

Select the interface you work in. The prerequisites and every task on this page switch to match it.

## Prerequisites

- A [workload](/en/documentation/platform/workloads/) bound to a firewall through its deployment. That firewall receives the rule you create in this guide.
- [Network Shield](/en/documentation/platform/firewall/#network-shield) turned on for that firewall. Network Shield is on by default when a firewall is created. To turn it on, refer to [Set a firewall's main settings](/en/documentation/guides/application-security/firewall-and-waf/firewall-configure-main-settings/).

**Console**

- Access to [Azion Console](https://console.azion.com/).

**CLI**

- The Azion CLI, installed and configured with a [personal token](/en/documentation/fundamentals/personal-tokens/).
- The ID of the firewall that your workload is bound to.

**API**

- A [personal token](/en/documentation/fundamentals/personal-tokens/). Each request in this guide carries it in place of `[TOKEN VALUE]`.
- The ID of the firewall that your workload is bound to.

---

## Create the address list

An `ip_cidr` list holds IP addresses and ranges, one per item, in IPv4 or IPv6. A range takes CIDR notation, such as `198.51.100.0/24`. A client matches the list when its address is an item or falls inside a range. The list in this guide holds one IPv4 address, one IPv4 range, and one IPv6 range. Its type stays `ip_cidr` for the life of the list. For the fields of a list and the format of each type, refer to [Network list fields](/en/documentation/platform/firewall/network-shield/network-lists/#network-list-fields) and [List types](/en/documentation/platform/firewall/network-shield/network-lists/#list-types).

**Console**

To create the list in Azion Console:

1. **Open the Network Lists page**

   Access [Azion Console](https://console.azion.com/) > **Edge Libraries** > **Network Lists**.

2. **Select Network List**

3. **Name the list**

   In the **General** section, enter a **Name**. For example: `Blocked addresses`.

4. **Select the IP/CIDR type**

   In the **Network List Settings** section, select *IP/CIDR* to replace *ASN*, the type that the form opens with.

5. **Enter the addresses**

   In the **List** field, enter each address or range on its own line:

   ```text
   192.0.2.10
   198.51.100.0/24
   2001:db8::/32
   ```

6. **Save the list**

   Select **Save**.

Azion Console confirms with the message `Your network list has been created`. **Network Lists** shows the list, and its **List Type** column reads *IP/CIDR*.

**CLI**

To create the list with the Azion CLI, save its definition as `network-list.json`:

```json
{
  "name": "Blocked addresses",
  "type": "ip_cidr",
  "items": ["192.0.2.10", "198.51.100.0/24", "2001:db8::/32"]
}
```

Then create the list from the file:

```bash
azion create network-list --file network-list.json
```

The CLI prints the ID of the list it created:

```text
Created Network List with ID <network-list-id>
```

The list `Blocked addresses` holds the three items, and the rule refers to the list by that ID.

**API**

To create the list with the API, send its body to `/v4/workspace/network_lists` in a `POST` request. Replace `[TOKEN VALUE]` with your personal token:

```bash
curl -X POST https://api.azion.com/v4/workspace/network_lists \
  -H "Authorization: Token [TOKEN VALUE]" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{"name":"Blocked addresses","type":"ip_cidr","items":["192.0.2.10","198.51.100.0/24","2001:db8::/32"]}'
```

The API answers `201` and returns the stored list:

```json
{
  "state": "executed",
  "data": {
    "id": <network-list-id>,
    "name": "Blocked addresses",
    "type": "ip_cidr",
    "items": ["192.0.2.10", "198.51.100.0/24", "2001:db8::/32"],
    "last_editor": "<your-email>",
    "last_modified": "2026-01-01T12:00:00.000000Z",
    "created_at": "2026-01-01T12:00:00.000000Z",
    "active": true,
    "version_id": null,
    "version_state": null,
    "is_versioned": false,
    "version": null
  }
}
```

A `state` of `executed` means that the list is stored already. Its `data.id` is the ID that the rule refers to.

---

## Create the rule that guards the path

The rule holds two criteria in one block. The first, *Network*, carries the conditional `if`. The second, *Request Uri*, carries `and`, which makes it a condition that must also be true. The rule therefore denies a request only when the client is in the list and the path starts with `/admin`. When either criterion is false, the rule runs nothing, and the firewall moves on to its next rule. For how criteria and blocks combine, refer to [Conditionals](/en/documentation/platform/firewall/rules-engine/#conditionals).

**Console**

To create the rule in Azion Console:

1. **Open the firewall bound to your workload**

   Access [Azion Console](https://console.azion.com/) > **Secure** > **Firewalls**. Select the firewall in the list.

2. **Select the Rules Engine tab**

3. **Select Rule**

   The **Create Rule** drawer opens.

4. **Name the rule**

   In the **General** section, enter a **Name**. For example: `Deny listed addresses on /admin`.

5. **Set the Network criterion**

   In the **Criteria** section, select *Network* as the variable and *matches* as the operator.

   The variable reads *Network - required Network Shield* while the firewall has Network Shield off. In that case, go to **Main Settings** > **Modules**, turn on **Network Shield**, and select **Save**. The variable is selectable after the save.

6. **Select the list**

   In the **Select a Network** dropdown, select `Blocked addresses`, the name you gave the list.

7. **Add a second criterion**

   Select **And**. Azion Console adds a criterion to the same block. The rule runs only when that criterion is true as well.

8. **Set the Request Uri criterion**

   In the added criterion, select *Request Uri* as the variable and *starts with* as the operator.

9. **Enter the path**

   As the argument of the added criterion, enter `/admin`.

10. **Add the Deny behavior**

    In the **Behaviors** section, select the *Deny (403 Forbidden)* behavior.

11. **Save the rule**

    Select **Save**.

Azion Console confirms with the message `Rule successfully created`. The rule appears in the **Rules Engine** tab, and its **Status** column reads *Active*.

**CLI**

`azion create firewall-rule` reads the rule from a JSON file. To create the rule with the Azion CLI, save this body as `rule.json`. Put your list ID in place of `<network-list-id>`, as a bare number with no quotes:

```json
{
  "name": "Deny listed addresses on /admin",
  "active": true,
  "criteria": [
    [
      { "variable": "${network}", "conditional": "if", "operator": "is_in_list", "argument": <network-list-id> },
      { "variable": "${request_uri}", "conditional": "and", "operator": "starts_with", "argument": "/admin" }
    ]
  ],
  "behaviors": [
    { "type": "deny" }
  ]
}
```

Then create the rule from the file. Write the ID of the firewall bound to your workload in place of `<firewall-id>`:

```bash
azion create firewall-rule --firewall-id <firewall-id> --file rule.json
```

The CLI prints the ID of the rule it created:

```text
Created Firewall Rule with ID <rule-id>
```

The firewall holds the rule, active, and the rule denies the listed addresses on the paths under `/admin`.

**API**

To create the rule with the API, send its body to `/v4/workspace/firewalls/{firewall_id}/request_rules` in a `POST` request. Write the ID of the firewall bound to your workload in place of `<firewall-id>`. Replace `<network-list-id>` with the `data.id` of the list response, a bare number with no quotes:

```bash
curl -X POST https://api.azion.com/v4/workspace/firewalls/<firewall-id>/request_rules \
  -H "Authorization: Token [TOKEN VALUE]" \
  -H "Accept: application/json" \
  -H "Content-Type: application/json" \
  -d '{
  "name": "Deny listed addresses on /admin",
  "active": true,
  "criteria": [
    [
      { "variable": "${network}", "conditional": "if", "operator": "is_in_list", "argument": <network-list-id> },
      { "variable": "${request_uri}", "conditional": "and", "operator": "starts_with", "argument": "/admin" }
    ]
  ],
  "behaviors": [
    { "type": "deny" }
  ]
}'
```

The API answers `202`, with the rule as the firewall stored it:

```json
{
  "state": "pending",
  "data": {
    "id": <rule-id>,
    "name": "Deny listed addresses on /admin",
    "active": true,
    "criteria": [
      [
        { "conditional": "if", "variable": "${network}", "operator": "is_in_list", "argument": <network-list-id> },
        { "conditional": "and", "variable": "${request_uri}", "operator": "starts_with", "argument": "/admin" }
      ]
    ],
    "behaviors": [{ "type": "deny" }],
    "description": "",
    "order": 0
  }
}
```

The firewall holds the rule. The platform adds an empty `description` and `order`, which is the position of the rule among the rules of the firewall.

> **Note**
>
> The rule body for the CLI and the API holds both criteria in one block. In Azion Console terms, `${network}` is the *Network* criterion and `is_in_list` its *matches* operator. `${request_uri}` is *Request Uri*, and `starts_with` is *starts with*. `deny` is the *Deny (403 Forbidden)* behavior. A firewall with Network Shield off refuses the rule with `25047 Missing Required Modules`. A list ID sent as a string is refused with `25042 Invalid Operator Argument Type`. For the operators of each variable, refer to [Operators](/en/documentation/platform/firewall/rules-engine/#operators) and [The Network criterion](/en/documentation/platform/firewall/network-shield/network-lists/#the-network-criterion).

---

## Confirm that the path denies the listed addresses

Expect the rule to reach traffic 6 minutes 29 seconds to 9 minutes 18 seconds after you create it. A workload bound shortly before can need several minutes for its first rule, and no duration is guaranteed. Until the rule reaches traffic, `/admin` answers the listed addresses as every other path does.

After that, a client in the list receives `HTTP 403` on `/admin` and every path under it. Its body is Azion's default error page, headed **Forbidden**. A request from a listed address to `/admin` gets this response:

```text
$ curl -i https://<your-workload-domain>/admin
HTTP/2 403
server: nginx
date: Thu, 01 Jan 2026 12:00:00 GMT
content-type: text/html; charset=utf-8
x-content-type-options: nosniff
x-azion-request-id: <request-id>
x-azion-edge-location: <edge-location>
alt-svc: h3=":443"; ma=86400

<title>Azion - Default error page</title>
...
<h1 class="error-header__title">Forbidden</h1>
...
Your IP         <your-ip>
Request ID      <request-id>
Status Code     403
Edge Location   <edge-location>
```

The `Your IP` row is the client address that the firewall compared with the list. A request from the same address to a path outside `/admin` passes the rule. It reaches the application, which answers as it does for any client. For the response that a denied client receives, refer to [Deny (403 Forbidden)](/en/documentation/platform/firewall/rules-engine/#deny-403-forbidden).

The *starts with* operator matches every path that begins with its argument. The argument `/admin` therefore also covers `/admin/users` and `/administrator`. To choose the path that a block needs, refer to [Scope a block to the path that needs it](/en/documentation/platform/firewall/best-practices/#scope-a-block-to-the-path-that-needs-it).

A change to the list's items after the rule is live reaches traffic sooner than the rule did: in 46 seconds to about 100 seconds. Meanwhile, one request can reflect the old items and the next one the updated items. Send the request again until the answers agree. For every propagation time, refer to [Propagation](/en/documentation/platform/firewall/how-it-works/#propagation).

---

## Next steps

- [Allow only the addresses in a list](/en/documentation/guides/application-security/bots-and-network/allowlist.md): Reverse the operator of the Network criterion, so that the rule denies every address outside the list.
- [Block requests by IP, ASN, or country](/en/documentation/guides/application-security/bots-and-network/blocklists-ip-addresses-edge.md): Build a list of each type, and deny it on every path in a firewall rule.
- [Network Lists](/en/documentation/platform/firewall/network-shield/network-lists.md): The list types, item formats, and errors behind the list that this guide creates.
- [How Firewall works](/en/documentation/platform/firewall/how-it-works.md#network-shield): Its Network Shield section explains how the Network criterion matches a client address with a list.
- [Firewall guides and tutorials](/en/documentation/platform/firewall/guides.md): The other configurations built on network lists, and every other guide for a firewall.
