Atlassian Crowd authentication for OpenVPN

In whichever IT company you work, whatever its size and whatever its form is at some point in time requirement to extend a private network over public network will appear. If you are Windows-guy (or gal, of course) in Windows-based-company - good for you, deploying Remote Access Server role will do the job. Else if there is Linux everywhere - a day of struggling with StrongSwan should be enough.

But what you can do, if your environment is highly heterogeneous and your teammates are not willing to abandon their shiny Mac OS, stable FreeBSDs and crazy Mameos [1] and switch to consistent platform?

We’ve turned to OpenVPN, as its behavior is consistent over all of these platforms.

[1]: Ok, the last two were just an exaggeration, we’ve blooming Apple garden, greenhouse built of multiple Windows kinds and a Linux distro for every single old African word.

 Attempt first: Certificate authority + client certificates

Long time ago in Brainly galaxy far far away OpenVPN authenticated via client certificates has been deployed. Every single new employee, despite of account in SSO service, had to get his VPN certificate issued, securely distributed and configured. Let’s not talk about bulk-revoking these certificates after staff changes. And don’t even ask how to revoke certificate if you don’t have its copy. This solution was simple & robust, but not very pleasant to maintain.

 Attempt second, and I hope, the final: Integrating OpenVPN with Atlassian Crowd

 crowd-radius-server

One or other day, hanging around Atlassian Market I’ve accidentally found Dieter Wimberger’s crowd-radius-server - simple RADIUS implemented server based on tinyradius backed by Crowd REST API.
https://github.com/dwimberger/crowd-radius-server

It’s really simple piece of Java code - all it can do for you is authentication to Crowd’s database. When configuring, don’t care about application URL - any will do the job, as it is not used.
config.properties:

#RADIUS Server Configuration
server.interface=RADIUS_SERVER_IP
server.port=1812
server.clients=OPENVPN_SERVER_IP:RADIUS_SERVER_SHARED_SECRET
server.duplicate.interval=5000
server.responsethreads.number=5

#Crowd Server Configuration
session.lastvalidation=session.lastvalidation
session.isauthenticated=session.isauthenticated
application.password=CROWD_APPLICATION_PASSWORD
application.name=CROWD_APPLICATION_NAME
session.validationinterval=0
crowd.server.url=CROWD_URL
session.tokenkey=session.tokenkey
application.login.url=<Application Login URL>

As there are no init scripts provided and we have experience mostly with PHP-based applications, I have decided to run it via awesome supervisord.

 openvpn-auth-radius

But, can OpenVPN authenticate to RADIUS server?
Here is where Ralf Luebben’s diploma thesis - openvpn-auth-radius - plugin for RADIUS authentication and accounting comes.
https://bitbucket.org/02strich/openvpn-auth-radius

Unfortunately, it was written to do accounting in every single configuration. Despite of fact, that crowd-radius-server does not support accounting, if you are using configuration with dynamic client-side IP assignment, it will result in failed CLIENT-CONNECT plugin calls, as there will be no client IP in environmental variables, finally breaking whole authentication process.

I’ve decided to strip accounting off the plugin and run slightly modified version, which is now available at:
https://github.com/brainly/openvpn-auth-radius

If you’re not willing to use foreign-patched code, basically just disabling the plugin calls should do the job:

diff --git a/radiusplugin.cpp b/radiusplugin.cpp
index 1335c3f..77ac751 100644
--- a/radiusplugin.cpp
+++ b/radiusplugin.cpp
@@ -73,7 +73,7 @@ extern "C"


                // Intercept the --auth-user-pass-verify, --client-connect and --client-disconnect callback.
-               *type_mask = OPENVPN_PLUGIN_MASK ( OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY ) | OPENVPN_PLUGIN_MASK ( OPENVPN_PLUGIN_CLIENT_CONNECT ) | OP
+               *type_mask = OPENVPN_PLUGIN_MASK ( OPENVPN_PLUGIN_AUTH_USER_PASS_VERIFY );

                // Get verbosity level from the environment.
                const char *verb_string = get_env ( "verb", envp );

After applying changes in any way, just compile the plugin and place in your library directory.

make radiusplugin.so
mkdir -p /usr/local/lib/openvpn
mv radiusplugin.so /usr/local/lib/openvpn/

Important part of openvpn.conf:

dev tap
mode server
username-as-common-name
client-cert-not-required
server-bridge 172.16.1.1    255.255.255.0   172.16.1.100    172.16.1.200
plugin /usr/local/lib/openvpn/radiusplugin.so /etc/openvpn/radiusplugin.cnf
status /var/log/openvpn/status.log 1
log /var/log/openvpn/radiusvpn.log

radiusplugin.cnf:

NAS-Identifier=OpenVPN
Service-Type=5
Framed-Protocol=1
NAS-Port-Type=5
NAS-IP-Address=OPENVPN_SERVER_IP
OpenVPNConfig=/etc/openvpn/openvpn.conf
subnet=255.255.255.0
overwriteccfiles=false
useauthcontrolfile=false

server
{
    authport=1812
    name=RADIUS_SERVER_IP
    retry=1
    wait=1
    sharedsecret=RADIUS_SERVER_SHARED_SECRET
}
 
32
Kudos
 
32
Kudos

Now read this

Configuring 802.1q trunk between UniFi AP and Juniper EX switch

Problem: After configuring 802.1q VLAN trunking on port, according to UniFi Wireless Controller, AP is now in Disconnected or Adoption Failed state. Diagnosis: Tap the traffic (e.g. using port reflector). UniFi AP expects no VLAN tagging... Continue →