#!/bin/bash # ovpn-ad-sync # # Description: # Script to synchronize AD/LDAP users with OpenVPN config files and email user certificates and a setup guide to end users. This script is a very rudimentary hack to fill my purpose. It may or may not work for you. It could also be put to use with LDAP with minimal modification even though I wrote it for an Active Directory environment. # Author: # Josh North 2014-12-01 # josh.north@point808.com # Free for use and modification. Credit is appreciated if you do anything with it but nothing is required. # Theory: # Basically, the script should be run on a cron schedule. At run, it searches all users in a specified AD group. It then checks to see if subdirectories exist for the user, if not, it decides to create them. It then loops through to look for directories that do not have a corresponding user in the AD list and deletes them. It technically (at this point) does not revoke access and restart the vpn, this is IMPORTANT, because in my setup we are authenticating against AD anyway as a second layer. This is not fully secure but like I said, it is a major work in progress. # # Instructions: # Please see README.md in the root of this github project or your cloned directory # VARIABLES OAS_ADUSR="oas_user@EXAMPLE.COM" # User@domain.tld or full DN OAS_ADPWD="oas_user" # We will change this later OAS_ADBASE="dc=example,dc=com" # Search base OAS_ADURI="ldap://192.168.1.21" # Full URI required OAS_VPNGRP="cn=OpenVPNUsers,cn=Users,dc=example,dc=com" # Full group DN OAS_USERDIR="/etc/openvpn/oas_clients" # Full path to user configs OAS_RSADIR="/etc/openvpn/rsa" # Full path to easy-rsa root OAS_LOGFILE="/var/log/oas.log" # Log file OAS_LOGRET=10 # Lines of old log to keep OAS_TPLDIR="/etc/openvpn/oas_templates" # Full path to user templates OAS_OVPNTPL="${OAS_TPLDIR}/template.ovpn" # Template file to use for clients OAS_MAILSUBJ="Example Company - VPN Information" # Subject line of email OAS_MAILFROM="admin@example.com" # This will appear as the "From" address OAS_MAILADMIN="admin@example.com" # Email to copy all configs and errors to OAS_ATTACHMENTS="/etc/openvpn/oas_attachments/*" # File guide to attach (path to dir plus /* at end)!!! OAS_ORGNAME="Example Company, Inc." # Company name # MAIN SCRIPT # easy logger function from http://mostlyunixish.franzoni.eu/ function logsetup { TMP=$(tail -n $OAS_LOGRET $OAS_LOGFILE 2>/dev/null) && echo "${TMP}" > $OAS_LOGFILE exec > >(tee -a $OAS_LOGFILE) exec 2>&1 } function log { echo "[$(date)]: $*" } logsetup log "Script starting up" # source rsa vars cd ${OAS_RSADIR} source ./vars # and back cd ${OAS_USERDIR} log "Beginning user creation run" # ldapsearch returns an array of user principals in the for loop. for each # principal in the vpn group, we want to get the users name, guid, and email for s_user in $( ldapsearch -x -D "${OAS_ADUSR}" -H "${OAS_ADURI}" -w "${OAS_ADPWD}" -s sub -b "${OAS_ADBASE}" "(&(objectCategory=user)(memberOf=${OAS_VPNGRP}))" | grep sAMAccountName | awk '{print $2}' ); do # now we are in a loop - the following row(s) are run on each user in group # is there already a dir? for right now we assume that if a directory exists we are good with that user log "Checking user directory for ${s_user}..." if [ -d "${OAS_USERDIR}/${s_user}" ]; then log "User directory for ${s_user} already already exists, no need to modify" # if not, lets notify and make one and do the vpn thingie else log "User directory for ${s_user} does not exist - this must be a new user in the group" log "Getting user details for ${s_user} from directory service..." OAS_USRMAIL="$(ldapsearch -x -D "${OAS_ADUSR}" -H "${OAS_ADURI}" -w "${OAS_ADPWD}" -s sub -b "${OAS_ADBASE}" "(&(objectCategory=user)(memberOf=${OAS_VPNGRP})(sAMAccountName=${s_user}))" | grep mail | awk '{print $2}')" OAS_USRGUID="$(ldapsearch -x -D "${OAS_ADUSR}" -H "${OAS_ADURI}" -w "${OAS_ADPWD}" -s sub -b "${OAS_ADBASE}" "(&(objectCategory=user)(memberOf=${OAS_VPNGRP})(sAMAccountName=${s_user}))" | grep UID | awk '{print $2}')" OAS_USRFNAME="$(ldapsearch -x -D "${OAS_ADUSR}" -H "${OAS_ADURI}" -w "${OAS_ADPWD}" -s sub -b "${OAS_ADBASE}" "(&(objectCategory=user)(memberOf=${OAS_VPNGRP})(sAMAccountName=${s_user}))" | grep displayName | awk '{print $(NF-1) " " $NF}')" #run another loop to see if email field is valid, if not, we have to error out! if [[ -n $(ldapsearch -x -D "${OAS_ADUSR}" -H "${OAS_ADURI}" -w "${OAS_ADPWD}" -s sub -b "${OAS_ADBASE}" "(&(objectCategory=user)(memberOf=${OAS_VPNGRP})(sAMAccountName=${s_user}))" | grep mail | awk '{print $2}') ]]; then log "User details for ${s_user} pulled successfully..." log "Creating user certificates..." export KEY_NAME="${OAS_USRFNAME}" export KEY_EMAIL="${OAS_USRMAIL}" cd ${OAS_RSADIR} ${OAS_RSADIR}/pkitool ${s_user} log "Certificates created for ${s_user}, now starting configuration and file generation..." mkdir ${OAS_USERDIR}/${s_user} cp ${OAS_RSADIR}/keys/${s_user}.crt ${OAS_USERDIR}/${s_user} cp ${OAS_RSADIR}/keys/${s_user}.key ${OAS_USERDIR}/${s_user} cp ${OAS_RSADIR}/keys/ca.crt ${OAS_USERDIR}/${s_user} cp ${OAS_RSADIR}/keys/dh2048.pem ${OAS_USERDIR}/${s_user} # now we need to make a config file... let's try using a template as a header and adding certs cat ${OAS_OVPNTPL} > ${OAS_USERDIR}/${s_user}/${s_user}.ovpn echo '' >> ${OAS_USERDIR}/${s_user}/${s_user}.ovpn cat ${OAS_USERDIR}/${s_user}/ca.crt >> ${OAS_USERDIR}/${s_user}/${s_user}.ovpn echo '' >> ${OAS_USERDIR}/${s_user}/${s_user}.ovpn echo '' >> ${OAS_USERDIR}/${s_user}/${s_user}.ovpn cat ${OAS_USERDIR}/${s_user}/dh2048.pem >> ${OAS_USERDIR}/${s_user}/${s_user}.ovpn echo '' >> ${OAS_USERDIR}/${s_user}/${s_user}.ovpn echo '' >> ${OAS_USERDIR}/${s_user}/${s_user}.ovpn cat ${OAS_USERDIR}/${s_user}/${s_user}.crt >> ${OAS_USERDIR}/${s_user}/${s_user}.ovpn echo '' >> ${OAS_USERDIR}/${s_user}/${s_user}.ovpn echo '' >> ${OAS_USERDIR}/${s_user}/${s_user}.ovpn cat ${OAS_USERDIR}/${s_user}/${s_user}.key >> ${OAS_USERDIR}/${s_user}/${s_user}.ovpn echo '' >> ${OAS_USERDIR}/${s_user}/${s_user}.ovpn log "Configuration created, now trying to email configuration file to the user" echo -e "to: ${OAS_USRMAIL}\ncc: ${OAS_MAILADMIN}\nsubject: ${OAS_MAILSUBJ}\nHello ${OAS_USRFNAME},\n\nThis email is from ${OAS_ORGNAME} You are receiving it because your account has been granted remote access privileges via a secure VPN client.\n\nThere should be multiple attachments to this email. One is your OpenVPN configuration file (${s_user}.ovpn), and at least one User Guide document, though your administrator may have attached additional documents specific to your network. Please review the attached guides before contacting your support personell if you have any questions or problems.\n\nIMPORTANT! Please do NOT share the information contained in this email or the attached key file with anyone! This file identifies your computer to the network, and any other use opens the company network for hacking or other malicious behaviour.\n\nNOTE: You will be prompted for a user name and password when connecting to the VPN client. Your username will be your domain login name (${s_user}) and your password is the same as your domain password.\n" | (cat - && uuencode ${OAS_USERDIR}/${s_user}/${s_user}.ovpn ${s_user}.ovpn && for s_file in ${OAS_ATTACHMENTS}; do uuencode "${s_file}" "$(basename "${s_file}")"; done) | /usr/sbin/sendmail -t -F ${OAS_MAILFROM} log "Emailed configuration file to user email address ${OAS_USRMAIL}" log "If they do not receive their email, just copy and paste the file from the server or re-run" else log "ERROR - no email address stored in directory for user ${s_user}. You must set an email address!" fi # go back to user dir!!! cd ${OAS_USERDIR} fi # end of the first looper! done # Now we need to list all directories, and then run an ldap search to see if there is a matching user. If not, we'll figure out how to revoke their certs and then delete the config directory. # source rsa vars to get ready to revoke cd ${OAS_RSADIR} source ./vars # go back to user directory cd ${OAS_USERDIR} log "Beginning user deletion run" # let's list the directories first, then on each dir, run a ldapsearch to see if user match. If not, delete and revoke. for s_userd in ${OAS_USERDIR} do echo "${s_userd}" # end of second looper. I think we are done for now done log "Script run complete - it may or may not be a success, the log will tell..." log "Taking a nap before the next run..." exit 0