Skip to content
Snippets Groups Projects
user avatar
Vesely, Petr authored
30991b82

Portmanager

Django-based web application for centralized configuration of network device access ports.

1 Background

Purpose of this project is to create web tool for viewing/configuration of basic parameters of access ports on network devices (description, VLAN, status, portsec, PoE output, connected MAC addresses), that could serve people with some basic knowledge of computer networks to manage their network devices without using CLI of various device manufacturers. System is currently is able to manage selected devices manufactured by Cisco, HP and Juniper.

2 Install

2.1 Prepare the environment

Application itself is running inside dockerized environment, but you need to complete few steps to get it running.

2.1.1 Docker

2.1.2 Docker Compose

2.1.3 TFTP server

  • Needed for applying default configurations into Cisco devices.
  • Install TFTP on same server where you want to deploy the application.
  • Default location for files is /srv/tftp. You can change it inside Dockerfile and docker-compose *.yml files if you prefer different location.

Configure TFTP server for file creation with TFTP_OPTIONS as you can see in the example below, allow traffic to the server and test if it runs correctly.

# /etc/default/tftpd-hpa

TFTP_USERNAME="tftp"
TFTP_DIRECTORY="/srv/tftp"
TFTP_ADDRESS="0.0.0.0:69"
TFTP_OPTIONS="--ipv4 --secure --create"

2.1.4 Webserver

  • You can run the application behind webserver of your choice, application is exposed on localhost:8888.
  • If you use production-compose.yml application will expect HTTP_X_REMOTE_USER header passed from the webserver (used for passing authenticated user ID from SSO).
  • Feel free to modify webapp/switches/users.py to match it to your user authentication.
  • To test logging in of different users, use production-compose.yml and change the DEBUG_USR inside config/environment/development.env

2.2 Build the containers

Automated build and deployment process is described in .gitlab-ci.yml file. Lets go through the file structure and process of manual build:

2.2.1 Base image

Dockerfile_base builds base image with prerequisites that don't often change, like Python, NetSNMP with Python bindings, vim, etc. so usually, you run this build phase only if you need to update some of these packages.

2.2.2 Main image

The main Dockerfile of the project is used to do the best. It creates necessary directory structure, downloads Python packages and copies code of the application.

2.2.3 Docker Compose

  • For production/staging deployments, use production-compose.yml file, it fetches the already built image from GitLab and redis image from the Docker Hub. Use docker login before trying to pull the remote images.
  • For development, use devel-compose.yml file, it builds an image locally and also maps code from a local machine (don't forget to modify file paths to match them to your devel environment).
  • Container for main appication consumes approx. 1.12 GB, Redis without data approx. 104MB. It should not be a problem, but check if you have enough disk space for that.

2.2.4 Docker & Docker Compose examples

$ docker-compose -f PathToYmlFile build    # build images with specified *.yml file
$ docker-compose up [-d]                   # run in foregroud/background
$ docker-compose logs --follow             # see logs for debugging purposes
$ docker-compose down                      # stop and remove containers
$ docker image prune -a                    # empty space by removing all images not referenced by any container
$ docker exec -it "container" /bin/bash    # execute commands inside

3 Configuration

3.1 Project structure

├── config                  # files needed for configuration
├── webapp                  # code of the application
├── devel-compose.yml       # docker-compose setup with container orchestration instructions for development
├── Dockerfile              # docker setup for building the webapp
├── Dockerfile              # base docker setup of basic container with dependencies to speedup build
├── LICENSE                 # license for this project
├── production-compose.yml  # docker-compose setup with container orchestration instructions for prod environment
└── README.md               # this file

3.2 Database

Application uses sqlite3 database, for production-compose.yml it creates var/data/data.db on host system. You can change the path in yml file and other settings in webapp/portmanager/settings.py:

DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.sqlite3',
        'NAME': '/srv/data/data.db',
        'USER': '',                      # Not used with sqlite3.
        'PASSWORD': '',                  # Not used with sqlite3.
        'HOST': '',
        'PORT': '',
        }
}

Migrations are not automated for now, so you have to run them manually by following commands:

$ python manage.py makemigrations
$ python manage.py migrate

3.3 Network traffic between the system and devices

To ensure that system will, you need to allow traffic between the system and your network devices. For basic functions, allow SNMP and configure it on your network devices.

Following sections will go through the special needs for different brands caused by different behaviour, security policies and implementation of SNMP:

3.3.1 Cisco

  • Uses SNMP for the most of the actions.
  • It is not possible to set everything via SNMP, Cisco does not allow setting all PortSec parameters via SNMPSet. To bypass that, applying default port configuration is done by getting whole running-config via TFTP, making changes locally and then uploading changed config back.
  • If you want to be able to set arbitrary default config, allow TFTP traffic

Configuration examples:

# Allow SNMP via access-list
ip access-list standard SNMP_portmanager
 permit "IP address of the Portmanager server"    
 deny   any

# Set SNMP community and mode to RW
snmp-server community "SNMP_Community" RW SNMP_portmanager 

3.3.2 Juniper

  • Because of its security policies, Juniper does not allow changing device parameters via SNMP, so SNMP is used only for getting basic information about ports.
  • All set methods are implemented by NetConf, so it is also necessary to allow NetConf network traffic between the system and network devices.

Configuration examples:

# Set login with user portmanager (mandatory) and SSH key
system {
    login {
        user portmanager {
            uid "SomeUIDNum";
            class super-user;
            authentication {
                ssh-rsa "ssh-rsa SomeKeyData user@example.com"; ## SECRET-DATA
            }
        }
  ...
# Allow NetConf for applying changes 
system{
    services {
        netconf {
            ssh;
        }
  ...
# Set SNMP
snmp {
    location "SomeLocation";
    contact "SomeContact";
    community "SNMPCommunity" {
        authorization read-write;
        clients {
            "Portmanager IP address"/32;
        }
    }
}
  ...
# Allow SNMP traffic
  ...
term SNMP {
            from {
                source-address {
                    "Portmanager IP address"/32;
                }
                protocol udp;
                destination-port snmp;
            }
            then accept;
        }    
  ...       

3.3.3 HP Procurve

  • Only SNMP needed for all of the actions.

4 Development

4.1 Add modules for supporting new device type

Inside webapp/switches/switch_modules/ are current implementations for Cisco, HP and Juniper devices. If you need to add new, create new python file inside that directory, create class based on GeneralSwitch and customize methods that are not common with methods written inside the GeneralSwitch class.

4.1 Translation to different language

System uses I18N for Django. Primary language for the whole system is english. For different localization, you need to generate and compile locale files inside webapp/portmanager_project/locale/ folder and upddate Django configuration.

For now, project is also translated into czech, below are commands used for generating and compiling locale files:

# create files for specified language, use -d djangojs for javascript files
$ django-admin makemessages -d djangojs -l cs --ignore="staticfiles/*"  --ignore="node_modules/*"
# compile *.po files into *.mo
$ django-admin compilemessages