Monitor OpenVPN Client Activity using Python

DevOps Engineer | Kubernetes | Python | Terraform | AWS | GCP
Search for a command to run...

DevOps Engineer | Kubernetes | Python | Terraform | AWS | GCP
No comments yet. Be the first to comment.
Tired of shuffling USB cables every time someone in your household or small office needs to print? Wish you could print wirelessly from any device on your network? Well, you're in luck! With the magic of a Raspberry Pi and a few simple commands, you ...

It is quite common to lose the integrity of configmaps/secrets for the following reasons: You have a large team with more than 5 people You do not use any Config/Secret Management Tool Lack of team collaboration Anyway, that's not the point. All...

It's quite common to see your important service account being modified by someone. Don't worry, my friend. Here is how you can track who did what. Login to GCP and navigate to Logging Set a proper timeline from the date-time picker (last X hour or ...

You can speed up your smart tv experience by disabling some annoying, built in apps. First, enable ADB on your Android TV unit. To Activate Developer Options: Navigate to Settings > About. Tap Build number seven times to enable developer mode. Once d...

If you need to automate the process of clicking a button on a webpage using Selenium, this guide will walk you through it effortlessly. Prerequisites You will need the following items. Python3 with selenium module Chrome Browser and Chrome Driver [...

Installing OpenVPN in your own server gives you two major benefits. First, you will have better privacy control. Second, no need to spend on pay-per-user thing. As long as the CPU can handle encryption/decryption, and the ethernet controller can handle the traffic, OpenVPN is a pretty good choice for providing VPN service to a small-sized team.
Anyway, a typical OpenVPN Server configuration looks like the following.
dev tun-udp-1194
server 10.10.10.0 255.255.255.0
proto udp
port 1194
ca /etc/openvpn/pki/ca.crt
cert /etc/openvpn/pki/issued/[email protected]
key /etc/openvpn/pki/private/[email protected]
dh /etc/openvpn/pki/dh.pem
crl-verify /etc/openvpn/pki/crl.pem
remote-cert-tls client
keepalive 10 120
tls-auth /etc/openvpn/pki/ta.key 0
cipher AES-256-CBC
tls-cipher TLS-DHE-DSS-WITH-AES-256-CBC-SHA256
auth SHA256
tls-version-min 1.2
comp-lzo
persist-key
persist-tun
verb 0
In order to access the telnet management console, the following line has to be added in /etc/openvpn/server.conf. Also the openvpn.service must be reloaded for the change to take effect.
management 127.0.0.1 7000
Alright. Next thing is, try connecting to port 7000 via telnet command. If it was a success, then we can use a small Python3 script to talk with the OpenVPN server.
Before we run any script, we need to find out the CN or Common Name used in the RSA Root Certificate. For example, if you generate the CA file with CN=mdminhazulhaque.io, both EasyRSA and OpenVPN will append this CN after the client's name. A sample server and client names could be as follows.
Server: server@mdminhazulhaque.io
Client Mark: mark@mdminhazulhaque.io
Client Bob: bob@mdminhazulhaque.io
Client Alice: alice@mdminhazulhaque.io
Which means, the client names must be unique because OpenVPN uses the client name to map DHCP IP Addresses for remote users.
Well, now we know the common name. It could be mdminhazulhaque.io, or example.com or server or anything. We need to amend the RE_COMMON_NAME regex and put the correct value there. Once done, upload the script to the OpenVPN server and run it using python3.
#!/usr/bin/env python3
import re
import telnetlib
import time
# TODO change here
RE_COMMON_NAME = "^*@mdminhazulhaque.io.*$"
HOST = "127.0.0.1"
PORT = "7000"
INTERVAL = 5
PRE_USERS = {}
def alert(user, ip, state):
print(F"*{user}* {state} from {ip}")
# TODO You can call Slack or API Gateway here
while True:
telnet = telnetlib.Telnet(HOST,PORT, 5)
telnet.write("status\n")
output = telnet.read_until("END\n", 1)
telnet.close()
CURR_USERS = {}
for line in output.split("\n"):
if re.search(RE_COMMON_NAME, line):
user, realaddress, _, _, _ = line.split(",")
ip = realaddress.split(":")[0]
CURR_USERS[user] = ip
connected = set(CURR_USERS.keys()) - set(PRE_USERS.keys())
disconnected = set(PRE_USERS.keys()) - set(CURR_USERS.keys())
for user in list(connected):
alert(user, CURR_USERS[user], "connected")
for user in list(disconnected):
alert(user, PRE_USERS[user], "disconnected")
PRE_USERS = CURR_USERS
time.sleep(INTERVAL)
If you keep running the script in background (screen or systemd whichever you prefer), you will see activity alerts like the following.
[email protected] connected from 190.106.117.114
[email protected] connected from 186.110.104.190
[email protected] connected from 144.143.163.176
...
[email protected] disconnected from 144.143.163.176
[email protected] disconnected from 190.106.117.114
[email protected] disconnected from 186.110.104.190
You can simply override the alert function and call custom Slack or API Gateway URL using requests. Tada!