pfweb
pfweb is a python web application to manage the OpenBSD Packet Filter (PF). It uses py-pf to interface with PF and Flask for the web framework. The look and feel is based on pfSense and a lot of the ideas are ripped off from them.
Warning!
There are a lot of people that would say running a web interface for PF is a bad idea. There are many reasons why, but here are a couple good ones:
- Security: Running pfweb requires the user running the application to have write access to /dev/pf to make changes. This gives access to the kernel.
- Features: When using a web application to manage PF instead of just modifying pf.conf, you lose massive amounts of powerful features and flexibility.
So why would use you use pfweb? Maybe a home network or an already secured lab. I don't judge though, use it how you want. I've had fun making it as well.
Development
As of Nov 2016 pfweb is under initial development. Use at your own risk.
Dependencies
- OpenBSD 6.0+: Only tested on OpenBSD 6.0 amd64
- py-pf: Python module for managing OpenBSD's Packet Filter
- Flask: A microframework for Python based on Werkzeug and Jinja 2
- Flask-Login: User session management for Flask
Installation
Installation under a virtualenv will work fine.
pfweb utilizes the well written py-pf module. The version in PyPi is not up to date so you'll need to clone from the py-pf github repo and install.
$ git clone https://github.com/dotpy/py-pf.git
$ cd py-pf
$ python setup.py install
pfweb is under heavy development right now, so it is probably best to clone from github. First install Flask and Flask-Login then install pfweb.
$ pip install Flask flask-login
$ git clone https://github.com/nahun/pfweb.git
$ cd pfweb
$ python setup.py install
Or if the version on PyPi is actually current you can use pip:
$ pip install pfweb
Setup
After installation, you'll have to decide how you want to run it. There are many options for python web applications such as FastCGI, mod_wsgi, uWSGI, etc... You can refer to Flask's documentation for more detail, but this guide will concentrate on FastCGI, flup, and OpenBSD's httpd
Install flup
You'll need to install flup, the FastCGI server:
$ pip install flup
Create the FastCGI Server
Then you need to create a FastCGI server file such as pfweb.fcgi:
from flup.server.fcgi import WSGIServer
import pfweb
if __name__ == '__main__':
WSGIServer(pfweb.app, bindAddress='/var/www/run/pfweb.sock').run()
Make sure the socket file path is in httpd's chroot of /var/www otherwise httpd won't be able to read it.
Setup httpd
Setup /etc/httpd.conf
to use the fastcgi socket and listen on your IP. Edit
the certificate paths with your own.
domain="example.com"
server $domain {
listen on 1.2.3.4 port 80
block return 301 "https://$SERVER_NAME$REQUEST_URI"
}
server $domain {
listen on 1.2.3.4 tls port 443
fastcgi socket "/run/pfweb.sock"
tls {
certificate "/etc/ssl/example.com.crt"
key "/etc/ssl/private/example.com.key"
}
}
Remember, httpd runs in a chroot under /var/www so set your fastcgi socket accordingly.
PF Permissions
You'll need to give a user access to /dev/pf and /etc/pf.conf so we don't run anything as root. Create or use whichever group you want, we'll use pfweb. Also make sure the user running your webserver and FastCGI server is a member of that group.
# chown root:pfweb /dev/pf /etc/pf.conf
# chmod g+rw /dev/pf /etc/pf.conf
Create a Config File
Now lets create the config file and username and password used to login to pfweb. The pfweb.ini file can exist at:
- ~/.pfweb.ini
- /etc/pfweb.ini
- /usr/local/etc/pfweb.ini
pfweb will choose from that order. There are two required parameters that you must set manually, the Flask secret_key used in sessions and a salt to hash the password we'll be setting for authentication. Create the pfweb.ini with random strings used for these two parameters.
[main]
secret_key = longrandomstring
salt = anotherrandomstring
Create a Username and Password
There are a few ways we can accomplish creating the username and password:
create_user.py
1. Use The script is distributed in the package so you will need to find it in your installation or just download it from the repo.
$ python create_user.py
Enter username: admin
Enter Password:
Confirm Password:
User tester created successfully
2. pfweb Config() manually
You can import the pfweb Config object and create the credentials manually:
>>> from pfweb.config import Config
>>> c = Config()
>>> c.create_user('your_username', 'your_password')
3. Manually hash your password
Using python you can hash your password and enter it in manually to the config file. This will hash the password the same way the Config.create_user() method does.
>>> import hashlib, binascii
>>> salt='your_salt'
>>> password='your_password'
>>> dk = hashlib.pbkdf2_hmac('sha256', password.encode(), salt.encode(), 100000)
>>> binascii.hexlify(dk)
'26383a0418be31cb6906418b367e19eb404cb8296e8f03521244b21cc079b82c'
Copy that hash and paste it into your config file with your username:
[main]
secret_key = longrandomstring
salt = anotherrandomstring
username = admin
password = 26383a0418be31cb6906418b367e19eb404cb8296e8f03521244b21cc079b82c
Run the servers
Run the FastCGI server and (re)start httpd. The httpd_flags="" command is obviously optional if you already have it running. Make sure to run the FastCGI server as the correct user that has access to PF.
$ python pfweb.fcgi
# echo httpd_flags="" >> /etc/rc.conf.local
# rcctl restart httpd
You should now be able be able to reach pfweb in your browser
Considerations
FastCGI Process Managers
Just as the
Flask docs
say, you may want to use a process manager for your FastCGI server.
Supervisor
works and OpenBSD has a package. Install with pkg_add supervisor
then create
a config file at /etc/supervisord.d/pfweb.ini
[fcgi-program:pfweb]
socket=unix:///var/www/run/pfweb.sock
command=/path/to/python /path/to/pfweb.fcgi
socket_owner=www
user=www
process_name=%(program_name)s_%(process_num)02d
numprocs=5
autostart=true
autorestart=true
Edit /etc/supervisord.conf
and uncomment the two lines at the end:
[include]
files = supervisord.d/*.ini
Restart supervisord and you should be good to go.