Metadata-Version: 2.4
Name: f5audit
Version: 0.2.2
Summary: Read-only audit tool for F5 BIG-IP LTM: finds unused nodes, pools, virtual servers and monitors via iControl REST and produces an Excel report.
Author-email: Israel Fernandez <israelfdzhdz@gmail.com>
License-Expression: MIT
Project-URL: Homepage, https://github.com/netcraftworks/f5audit
Project-URL: Repository, https://github.com/netcraftworks/f5audit
Project-URL: Issues, https://github.com/netcraftworks/f5audit/issues
Keywords: f5,big-ip,ltm,audit,icontrol-rest,network-automation
Classifier: Development Status :: 4 - Beta
Classifier: Environment :: Console
Classifier: Intended Audience :: System Administrators
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.9
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Programming Language :: Python :: 3.14
Classifier: Topic :: System :: Networking
Classifier: Topic :: System :: Systems Administration
Requires-Python: >=3.9
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: requests>=2.25
Requires-Dist: openpyxl>=3.0
Provides-Extra: dev
Requires-Dist: pytest>=7; extra == "dev"
Requires-Dist: ruff>=0.6; extra == "dev"
Dynamic: license-file

# f5audit

[![CI](https://github.com/netcraftworks/f5audit/actions/workflows/ci.yml/badge.svg)](https://github.com/netcraftworks/f5audit/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/f5audit?label=pypi)](https://pypi.org/project/f5audit/)
[![Python](https://img.shields.io/pypi/pyversions/f5audit?label=python)](https://pypi.org/project/f5audit/)

Read-only audit tool for **F5 BIG-IP LTM**. It collects configuration and
statistics via iControl REST (GET only), correlates object references, and
produces a multi-sheet **Excel report** identifying unused objects (nodes,
pools, virtual servers, monitors) as input for a human-driven, change-
controlled cleanup.

**This tool never modifies the device.** The "suggested command" columns in
the report are informational text only; nothing is ever executed.

## Safety design

- The HTTP client (`F5ReadOnlyClient`) exposes a single `get()` method.
  There are no `post`/`patch`/`put`/`delete` methods. The only internal
  write is the token login, hardcoded to `/mgmt/shared/authn/login`.
  This is enforced by structural tests.
- No `tmsh`/bash execution endpoints are used or referenced anywhere.
- No explicit logout (deleting the token would be a write); tokens expire
  on their own (~20 minutes).
- Passwords are read from an interactive prompt (`getpass`) or the
  `F5_PASS` environment variable — never from a CLI argument, and never
  written to disk or logs.
- Management-plane friendly: sequential requests only, `$top`/`$skip`
  pagination, per-request delay (`--delay`, default 0.1 s), 30 s timeout,
  max 2 retries with exponential backoff.

## Requirements

- Python >= 3.9, `requests`, `openpyxl`
- An account with a **read-only role** (Auditor/Guest) and iControl REST
  access on the BIG-IP
- Network access to the management interface (TCP 443)

## Installation

```
pip install f5audit
```

From source: `pip install .` — or without installing, from the project
directory: `python -m f5audit ...`

## Usage

### 1. Validate access first

```
f5audit validate --host 192.0.2.1 --user auditor --insecure
```

Probes login plus the key GET endpoints and prints a diagnosis per
response code (bad credentials, missing REST access, denied endpoints,
old BIG-IP versions, network timeouts).

### 2. Collect once, analyze offline N times

```
f5audit collect --host 192.0.2.1 --user auditor --insecure --save-raw ./raw/
f5audit analyze --from-raw ./raw/ --out report.xlsx
```

`collect` saves every raw JSON response (with timestamps) to disk;
`analyze --from-raw` re-analyzes from that cache **without touching the
F5 again**. This is the recommended workflow: one collection per session,
all further analysis offline.

### One-step alternative

```
f5audit analyze --host 192.0.2.1 --user auditor --insecure --save-raw ./raw/ --out report.xlsx
```

### Options

| Flag | Meaning |
|---|---|
| `--user` / `F5_USER` | Username (password via prompt or `F5_PASS`) |
| `--login-provider` | Token auth provider (default `tmos`; set for TACACS+/RADIUS) |
| `--insecure` | Skip TLS verification (self-signed mgmt certs); prints a warning |
| `--delay` | Seconds between requests (default 0.1) |
| `--top` | Pagination page size (default 100) |
| `--format xlsx\|csv` | Excel workbook or one CSV per sheet |
| `--allow-standby` | On a standby unit, emit traffic- and availability-based verdicts marked `UNRELIABLE (standby)` instead of skipping them |

Exit codes: `0` OK · `1` connection/auth error · `2` analysis completed
with warnings (standby device, denied partitions, missing endpoints).

## Verdicts

| Verdict | Meaning |
|---|---|
| `ORPHAN` | Not referenced by anything (node: no pool membership; pool: no VS/iRule/policy reference; monitor: no user). Only issued when the inventory is complete and no attached dynamic iRule can reach the object (see `MANUAL REVIEW`). |
| `MANUAL REVIEW` | A dynamic iRule (`pool $var`, `pool [...]`, datagroups) or a missing `ltm/rule` endpoint means the object *could* be referenced at runtime. Never auto-cleanup these. A dynamic iRule attached to a virtual server reaches the pools of its own partition, the VS's partition, `/Common`, and any partition named literally (`/Partition/...`) in its Tcl; pools in other partitions are not affected, and nodes inherit the reach of their pools. |
| `INACTIVE` | Configured and referenced, but disabled or zero total connections since the last counter reset. |
| `OFFLINE (decommission candidate)` | Referenced, but the whole dependency chain is monitor-offline: every member of the pool is down, so the pool and its virtual servers are offline. A deletion candidate to confirm with the config owner — availability is point-in-time, so it may also mean maintenance. A node is only included when it is dead in **every** pool it belongs to; a node alive in another pool stays `IN USE` ("in use elsewhere"). Only issued on the ACTIVE unit; capped at `MANUAL REVIEW` when an attached dynamic iRule can reach the pool. |
| `UNRELIABLE (standby)` | Traffic-based verdict computed on a standby unit (only with `--allow-standby`). |
| `UNRELIABLE (incomplete inventory)` | Some partitions were not readable; a reference could exist in an invisible partition. |
| `IN USE` | Everything else. |

## Operational warning

- **Collect on the ACTIVE unit** of the HA pair. On a standby unit traffic
  counters are zeros and the tool will skip traffic analysis (or mark it
  `UNRELIABLE` with `--allow-standby`).
- Traffic counters reset on reboot / stats reset. Ideally collect after
  **several weeks of uptime**; the report includes the failover-state age
  as context.
- `INACTIVE` means "no traffic since the counters started", not "safe to
  delete". Use the planned `compare` workflow (v2) — two collections some
  weeks apart — to distinguish real zero traffic from a recent reset.
  The raw cache already stores per-file timestamps to enable this.
- Availability is **point-in-time**: an `OFFLINE` chain reflects monitor
  state at collection time and may mean maintenance rather than
  decommissioning. Always confirm with the config owner before requesting
  deletion.

## Report sheets

1. **Summary** — hostname, version, HA state, uptime context, partitions,
   verdict counts, active warnings.
2. **Inventory** — one row per pool member (plus rows for pool-less
   nodes), fully correlated: node ↔ pool ↔ virtual server ↔ monitor ↔
   iRule/policy references, statuses, traffic and verdict. Two columns
   concern iRules and are not expected to match: `VS iRules` is
   configuration (the iRules attached to the row's virtual servers — in
   F5, iRules only attach to virtual servers), while `iRules selecting
   pool` is code analysis (every iRule whose Tcl contains `pool <this
   pool>`, whichever virtual server it is attached to). The latter, with
   `Policies forwarding to pool`, is the evidence that keeps a pool with no
   default-pool reference from being `ORPHAN`.
3. **Orphan Nodes** · 4. **Orphan-Inactive Pools** (with the same
   `iRules selecting pool` / `Policies forwarding to pool` evidence
   columns) · 5. **Inactive Virtual Servers** (with the attached
   `iRules`) — filtered views with informational `tmsh` commands for the
   change request.
6. **Dead Chains** — one row per pool with an
   `OFFLINE (decommission candidate)` verdict, grouping the whole chain
   (virtual servers → pool → member nodes) with per-object verdicts and
   the informational `tmsh delete` lines to take to the config owner.
   Nodes still alive in another pool get no delete line here.
7. **Orphan Monitors** — filtered view with informational `tmsh`
   commands.
8. **Manual Review** — objects touched by dynamic logic, with the
   iRule/policy that causes the doubt.

Color coding: red = ORPHAN · yellow = MANUAL REVIEW / UNRELIABLE ·
orange = INACTIVE · purple = OFFLINE · green = IN USE.

## Development

```
pip install -e ".[dev]"
ruff check f5audit tests && ruff format --check f5audit tests
pytest
```

No test touches the network; everything runs from anonymized JSON
fixtures and mocked HTTP sessions. Structural tests assert the client
exposes no write verbs and that no forbidden endpoint appears in the
source. CI runs lint plus the test suite on Python 3.9 through 3.14;
all checks must pass before a PR can merge.

Releases are published to PyPI automatically: bump `__version__` in
`f5audit/__init__.py`, merge, and create a GitHub release tagged
`v<version>`. The release workflow verifies the tag matches the package
version, builds, and publishes via PyPI Trusted Publishing (no stored
API tokens).
