Cryptode: Cryptode protects you using a hidden path
Cryptode is a command-line driven OpenVPN client for macOS (Sierra and High Sierra) and (WIP: RHEL/CentOS 7 + Ubuntu) with two focus areas:
-
CLI usage for automation
-
Security for protection of your OpenVPN private keys + certificates and ensuring that only approved routes are added to your route table
NOTE1: Let us know if you have any comments, suggestions for improvement, found a bug or identified a security vulnerability.
NOTE2: We are open to pull requests!
On macOS:
brew tap cryptode/cryptode
brew install cryptode
sudo /usr/local/bin/cryptode_install.sh|
Warning
|
Remember to follow instructions given in the "caveats" section during brew install!
|
|
Note
|
Take a look at the Cryptode homebrew formula if you want to know more. |
On RHEL/CentOS:
sudo yum install https://github.com/<TODO>$ cryptode
Usage: cryptode [options]
connect <all|connection name> : connect to a VPN with given name (default:all)
disconnect <all|connection name> : disconnect VPN with given name (default:all)
reconnect <all|connection name> : reconnect VPN with given name (default:all)
status <all|connection name> : get status of VPN connection with given name (default:all)
json : display output as JSON format
edit <connection name> <auto-connect|pre-exec-cmd|profile> <value>: edit VPN connection with given name
remove <connection name> [force] : remove VPN connection (sudo required)
import <new-from-tblk|new-from-ovpn> <path> : import VPN connection (sudo required)
reload : reload configuration (sudo required)
dns-override <enable <DNS serve IP list>|disable|status> : override DNS settings (sudo required)
script-security <enable|disable> : enable/disable script security
version : print version
help : print help messageFollow these steps to setup a new VPN connection. The name of the VPN is derived from the filename.
Add the OpenVPN configuration (a .ovpn file):
sudo vi /opt/cryptode/etc/vpn.d/vpn1.ovpnExample OpenVPN file (with empty <cert>, <ca> and <key>, these
obviously needs to be in there when actually adding the VPN):
client
dev tun
proto tcp
remote 10.1.1.1 1194
resolv-retry infinite
nobind
persist-key
persist-tun
remote-cert-tls server
comp-lzo
verb 3
auth SHA512
cipher AES-256-CBC
tls-version-min 1.2
<ca>
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
</ca>
<cert>
-----BEGIN CERTIFICATE-----
...
-----END CERTIFICATE-----
</cert>
<key>
-----BEGIN RSA PRIVATE KEY-----
...
-----END RSA PRIVATE KEY-----
</key>(OPTIONAL) Add the NOC configuration:
sudo vi /opt/cryptode/etc/vpn.d/vpn1.noc{
"auto-connect": false,
"pre-connect-exec": "",
"pre-connect-exec-interval": ""
}Set the correct permissions on both files:
sudo chmod 500 /opt/cryptode/etc/vpn.d/vpn1.ovpn
sudo chmod 500 /opt/cryptode/etc/vpn.d/vpn1.nocAfter adding the new VPN called vpn1 by adding the .ovpn + .noc files
to <Cryptode path>/etc/vpn.d you need to reload cryptoded.
Reload cryptoded:
$ sudo cryptode reload
Sending reload signal to cryptoded process '3667' has succeeded.Check status:
$ cryptode status vpn1
name: vpn1
config-status: NOC configuration exists
profile: /opt/cryptode/etc/vpn.d/vpn1.ovpn
status: DISCONNECTED
openvpn-status: DISCONNECTED
in-total: 0
out-total: 0
timestamp: 1512720431
auto-connect: Disabled
pre-exec-cmd:
pre-exec-status:
pre-exec-interval:$ cryptode connect vpn1
name: vpn1
config-status: NOC configuration exists
profile: /opt/cryptode/etc/vpn.d/vpn1.ovpn
status: CONNECTING
openvpn-status: DISCONNECTED
in-total: 0
out-total: 0
timestamp: 1512720713
auto-connect: Disabled
pre-exec-cmd:
pre-exec-status:
pre-exec-interval:
$ cryptode status vpn1
name: vpn1
config-status: NOC configuration exists
profile: /opt/cryptode/etc/vpn.d/vpn1.ovpn
status: CONNECTED
openvpn-status: CONNECTED
in-total: 2293
out-total: 2419
connected-time: 1512720716
in-current: 2293
out-current: 2419
timestamp: 1512720719
auto-connect: Disabled
pre-exec-cmd:
pre-exec-status:
pre-exec-interval:$ cryptode status vpn1
name: vpn1
config-status: NOC configuration exists
profile: /opt/cryptode/etc/vpn.d/vpn1.ovpn
status: CONNECTED
openvpn-status: CONNECTED
in-total: 3036
out-total: 3153
connected-time: 1512720716
in-current: 3036
out-current: 3153
timestamp: 1512720769
auto-connect: Disabled
pre-exec-cmd:
pre-exec-status:
pre-exec-interval:$ cryptode disconnect vpn1
name: vpn1
config-status: NOC configuration exists
profile: /opt/cryptode/etc/vpn.d/vpn1.ovpn
status: DISCONNECTING
openvpn-status: CONNECTED
in-total: 3226
out-total: 3358
timestamp: 1512720820
auto-connect: Disabled
pre-exec-cmd:
pre-exec-status:
pre-exec-interval:
$ cryptode status vpn1
name: vpn1
config-status: NOC configuration exists
profile: /opt/cryptode/etc/vpn.d/vpn1.ovpn
status: DISCONNECTED
openvpn-status: DISCONNECTED
in-total: 3226
out-total: 3358
timestamp: 1512720824
auto-connect: Disabled
pre-exec-cmd:
pre-exec-status:
pre-exec-interval:Cryptode has the following structure:
-
<Cryptode path>/bin/cryptoded: the daemon that is responsible for starting and stopping VPN connections -
<Cryptode path>/bin/cryptode: the client that is used to makecryptodedconnect/disconnect to VPNs -
<Cryptode path>/etc/cryptoded.conf: the main configuration file forcryptoded -
<Cryptode path>/etc/vpn.d: the directory in which.ovpnand.nocfiles are stored -
/var/run/cryptoded: the socket thatcryptodeuses to communicate withcryptoded -
/var/log/cryptoded/cryptoded.log: the log file fromcryptoded, use this for troubleshooting
Mandatory VPN configuration files:
-
<Cryptode path>/etc/vpn.d/<vpn>.ovpn: the OpenVPN file that contains the configuration of the VPN, private key, client certificate and CA certificate
Optional VPN configuration files:
-
<Cryptode path>/etc/vpn.d/<vpn>.noc: thecryptodedconfiguration of this particular VPN
VPN log files:
-
/var/log/cryptoded/<vpn>.ovpn.log: VPN log file
- Cryptode path
-
/opt/cryptode launchdcryptodedplist-
/Library/LaunchDaemons/com.ribose.cryptoded.plist
Dependencies:
-
/opt/openvpn/sbin/openvpn: a copy of the OpenVPN executable that is owned byroot
Cryptode has HCL-based configuration format which is parsed by libnereon
The <Cryptode path>/etc/cryptoded.conf configuration file looks like this on macOS:
global {
user_id = 501
restrict_socket = true
log_directory = "/var/log/cryptoded"
vpn_config_paths = "/opt/cryptode/etc/vpn.d"
}
openvpn {
sbin_path = "/opt/openvpn/sbin/openvpn"
root_check = true
enable_updown_scripts = false
}openvpn_bin-
the location of the OpenVPN executable. Since this executable will run as
uid 0it is important to place this executable in a directory not writable by unprivileged users.NoteOn macOS OpenVPN will be most likely installed by brewin/usr/local/sbinand for security purposes therefore must be copied to/opt/openvpn/sbin. If you wish to havecryptodeduse the OpenVPN executable in/usr/local/sbinthen you can, but this is not advised as a local attacker typically can replace anything in/usr/local/. openvpn_root_check-
cryptodedcan perform a check whether the OpenVPN executable is owned by root. On macOScryptodedwill expect OpenVPN to live in/opt/openvpn/sbinwhich must be owned by root. In case you want to use the OpenVPN executable in another directory such as/usr/local/binthen you can disable this check, but this is not advised. ovpn_up_down_scripts-
OpenVPN allows to run up and down scripts to set routes and perform MFA actions. By default this behaviour is disabled and up scripts are handled by
cryptodedon a per VPN basis with thepre-connect-execstatement in the VPN .noc file. It is not advised to enable theovpn_up_down_scriptsglobally unless you really need this and know what you are doing. user_id-
this is the UID of the unprivileged user
cryptodedwill executepre-connect-execscripts as. Also the socket ofcryptodedwill only be writable to by this UID. restrict_socket-
cryptodedby default only acceptscryptodesocket connections from the UID set inuser_id. This is to prevent access to your VPN connections on multi-user systems. Disabling this restriction is not advised. log-
this is the log file
cryptodedwill write to. vpn_config_paths-
cryptodedstores OpenVPN files on macOS in/opt/cryptode/etc/vpn.dand on RHEL/CentOS in/usr/local/etc/vpn.d/.
This file is mandatory.
Example cryptoded configuration for a VPN: <Cryptode path>/etc/vpn.d/vpn1.noc.
{
"auto-connect": false,
"pre-connect-exec": "",
"pre-connect-exec-interval": ""
}This file is optional.
auto-connect-
Set this to
truewhen you want to automatically connect to a VPN whencryptodedstarts. This is useful when you have Jenkins slaves auto connecting to VPNs upon boot. pre-connect-exec-
Run a script or executable before connecting to the VPN. This can be used to execute a script for MFA purposes.
pre-connect-exec-interval-
Repeat the execution of the
pre-connect-execat set intervals. This is useful for continuous MFA keep alive.
The .noc configuration file for a VPN is optional. You should only
create one if you need auto-connect and/or a pre-connect-exec script
to run.
The architecture of Cryptode is designed to be seamlessly used and managed from the command line, but kept as secure as possible.
You need sudo for operations that require access to root owned
directories and files.
|
Note
|
macOS clients are typically GUI based and require you to enter a password every time you want to change something. This approach makes it impossible to automate VPN management and operation. Cryptode is created to fix this for macOS OpenVPN connection management. |
+-----------------+
| launchd/systemd |
+-+---------------+
|
v
+----------------------------------+ +-main configuration--------------+
| <Cryptode path>/bin/cryptoded +->| <Cryptode path>/etc/cryptoded.conf |
+-+----+---------------------------+ +---------------------------------+
|
| +-cryptoded VPN configuration file----+
| +->| <Cryptode path>/etc/vpn.d/<vpn>.noc |
| | +-------------------------------------+
+-----+
| | +-OpenVPN configuration file-----------+
| +->| <Cryptode path>/etc/vpn.d/<vpn>.ovpn |<-+
| +--------------------------------------+ |
| |
| +-cryptoded log--------------------+ +----+
+----->| /var/log/cryptoded/cryptoded.log | |
| +----------------------------------+ |
| |
| +-OpenVPN started by cryptoded----------+-------------------------------+
+----->| <OpenVPN path>/openvpn --config <Cryptode path>/etc/vpn.d/<vpn>.ovpn |
| + --log-append /var/log/cryptoded/<vpn>.ovpn.log |
| +-------------------------------------+---------------------------------+
| |
| +-------------+
| |
| +-socket-------------+ | +-VPN log file----------------------+
+----->| /var/run/cryptoded | +->| /var/log/cryptoded/<vpn>.ovpn.log |
+--------------------+ +-----------------------------------+
^
|
+----------+-------------------+
| <Cryptode path>/bin/cryptode +
+------------------------------+
cryptoded is owned by root:wheel and has the following permissions:
-r-x------. cryptoded is meant to be only executed by launchd or
systemd. So don’t start it manually. Upon starting cryptoded will create a
socket in /var/run/cryptoded which will be writable only by a predefined
userid that is set in <Cryptode path>/etc/cryptoded.conf.
It looks like this:
$ ls -la /var/run/cryptoded
srw------- 1 test wheel 0 Sep 19 15:52 /var/run/cryptoded
$ id test
uid=501(test) gid=20(staff) groups=20(staff),401(com.apple.sharepoint.group.1),12(everyone),61(localaccounts),79(_appserverusr),80(admin),81(_appserveradm),98(_lpadmin),501(access_bpf),701(com.apple.sharepoint.group.3),33(_appstore),100(_lpoperator),204(_developer),395(com.apple.access_ftp),398(com.apple.access_screensharing),399(com.apple.access_ssh),402(com.apple.sharepoint.group.2)cryptode is owned by root:wheel and has the following permissions:
-r-xr-xr-x. cryptode can be executed by any user but the socket cryptode
connects to can only be written to a predefined userid. This restricts
the connecting/disconnecting of VPNs to a single userid. Sending a
reload signal to cryptoded using cryptode requires sudo.
On macOS Brew and/or a manual make install installs cryptode to
/usr/local/bin, you MUST follow the instructions to install the
executables in /opt/cryptode/bin using cryptode_install.sh.
cryptode performs a check whether it is executed from /opt/cryptode/bin or
not. If it isn’t then it will exit. This will force you to put
/opt/cryptode/bin in the beginning of your PATH. This is to prevent you
from running sudo on a backdoored cryptode that was placed in
/usr/local/bin by a local attacker.
OpenVPN configuration files are stored in <Cryptode path>/etc/vpn.d which
is owned by root:wheel and has drwxr-xr-x permissions.
The per-connection OpenVPN files are stored as
<Cryptode path>/etc/vpn.d/<vpn>.ovpn, owned by root:wheel and have
-rw------- permissions.
The cryptoded VPN configuration are stored as
<Cryptode path>/etc/vpn.d/<vpn>.noc, owned by root:wheel and have
-rw------- permissions.
This strict permission and owner scheme is to prevent your private keys being leaked and/or your VPN configurations modified by a local attacker.
If cryptoded were to be allowed to use any OpenVPN file then a local
attacker could potentially change the routes to the system’s DNS servers
to an attacker controlled IP.
cryptoded only accepts OpenVPN files that are owned by root and are not
readable by others:
$ ls -la /opt/cryptode/etc/vpn.d
total 144
drwxr-xr-x 14 root wheel 476 Sep 15 13:28 .
drwxr-xr-x 4 root wheel 136 Sep 15 16:48 ..
-rw------- 1 root wheel 146 Sep 11 13:50 vpn1.noc
-rw------- 1 root wheel 7240 Sep 11 13:50 vpn1.ovpnVPNs do not not require a .noc cryptoded configuration file. By default
VPN connections will not auto-connect and no pre-connect-exec will
be executed.
VPNs can be configured that a script is executed before OpenVPN will
connect. This is defined in pre-connect-exec in
<Cryptode path>/etc/vpn.d/<vpn>.noc.
As cryptoded runs as root it will drop its root privileges to the UID
defined with user_id in <Cryptode path>/etc/cryptoded.conf.
OpenVPN will be executed as root but log files will be owned by
user_id. This is to ensure that your desktop user can access and
delete the log files of his/her VPNs.
The following code in src/vpn.c is responsible for this:
On macOS Brew installs OpenVPN in /usr/local/sbin. This allows a local
attacker to replace the openvpn executable with something malicious.
Therefore during installation of Cryptode a root-owned copy of openvpn
needs to be placed in /opt/openvpn/sbin.
Upon start, cryptoded will perform the root check on the openvpn
executable before it actually runs it.