# F5 BIG-IP iRules

> Deploy Centinel Analytica on F5 BIG-IP load balancers using iRules for bot detection.

Source: https://docs.centinelanalytica.com/platforms/cdn-edge/f5-bigip

## Overview

The Centinel iRule runs on your F5 BIG-IP, calls the Centinel API for each request, and blocks or challenges traffic based on the response.

## Prerequisites

* Centinel secret key (from your dashboard)
* F5 BIG-IP device with LTM module (v11.5+ recommended)
* SSH or TMSH access to the F5 device
* BIG-IP local caching nameserver (BIND) that resolves `validator.centinelanalytica.com`

> **DNS resolver required:** The iRule uses `RESOLV::lookup` without an explicit nameserver to resolve `validator.centinelanalytica.com`. BIG-IP sends this lookup to its local caching nameserver (BIND).
>
> Configure the local caching nameserver to resolve the API hostname. A shell DNS test does not test the iRule DNS path.

## Install

1. **Download and extract the iRule package**

   Download [centinel-f5-irules.zip](https://docs.centinelanalytica.com/downloads/centinel-f5-irules.zip) and extract it:

   ```bash
   curl -O https://docs.centinelanalytica.com/downloads/centinel-f5-irules.zip
   unzip centinel-f5-irules.zip
   ```

   The zip contains:

   * `Centinel.tcl` — the main iRule, with the API integration
   * `Centinel-SSL-Helper.tcl` — the SSL connection handler

2. **Upload the iRule files**

   Log into your F5 BIG-IP management interface and upload both iRule files:

   **Via Web UI:**

   1. Navigate to **Local Traffic → iRules → iRules List**
   2. Click **Create**
   3. Enter name: `Centinel`
   4. Paste the contents of `Centinel.tcl`
   5. Click **Finished**
   6. Repeat for `Centinel-SSL-Helper` with `Centinel-SSL-Helper.tcl`

   **Via TMSH:**

   ```bash
   # Copy files to BIG-IP first
   scp Centinel.tcl Centinel-SSL-Helper.tcl root@<bigip-mgmt-ip>:/var/tmp/

   # Wrap and load each iRule
   { echo 'ltm rule Centinel {'; cat /var/tmp/Centinel.tcl; echo '}'; } > /var/tmp/Centinel.conf
   tmsh load sys config merge file /var/tmp/Centinel.conf

   { echo 'ltm rule Centinel-SSL-Helper {'; cat /var/tmp/Centinel-SSL-Helper.tcl; echo '}'; } > /var/tmp/Centinel-SSL-Helper.conf
   tmsh load sys config merge file /var/tmp/Centinel-SSL-Helper.conf
   ```

3. **Configure your API key**

   Edit the `Centinel` iRule and update the secret key on line 8:

   ```tcl
   # Replace with your actual API key
   set static::CENTINEL_SECRET_KEY "sk_live_your_key_here"
   ```

   **Via Web UI:**

   1. Navigate to **Local Traffic → iRules → iRules List**
   2. Click on `Centinel`
   3. Click **Edit**
   4. Update line 8 with your secret key
   5. Click **Finished**

   **Via TMSH:**

   ```bash
   tmsh edit ltm rule Centinel
   # Update the key, then save and exit
   ```

4. **Create the API virtual server**

   Create a virtual server for making outbound HTTPS calls to the Centinel API:

   **Via Web UI:**

   1. Navigate to **Local Traffic → Virtual Servers → Virtual Server List**
   2. Click **Create**
   3. Configure:
      * **Name**: `centinel_api_ssl_vs`
      * **Destination Address/Mask**: `0.0.0.0/0` (any)
      * **Service Port**: `443`
      * **Protocol**: `TCP`
      * **HTTP Profile (Client)**: `http`
      * **SSL Profile (Server)**: `serverssl-insecure-compatible`
      * **Source Address Translation**: `Auto Map`
      * **Address Translation**: `Enabled`
      * **Port Translation**: `Enabled`
   4. Click **Finished**

   > **Upstream TLS behavior:** The SSL helper sends `validator.centinelanalytica.com` in SNI.
   >
   > These instructions do not configure a trusted CA, require a server certificate, or set an Authenticate Name. The supplied setup does not authenticate the API certificate or hostname.
   >
   > If the API call fails, the main iRule allows the application request.

   **Via TMSH:**

   ```bash
   tmsh create ltm virtual centinel_api_ssl_vs \
       destination 0.0.0.0:443 \
       ip-protocol tcp \
       mask 0.0.0.0 \
       profiles add { tcp http { context all } serverssl-insecure-compatible { context serverside } } \
       source 0.0.0.0/0 \
       source-address-translation { type automap } \
       translate-address enabled \
       translate-port enabled
   ```

5. **Apply SSL helper to API virtual server**

   Attach the `Centinel-SSL-Helper` iRule to the API virtual server:

   **Via Web UI:**

   1. Navigate to **Local Traffic → Virtual Servers**
   2. Click on `centinel_api_ssl_vs`
   3. Go to **Resources** tab
   4. Under **iRules**, click **Manage**
   5. Move `Centinel-SSL-Helper` from Available to Enabled
   6. Click **Finished**

   **Via TMSH:**

   ```bash
   tmsh modify ltm virtual centinel_api_ssl_vs rules { Centinel-SSL-Helper }
   ```

6. **Apply main iRule to application virtual server**

   Attach the `Centinel` iRule to your application's virtual server(s):

   **Via Web UI:**

   1. Navigate to **Local Traffic → Virtual Servers**
   2. Click on your application virtual server (e.g. `www_vs`)
   3. Go to **Resources** tab
   4. Under **iRules**, click **Manage**
   5. Move `Centinel` from Available to Enabled
   6. Click **Finished**

   **Via TMSH:**

   ```bash
   tmsh modify ltm virtual your_application_vs rules { Centinel }
   ```

   > **Note:** The `Centinel` iRule can be applied to multiple virtual servers.

7. **Save configuration**

   Save your changes to persistent storage:

   **Via Web UI:** Click **System → Configuration → Save Configuration**

   **Via TMSH:**

   ```bash
   tmsh save sys config
   ```

## Configure

### Advanced configuration

**Path filtering**

#### URI path filtering

By default, static assets (images, CSS, JS, fonts) are excluded from validation for better performance.

##### Exclude additional paths

Edit `CENTINEL_URI_REGEX_EXCLUSION` (line 28) to skip more paths:

```tcl
# Example: Exclude health checks and metrics
set static::CENTINEL_URI_REGEX_EXCLUSION {(?i)\.(avi|flv|mka|mkv|mov|mp4|mpeg|mpg|mp3|flac|ogg|ogm|opus|wav|webm|webp|bmp|gif|ico|jpeg|jpg|png|svg|svgz|swf|eot|otf|ttf|woff|woff2|css|less|js)$|^/health$|^/metrics$}
```

##### Protect only specific paths

Add `CENTINEL_URI_REGEX` to validate only certain paths (unset by default, meaning all paths are checked):

```tcl
# Only protect paths starting with /api/ or /admin
set static::CENTINEL_URI_REGEX {^/(api|admin)/}
```

**Timeouts**

#### Timeout configuration

Adjust API timeout for your network. Default is 150ms.

```tcl
set static::CENTINEL_timeout 300
```

**Logging**

#### Debug logging

Enable detailed logging for troubleshooting:

Edit the `Centinel` iRule and set these variables:

```tcl
# Enable debug logging
set static::CENTINEL_LOG_REQUEST_HEADERS 1
set static::CENTINEL_LOG_RESPONSE_HEADERS 1
set static::CENTINEL_LOG_REQUEST_TIME 1
```

View logs:

```bash
# Real-time log monitoring
tail -f /var/log/ltm | grep CENTINEL

# Search for errors
grep "CENTINEL ERROR" /var/log/ltm
```

For high-traffic environments, use High-Speed Logging (HSL) to avoid flooding the local log:

```tcl
set static::CENTINEL_LOG_PUBLISHER "/Common/remote_log_publisher"
```

**Performance**

#### Performance optimization

1. Connection pooling is automatic — the iRule reuses TLS connections to the Centinel API across requests. No configuration needed.

2. Raise the connection limit on the API virtual server if needed:
   ```bash
   tmsh modify ltm virtual centinel_api_ssl_vs connection-limit 10000
   ```

3. Apply the iRule to multiple F5 devices in an HA pair or cluster — each device maintains its own connection pool.

### Configuration reference

#### Main iRule variables

Edit these in the `Centinel` iRule (inside `when RULE_INIT`):

| Variable                        | Default                       | Description                                                                              |
| ------------------------------- | ----------------------------- | ---------------------------------------------------------------------------------------- |
| `CENTINEL_SECRET_KEY`           | (required)                    | Your API key from Centinel dashboard                                                     |
| `CENTINEL_MODULE_VERSION`       | `1.1.1`                       | Module version (informational)                                                           |
| `CENTINEL_vs`                   | `/Common/centinel_api_ssl_vs` | Name of API virtual server                                                               |
| `CENTINEL_timeout`              | `150`                         | API timeout in milliseconds                                                              |
| `CENTINEL_URI_REGEX`            | (unset)                       | Regex pattern for paths to validate. Unset validates all paths                           |
| `CENTINEL_URI_REGEX_EXCLUSION`  | (see code)                    | Regex pattern for paths to skip                                                          |
| `CENTINEL_HEADER_WHITELIST`     | (see code)                    | List of HTTP headers sent to API (customizable)                                          |
| `CENTINEL_LOG_REQUEST_HEADERS`  | `0`                           | Log outbound request headers (0=off, 1=on)                                               |
| `CENTINEL_LOG_RESPONSE_HEADERS` | `0`                           | Log API response headers (0=off, 1=on)                                                   |
| `CENTINEL_LOG_REQUEST_TIME`     | `0`                           | Log request timing (0=off, 1=on)                                                         |
| `CENTINEL_LOG_PUBLISHER`        | (unset)                       | High-Speed Logging publisher. Unset logs to `/var/log/ltm`                               |
| `CENTINEL_LOG_POOL`             | (unset)                       | UDP syslog pool for High-Speed Logging. Used only when `CENTINEL_LOG_PUBLISHER` is unset |

## Verify

1. **Verify the API DNS lookup**

   The iRule resolves `validator.centinelanalytica.com` through the BIG-IP local caching nameserver (BIND).

   Send a test request to your application. Then confirm that the request appears in the Centinel dashboard.

   The command `run /util dig validator.centinelanalytica.com` tests the shell resolver. It does not test the TMM `RESOLV::lookup` path.

   The application request can still succeed when the API DNS lookup fails. The iRule fails open for an unavailable API response.

2. **Test the integration**

   1. **Check logs**: Monitor for Centinel activity
      ```bash
      tail -f /var/log/ltm
      ```

   2. **Test normal traffic**: Visit your application to confirm requests work normally

   3. **Check statistics**: View iRule execution stats
      ```bash
      tmsh show ltm rule Centinel
      ```

   4. **Monitor Centinel dashboard**: Verify requests appear in your Centinel dashboard

## Changelog

* **v1.1.1** — F5 string limit fix
* **v1.1.0** — Performance optimizations
* **v1.0.5** — Send all headers
* **v1.0.3** — TLS connection reuse
* **v1.0.2** — TCL 8.4 compatibility
* **v1.0.0** — Initial release
