OpenVPN Server Setup With Easy-RSA on SmartOS
Posted by Dave Eddy on Jul 05 2018 - tags: techAt home I have a zone dedicated to running an OpenVPN server. With this I can connect to my home network securely on both my laptop and phone when I’m away.
I followed this guide for getting the zone ready to route properly for OpenVPN, and then used Easy-RSA to generate the certificates needed.
Zone Setup
To get started, make sure the zone is created with allow_ip_spoofing
enabled
on the NIC of the zone. I used a payload similar to this to create the vpn
zone.
{
"brand": "joyent",
"image_uuid": "221635c4-3b85-11e8-b6ba-23f68c9bf2c4",
"autoboot": true,
"alias": "vpn",
"hostname": "vpn.rapture.com",
"dns_domain": "rapture.com",
"resolvers": [
"10.0.1.2",
"10.0.1.3"
],
"ram": 512,
"nics": [
{
"nic_tag": "admin",
"ip": "10.0.1.41",
"allow_ip_spoofing": true,
"netmask": "255.255.255.0",
"gateway": "10.0.1.1",
"primary": true
}
]
}
If the zone is already created, you can update the NIC with this option with:
vmadm update $uuid <<< '{"update_nics":[{"mac":"00:00:00:00:00:00","allow_ip_spoofing":true}]}'
Where $uuid
is the zones’ UUID and 00:00:00:00:00:00
is the MAC address of
the NIC you want to enable spoofing on.
Zone Networking
IPv4 forwarding must be enabled on the zone with the following command:
routeadm -ue ipv4-forwarding
You can verify this worked by running:
# routeadm -p ipv4-forwarding
persistent=enabled default=disabled current=enabled
And seeing that persistent
and current
are both set to enabled.
The final part of the networking setup for the zone is to rewrite packets from
the clients. To do this, create /etc/ipf/ipnat.conf
with this single line.
map * from 192.168.1.0/24 to any -> 0.0.0.0/32
And then enable ipfilter:
svcadm enable ipfilter
Now the zone is setup to properly rewrite and forward packets received by the OpenVPN server.
OpenVPN Setup
Install the OpenVPN server as well as the easy-rsa tool we’ll use to generate certificates.
pkgin in easy-rsa openvpn
Just in case the server tries to come up upon being installed, disable it for now until we configure it properly.
svcadm disable openvpn
Next, create the config file for OpenVPN at /opt/local/etc/openvpn/openvpn.conf
# OpenVPN Server Config
port 1194
proto udp
management localhost 7505
dev tun
comp-lzo
persist-key
persist-tun
verb 3
# keys and certs
ca certs/ca.crt
cert certs/issued/vpn-server.crt
key certs/private/vpn-server.key
dh certs/dh.pem
# This will be the internal tun0 connection IP - should match ipnat.conf
server 192.168.1.0 255.255.255.0
ifconfig-pool-persist ipp.txt
# This will send all of a client's traffic to the private vlans through the tunnel
# XXX Configure these to match your local setup - rapture.com is my internal domain
push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 10.0.1.2"
push "dhcp-option DNS 10.0.1.3"
push "dhcp-option DOMAIN-SEARCH rapture.com"
push "dhcp-option DOMAIN rapture.com"
keepalive 10 120
# connect script
script-security 2
client-connect ./client-connect
At the bottom of the config is client-connect
and script-security
(optional). These lines make it so a command will be run whenever a client is
connected to the VPN server. I use this script below to send a push
notification to my phone whenever a new client connects:
/opt/local/etc/openvpn/client-connect
#!/usr/bin/env bash
pushover OpenVPN "$common_name connected from $trusted_ip"
exit 0
You’re free to put whatever logic you’d like in here, or comment out the 2 lines to disable this functionality.
Server Certificates
With this config in place, we’ll create the files that the config requires to
work using easyrsa
. To get started, I find it easiest to make a wrapper
script for easyrsa
that exports some of the environmental variables we’ll
need to make this process easy.
cd
cat <<-EOF > ./easyrsa
#!/usr/bin/env bash
export EASYRSA=/opt/local/etc/easyrsa
export EASYRSA_PKI=/opt/local/etc/openvpn/certs
exec easyrsa "$@"
EOF
And then
chmod +x ./easyrsa
EASYRSA
is the location of the easy-rsa config files and suchEASYRSA_PKI
is the location to store the certs - this could be anything. I personally set it to/var/tmp/certs
when I want to test it without interfering with my existing setup.
With this wrapper, we can start building out the cert infrastructure. Run these 3 commands to get started (gen-dh
will take a while).
./easyrsa init-pki
./easyrsa gen-dh
./easyrsa build-ca
Enter a password when prompted by build-ca
and then confirm the rest of the
command with the defaults. This password will be used whenever you sign a
certificate that has been generated.
Create the certificate and key for the vpn server itself:
./easyrsa gen-req vpn-server nopass
./easyrsa sign-req server vpn-server
sign-req
will ask you to confirm the selection by typing yes
, and then it
will also prompt you for a password - this is the password created when
build-ca
was run above.
nopass
is used when generating the certificate so the server can start
automatically without human intervention to enter the password.
Start OpenVPN
Now, we are ready to start the server! Start it with:
svcadm enable openvpn
To ensure that everything is working you can look at the logs here
# svcs -L openvpn
/var/svc/log/pkgsrc-openvpn:default.log
# tail /var/svc/log/pkgsrc-openvpn:default.log
Fri Jul 6 01:53:02 2018 OpenVPN 2.4.5 x86_64-sun-solaris2.11 [SSL (OpenSSL)] [LZO] [LZ4] [MH/PKTINFO] [AEAD] built on Apr 7 2018
Fri Jul 6 01:53:02 2018 library versions: OpenSSL 1.0.2o 27 Mar 2018, LZO 2.10
Fri Jul 6 01:53:02 2018 setsockopt(IPV6_V6ONLY=0)
Fri Jul 6 01:53:02 2018 MANAGEMENT: TCP Socket listening on [AF_INET6]::1:7505
Fri Jul 6 01:53:02 2018 NOTE: the current --script-security setting may allow this configuration to call user-defined scripts
Fri Jul 6 01:53:02 2018 Diffie-Hellman initialized with 2048 bit key
Fri Jul 6 01:53:02 2018 open_tun: got dynamic interface 'tun2'
Fri Jul 6 01:53:02 2018 TUN/TAP device tun2 opened
Fri Jul 6 01:53:02 2018 do_ifconfig, tt->did_ifconfig_ipv6_setup=0
Fri Jul 6 01:53:02 2018 /sbin/ifconfig tun2 192.168.1.1 192.168.1.2 mtu 1500 up
Fri Jul 6 01:53:02 2018 /sbin/ifconfig tun2 netmask 255.255.255.255
Fri Jul 6 01:53:02 2018 /sbin/route add 192.168.1.0 -netmask 255.255.255.0 192.168.1.2
add net 192.168.1.0: gateway 192.168.1.2
Fri Jul 6 01:53:02 2018 Could not determine IPv4/IPv6 protocol. Using AF_INET6
Fri Jul 6 01:53:02 2018 Socket Buffers: R=[57344->57344] S=[57344->57344]
Fri Jul 6 01:53:02 2018 setsockopt(IPV6_V6ONLY=0)
Fri Jul 6 01:53:02 2018 UDPv6 link local (bound): [AF_INET6][undef]:1194
Fri Jul 6 01:53:02 2018 UDPv6 link remote: [AF_UNSPEC]
Fri Jul 6 01:53:02 2018 MULTI: multi_init called, r=256 v=256
Fri Jul 6 01:53:02 2018 IFCONFIG POOL: base=192.168.1.4 size=62, ipv6=0
Fri Jul 6 01:53:02 2018 IFCONFIG POOL LIST
Fri Jul 6 01:53:02 2018 Initialization Sequence Completed
Also, the config line management localhost 7505
starts a management socket on
port 7505 that we can use to verify its working:
# nc localhost 7505 <<< 'pid'
>INFO:OpenVPN Management Interface Version 1 -- type 'help' for more info
SUCCESS: pid=26128
Note that it’s possible to do a lot of things using this management port - including kill the vpn daemon. There is no authentication and any user on the system can connect to this port (it can be disabled in the configuration). The management interface runs on localhost, the zone I’m running this server on only has the root user, has no SSH access, and only runs this daemon so that’s secure enough for my setup - your situation may differ so be mindful of that.
Finally, it should be noted that a tunnel interface is created for this (as per
the config). In the log you can see tun2
, and using ifconfig
we can see:
# ifconfig tun2
tun2: flags=10011008d1<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST,ROUTER,IPv4,FIXEDMTU> mtu 1500 index 6
inet 192.168.1.1 --> 192.168.1.2 netmask ffffffff
ether 40:5a:ea:9c:2f:fe
Client Certificates
The server is running and ready for new clients to connect, now we just need to make some certificates for clients to use.
To make a new client cert and key run the following commands:
./easyrsa gen-req dave-laptop-client
./easyrsa sign-req client dave-laptop-client
Note that gen-req
will ask for a password to use to protect the private key
being generated, and sign-req
will ask for the password created during the
build-ca
step at the beginning of this whole process.
Once these 2 steps are done we now have a cert and key for a new client that can be used to connect to the server! The final step is to use these new files to create an ovpn file - these files can be easily imported into OpenVPN clients. On my iPhone I can use the OpenVPN app with this file to set it up and on my Arch Linux laptop I can just import the file using NetworkManager.
A simple ovpn template looks like this:
client
remote 10.0.1.41 1194
proto udp
dev tun
persist-key
persist-tun
resolv-retry infinite
nobind
comp-lzo
verb 3
<ca>
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
</ca>
<cert>
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
</cert>
<key>
-----BEGIN ENCRYPTED PRIVATE KEY-----
...
-----END ENCRYPTED PRIVATE KEY-----
</key>
The remote
line should be set to the IP (or hostname) and port of the VPN
server.
To create the file, I use a helper script I call gen-ovpn
.
~/gen-ovpn
#!/usr/bin/env bash
#
# Generate an ovpn file using an existing easy-rsa pki structure
#
# Author: Dave Eddy <[email protected]>
# Date: July 06, 2018
# License: MIT
name=$1
pki=${EASYRSA_PKI:-/opt/local/etc/openvpn/certs}
[[ -n $name ]] || exit 1
cd "$pki" || exit 1
ca=$(< ca.crt)
cert=$(< issued/$name.crt)
key=$(< private/$name.key)
[[ -n $ca && -n $cert && -n $key ]] || exit 1
cat <<-EOF
client
remote 10.0.1.41 1194
proto udp
dev tun
persist-key
persist-tun
resolv-retry infinite
nobind
comp-lzo
verb 3
<ca>
$ca
</ca>
<cert>
$cert
</cert>
<key>
$key
</key>
EOF
This way, I can simply specify the basename of the client and it will create the file with the data in the right place.
./gen-ovpn dave-laptop-client > dave-laptop-client.ovpn
And that’s it! That file can be sent to a client that wants to connect, and as
long as they know the password (used during gen-req
for the cert) they can
connect to the server.
Conclusion
You can now generate certs, keys, and ovpn files for any new clients you want to have access to your VPN server!
You can see the active connections by checking the status
of the management interface
# nc localhost 7505 <<< 'status'
>INFO:OpenVPN Management Interface Version 1 -- type 'help' for more info
OpenVPN CLIENT LIST
Updated,Fri Jul 6 05:40:52 2018
Common Name,Real Address,Bytes Received,Bytes Sent,Connected Since
dave-laptop-client,10.0.1.165,22256,3086,Fri Jul 6 05:40:18 2018
ROUTING TABLE
Virtual Address,Common Name,Real Address,Last Ref
192.168.1.6,dave-laptop-client,10.0.1.165,Fri Jul 6 05:40:51 2018
GLOBAL STATS
Max bcast/mcast queue length,0
END