← Back to projects
OT asset visibility · Active learning project

Building a Flask-Based OT Network Asset Inventory

A practical learning project for recording OT devices, classifying them by network zone and Purdue level, and creating a foundation for future device interaction with Netmiko.

Read the article GitHub repository coming soon
Current stageWorking Flask application
Primary purposeStructured OT asset records
Next directionNetmiko-assisted validation
PythonFlaskSQLAlchemySQLiteBootstrap
Current application build
Bright OT IP Inventory dashboard with links to register and review industrial assets

Dashboard for registering assets and reviewing the OT inventory.

Turning a device list into a structured OT engineering record

I have started building a small OT network inventory application with Flask. The immediate goal is deliberately simple: understand the complete path from an HTML form to validation, a Python object, a database record, and a useful page for the engineer.

This is an educational application that I am rebuilding and extending step by step. Keeping the code clear is more important than adding complexity too early. The project gives me a practical way to strengthen my understanding of Flask while working on a subject directly connected to industrial networking and OT cybersecurity.

FlaskApplication and routes
SQLiteLocal inventory data
3 rolesViewer, editor, admin
NextNetmiko interaction

Why asset inventory matters in an OT network

An organisation cannot protect, maintain, or recover equipment it does not know it has. This is especially important in OT, where network switches, firewalls, PLCs, HMIs, SCADA servers, historians, engineering workstations, and supporting infrastructure may remain in service for many years.

A useful OT inventory is more than a list of IP addresses. It should help an engineer answer practical questions:

  • What is connected to the industrial network, and where is it located?
  • Which vendor and model are in service, and how can the physical unit be identified?
  • Which site, VLAN, Purdue level, and security zone does the asset belong to?
  • Is the asset active, under maintenance, inactive, or decommissioned?
  • Which systems may be affected by a vulnerability, failure, or proposed change?

This information supports vulnerability management, maintenance planning, segmentation reviews, incident response, lifecycle decisions, and recovery priorities. It also gives engineering and cybersecurity teams a shared reference instead of relying on disconnected spreadsheets, diagrams, and personal knowledge.

Inventory and taxonomy belong together

Recent joint guidance led by CISA describes an OT inventory as a regularly updated record and recommends supplementing it with a taxonomy that classifies assets by function and criticality. The Purdue level and zone fields in this learning project are an early step towards that richer operational context.


What the application can do today

The current version has moved beyond a static interface. It now provides a working database-backed workflow with authentication and role-aware actions.

01Create an inventory record

Validated forms capture identity, addressing, manufacturer, location, classification, status, and notes.

02Review the complete inventory

A single table presents the key identity, network, site, Purdue, zone, and status fields.

03Open and update an asset

Detail and edit views separate routine review from controlled record maintenance.

04Control application access

Authentication and viewer, editor, and administrator roles restrict sensitive actions.

The application uses an application factory, a Flask blueprint, SQLAlchemy models, Flask-Migrate database migrations, Flask-WTF forms, password hashing, login sessions, and Bootstrap templates. SQLite keeps the learning environment lightweight while the data model develops.


Following one asset through the application

The project has helped me understand that a new field must be connected through every layer. For example, adding the subnet prefix required a model column, a validated WTForms field, route handling, a migration, and an explicit Jinja output.

A value starts in the device form, is checked before submission, is handled by the appropriate Flask route, and is then stored in the database. The inventory and asset-detail pages deliberately select how that information is presented back to the engineer.

The current form accepts IPv4 addresses and prefix lengths from 0 to 32. IP addresses are unique, which prevents two inventory records from silently claiming the same address. Later versions can extend the design for IPv6 and introduce stronger rules for naming, sites, zones, and lifecycle data.

Bright Add OT device form with identity, addressing, status, and manufacturer fields
Structured input: the add-device form captures known asset information and explains required values such as the subnet prefix.

Keeping OT information readable

The interface follows the same Bootstrap-based design direction as my Engineering Change Request project. This is intentional: the two applications may eventually form part of a wider engineering toolkit, so their navigation, cards, forms, status labels, and page structure should feel consistent.


Adding authentication and role-based access

An inventory contains operationally useful information, so even a learning application should not treat every visitor as an administrator. The current version supports three straightforward roles:

Viewer

Can sign in, review the inventory, and open device details without add or edit controls.

Editor

Can review records and create or update OT assets as part of inventory maintenance.

Administrator

Can maintain assets and create authorised viewer, editor, or administrator accounts.

The interface hides unavailable actions, while the Flask routes also enforce the role requirement on the server. This distinction matters: hiding a button improves the user experience, but server-side authorisation provides the actual control.


What this stage has taught me

  • A database model describes what Python expects, but migrations change the physical database structure.
  • Forms should validate data before the route creates or updates an object.
  • Template variable names must match the values passed by the route.
  • Each database field must be deliberately presented in the user interface.
  • Authorisation must be enforced at the route as well as reflected in the page.
  • A useful OT record needs operational context, not only a hostname and IP address.

These are basic lessons, but they are exactly why I am keeping the application small and understandable. Repeating the full workflow is helping me build confidence with Flask rather than only copying a finished structure.


From a manual inventory to Netmiko-assisted validation

The next major direction is interaction with supported network assets through Netmiko. The inventory can become the source of connection targets, while a controlled collection process retrieves selected read-only facts from switches, routers, and firewalls.

A future service could compare declared inventory data with observed device data—for example hostname, platform, software version, interface state, and serial number—and record when the information was last checked. The first implementation will stay narrow, use approved read-only commands, and avoid storing credentials directly in an asset record.

Near-term

Improve account administration, tests, error handling, filtering, search, exports, and audit history.

Network interaction

Add read-only Netmiko collection, supported platform profiles, safe credential handling, and last-checked evidence.

Inventory quality

Detect differences between declared and observed facts without silently overwriting an engineer-approved record.

Wider toolkit

Explore connections with change control so that significant inventory changes can be reviewed and evidenced.

Active discovery in OT must be introduced carefully. Device capability, process sensitivity, approved commands, rate limits, maintenance windows, logging, and ownership all need to be understood before automation touches production equipment. The lab will therefore remain the proving ground for this feature.


Guidance informing the project

This learning project is not intended to replace a production-grade asset-management platform. Its design direction is informed by broader industry guidance on building and maintaining OT visibility:

A working foundation, built one understandable step at a time.

The source repository link will be added after the project is placed under version control and published.