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
}