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.
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.
As of Nov 2016 pfweb is under initial development. Use at your own risk.
- 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 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
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
You'll need to install flup, the FastCGI server:
$ pip install flup
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 /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.
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
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
There are a few ways we can accomplish creating the username and password:
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
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')
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 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
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.