2

Integrated Enterprise OpenVPN Configuration

I've scoured the Internet high and low attempting to locate a definitive source of how to configure openvpn in a manner that is secure, and most importantly, is 100% integrated with Active Directory. I am way too lazy to have multiple systems to take care of. I want:

  • OpenVPN Client with no customization (besides config file, of course)
  • Tight Integration with Active Directory
  • Multiple Factors of Authentication (MS Certificate Store + Password)
  • Super-Easy to Manage

Here's what I've come up with. Is this solution secure and does it meet the needs above?

At this point, I'm going to assume there is an active directory server somewhere that the openvpn server can connect to and that the client machine is joined to the domain.

I'm also going to assume you have an AD CA deployed.

Auto-Enrollment

It all starts with a trip through the age-old process of auto-enrollment. I'm not going to get in to the specifics here, as this note describes the process well. The only note here is that I auto-enrolled machine certificates, not user certificates.

Once the GPO is rolled out, all end-users will have an unexportable, private machine certificate that is signed by the the domain CA.

Now, can we marry the AD auto-enrolled certificates with OpenVPN? I think so.

Certificate Authority

On the AD CA, export the CA public certificate. In my case, I named it the same as the machine name with a .crt at the end.

PKI Configuration

These examples assume an ubuntu-based operating system. Adjust the packages and ca-certificates step for your distribution.

# install our requisite packages
apt-get -y install openvpn openvpn-auth-ldap

# install our ca key as root ca
mkdir /usr/share/ca-certificates/extra/
cat > /usr/share/ca-certificates/extra/contoso-CONAWSDC01-CA.crt << EOM
-----BEGIN CERTIFICATE-----
MIIDBjCCAe6gAwIBAgIQf0VK+i3wuppE8eWGBn525TANBgkqhkiG9w0BAQsFADAc
...
KYTE7h9qTnJ4EQ==
-----END CERTIFICATE-----
EOM

# enable this root ca
dpkg-reconfigure ca-certificates

# go to /etc/openvpn for the remainder of this exercise
cd /etc/openvpn

# create our private key
openssl genrsa -des3 -out server.key 2048

# create a csr for the domain controller to sign. you *should* have the correct CN, but it's not required
openssl req -key server.key -out server.csr 

# then, over on the CA, we need to sign this key (note the webserver cheat)
# certreq.exe -submit -attrib "CertificateTemplate:WebServer" .\bopawsvpn02.txt

# create ta.key, which is used by the tls-auth pragma to prevent DOS attacks
openvpn --genkey --secret /etc/openvpn/ta.key

# symlink to our ca key
ln -s /usr/share/ca-certificates/extra/bop-BOPAWSDC01-CA.crt ca.crt

# enable ip forwarding
sysctl -w net.ipv4.ip_forward=1
# ( update /etc/sysctl.conf )   

# If you are hosting the OpenVPN server on an Amazon Web Services (AWS) EC2 instance make sure "Source/Destination Checking" is disabled on the instance's Elastic Network Interface (enabled by default)

OpenVPN Configuration

I started with the basic road warrior configuration and tweaked it for my needs. Mostly, I added dns settings and routes.

I was unable to get chroot to work well due to dependencies on other modules for LDAP authentication.

server.conf

port 1194
proto udp
dev tun
sndbuf 0
rcvbuf 0
ca ca.crt
cert server.crt
key server.key
dh dh.pem
tls-auth ta.key 0
topology subnet
server 10.22.0.0 255.255.0.0
ifconfig-pool-persist ipp.txt
push "dhcp-option DNS 10.20.1.4"
push "dhcp-option DOMAIN contoso.com"
push "route 10.0.0.0 255.255.0.0"
push "route 192.168.1.0 255.255.255.0"
keepalive 10 120
cipher AES-128-CBC
comp-lzo
user nobody
group nogroup
persist-key
persist-tun
status openvpn-status.log
verb 3
plugin /usr/lib/openvpn/openvpn-auth-ldap.so /etc/openvpn/ldap.conf

LDAP Configuration

In order to configure LDAP, you're going to need service account to bind with before we can ask for authentication. I created an account with a long password with very minimal privileges.

ldap.conf

<LDAP>
        # LDAP server URL
        URL             "ldap://10.20.1.4"

        # Bind DN (If your LDAP server doesn't support anonymous binds)
        # BindDN                uid=Manager,ou=People,dc=example,dc=com
        BindDN          "CN=auth,OU=Service Accounts,DC=contoso,DC=com"

        # Bind Password
        Password        areallyreallyreallylongpassword

        # Network timeout (in seconds)
        Timeout         15

        # Enable Start TLS
        TLSEnable       no

        # Follow LDAP Referrals (anonymously)
        FollowReferrals yes

        # TLS CA Certificate File
        TLSCACertFile   /usr/local/etc/ssl/ca.pem

        # TLS CA Certificate Directory
        TLSCACertDir    /etc/ssl/certs

        # Client Certificate and key
        # If TLS client authentication is required
        #TLSCertFile    /usr/local/etc/ssl/client-cert.pem
        #TLSKeyFile     /usr/local/etc/ssl/client-key.pem

        # Cipher Suite
        # The defaults are usually fine here
        # TLSCipherSuite        ALL:!ADH:@STRENGTH
</LDAP>

<Authorization>
        # Base DN
        BaseDN          "OU=local,DC=contoso,DC=com"

        # User Search Filter
        #SearchFilter   "(&(uid=%u)(accountStatus=active))"
        SearchFilter    "(sAMAccountName=%u)"

        # Require Group Membership
        RequireGroup    false

        # Add non-group members to a PF table (disabled)
        #PFTable        ips_vpn_users

</Authorization>

Client Configuration

I wanted a single configuration that I would send to all of my users that worked without embedding an identifier or certificate in the .ovpn file. After some experimentation and a less-than-well-documented feature of the cryptoapi, I found this cheat. By specifying my domain in the SUBJ call to cryptoapi, OpenVPN will find the first certificate with that name, which is my machine's cert.

I did have to embed the CA certificate, as I couldn't figure out how to pull that from the certificate store too. But that's public information, so I'm not too worried.

client.ovpn

client
dev tun
proto udp
sndbuf 0
rcvbuf 0
remote vpn.contoso.com 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
cipher AES-128-CBC
comp-lzo
key-direction 1
verb 3
auth-user-pass
setenv opt block-outside-dns # block all non-vpn dns queries
# redirect-gateway def1 # route *all* traffic through vpn
# this is my domain fqdn. allows one config for multiple connections
cryptoapicert "SUBJ:.contoso.com" 

<ca>
-----BEGIN CERTIFICATE-----
MIIDBjCCAe6gAwIBAgIQf0VK+i3wuppE8eWGBn525TANBgkqhkiG9w0BAQsFADAc
...
KYTE7h9qTnJ4EQ==
-----END CERTIFICATE-----
</ca>

Am I missing any obvious security holes?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.