Needed to use OpenVPN for a small project. I have an account with the cloud infrastructure provider Digital Ocean (DO) and OpenVPN has an image in the market place that you can use to create an OpenVPN access server. OpenVPN also provides this quick start guide with detailed steps. The guide takes you from creating a Droplet through configuring your OpenVPN access server. A Droplet is what DO calls their virtual machine instances. You can create different Droplets depending on what your requirements are. And they say you can create a droplet in just 55 seconds! I never timed how long it took to create a droplet, but it was fast.
But in addition to following the OpenVPN quick start guide, I wanted to explore how you can create the OpenVPN access server with a few variations in the steps by using the DO API via the command line. I am doing this on OS X. It also works on a Windows 10 laptop with WSL2 that is running an instance of Ubuntu 20.04. So it should work on full Linux distro too. Please note that while the examples work, you might have some issues with copy and pasting them. In the curl commands you will see single and double quotes being used. The single quotes don’t allow for variable substitution, so double quotes are used. The inner double quotes must then be escaped by using a \ in front of them like this \”.
The first step is to create a new API access token or use one of your existing access tokens. You can’t use the DO API to create an access token. You will have to create the access token online following the steps in the link above. Make sure that you keep your access tokens secret. After you have an access token, then you can use the API to create your Droplet. There are a number of language bindings for the API, but I am going to use curl commands for all my examples. Note that you’ll need to either save your API access token to an environment variable (TOKEN) or substitute it into your curl commands. Here is an example (this is not a real token). Please note that the $ sign is the command prompt. It is used in all of the examples.
$ export TOKEN=77e027c7447f468068a7d4fea41e7149a75a94088082c66fcf555de3977f69d3
1. Create a new ssh key pair with ssh-keygen if you don’t have one, else skip this step.
Open a terminal and run the ssh-keygen command. While a lot of examples use rsa (ssh-keygen -t rsa), it is best practice today to go straight to ed25519.
$ ssh-keygen -t ed25519
You will prompted with a few questions as you create the key pair. First you will be asked to enter the name of the file to save the key into. I just hit return to use the default.
Generating public/private ed25519 key pair. Enter file in which to save the key (/Users/USER/.ssh/id_ed25519):
Next you will be asked to create and confirm a passphrase for the key. While it is highly recommended, it’s optional to use a passphrase. But using a passphrase does have a plus. If your passphrase-protected private key falls into an unauthorized user’s possession, they won’t unable to use it to log on to your account until they figure out the passphrase. Thus giving you some extra time. The only downside to having a passphrase, is you have to type it in each time you use your ssh key pair.
Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /Users/martin/.ssh/id_ed25519. Your public key has been saved in /Users/martin/.ssh/id_ed25519.pub. The key fingerprint is: SHA256:JD5gQbTjflChPEDZm1AEMlWGFbQX4nTqBQicEgeClko martin@Quos-Mac-Pro.local The key's randomart image is: +--[ED25519 256]--+ |X*O#/.+ | |+E=*.X o | |= .%o= . | |. +oO o | | + o S | | . . . | | . . | | . | | | +----[SHA256]-----+
Running ssh-keygen generated two files. Since I used the default, they are called id_ed25519 and id_ed25519.pub. Next we will add this public ssh key to the DO account. If you have been using Unix/Linux for more than a few years, you probably notice that the key fingerprint looks different. The fingerprint used to be presented in a semicolon delimited sequence that looked like this.
39:38:77:25:db:16:db:fc:9d:a9:08:a6:8f:92:48:99
This is because the default fingerprints are shown as SHA256 sequences now, and before the were MD5 sequences.
In order to show the SSH fingerprint using MD5, enter this command. Note that $HOME is set to be the default home directory for the current user.
$ ssh-keygen -l -E md5 -f $HOME/.ssh/id_ed25519 256 MD5:39:38:77:25:db:16:db:fc:9d:a9:08:a6:8f:92:48:99 martin@Quos-Mac-Pro.local (ED25519)
2. Load the ssh key you created into your DO account. First I saved the public ssh key to an environment variable called My_PubKey
$ export MY_PubKey=`cat ~/.ssh/id_ed25519.pub`
Then I ran this curl command to load the public key into my DO account. Note that I am using the environment variables TOKEN and MY_PubKey that I defined prior to running the command.
$ curl -X POST \
-H "Content-Type: application/json" \
-H "Authorization: Bearer $TOKEN" \
-d "{ \"name\":\"My_OV_SSH_PublicKey\" ,\"public_key\":\"${MY_PubKey}\"}" \
"https://api.digitalocean.com/v2/account/keys"
3. Get the id of the ssh key from the output of your curl command after it has been run. You can get all the public ssh keys defined on your DO account with this curl command:
$ curl -X GET -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ "https://api.digitalocean.com/v2/account/keys"
Here is the output from the command to list all of the ssh keys in your account. I didn’t have any before, so there is one the one I just created. You can see the id is 9999999.
{"ssh_key":{"id":9999999,"fingerprint":"39:38:77:25:db:16:db:fc:9d:a9:08:a6:8f:92:48:99","public_key":"ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDRPKgXSZucXuGvl2h8smotrFKfSwUVajJqltfc/m/SYx2lDtABrqrpk0XwmTXPhLtDxsYDx59NqX/KIjMurhp1Ril60uNn8x3GosLhW6nWMpPhs/Thcr0rK95eV/Kzx/ZiLKc8ZPbDV2laa71nmxEX0rK/f9c9g2lnT/f8926uPEGsqeA3Z3mZ4vZixJaQ1ISqZ7GfC8OBNpwLLfqXVVrhVzQRUNYEnCsZ2LEpbYjtTO1kqgMqjsfEeQEjmLEOr03J5uml9LfAUKlcPaI07NLAv5gVYbcITO07ZOtnoglCaLfgE0DGC6zx8LwqKFgHzHirU+lAD83DuBH+fPQTZJWZ martin@Quos-Mac-Pro.local","name":"My_OV_SSH_PublicKey"}}4. Create a droplet with this curl command. Replace the 9999999 in the curl command with the id of your ssh key that you are going to use. This is not the fingerprint or the public_key.
$ curl -X POST "https://api.digitalocean.com/v2/droplets" \
-d'{"name":"My-OpenVPN-Droplet1","region":"nyc3","size":"s-1vcpu-1gb","image":"openvpn-18-04","ssh_keys":[9999999],"backups":false,"user_data":null,"private_networking":null,"volumes": null,"tags":["awesome"]}' \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json"At this point you can list the Droplets you have in your DO account. Use this curl command to do so.
$ curl -X GET -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ "https://api.digitalocean.com/v2/droplets?page=1&per_page=1"
5. Connect to the Open VPN access server via ssh and configure.
$ ssh root@xxx.xxx.xxx.xxx
The OpenVPN Access Server Setup Wizard runs automatically upon your initial login. One of the things that you will be asked for is the OpenVPS access server license key. If you are testing out the product, OpenVPS recommends that you leave this blank. The access server will allow two connection for free by default. A fixed license key can be activated at any time. You can get a free account with OpenVPN that will allow you to have 2 access keys for free. See OpenVPN’s website.
You can activate the license key from your Droplet’s OpenVPN Web Interface or by the command line when logged on as the root user. When activating the license key on the command line, you must be in the /usr/local/openvpn_as/scripts/ folder where the CLI tools for Access Server are located.
Activating a new license key:
$ ./liman Activate "LICE-NSEK-EYIN-HERE"
Show the current licensing state, and any possible problems with license keys:
$ ./liman info
After completing your configuration selections, you will need to define the password for your “openvpn” user as your final step before going to the Admin Web UI. Please note that if you specified a custom Admin UI username instead of the default ‘openvpn’ user account, you should use that username you entered instead. Set the openvpn password with this command.
$ sudo passwd openvpn
6. Disable the password for the root login. It is a good idea to do this. You can restrict the root login to only be permitted via SSH keys.
First edit the SSH config file. In my example I am using the Vi or rather Vim editor to edit the config file. Another editor to use is nano. It has a menu at the bottom of the edit screen that will be helpful.
$ sudo vi /etc/ssh/sshd_config
Inside the sshd_config file, find the line that has PermitRootLogin on it and then modify it to be like this to ensure that users can only connect using their SSH key.
PermitRootLogin without-password
Save and close the file when when you are done. To put these changes into effect you will need to reload the sshd service.
$ sudo systemctl reload sshd.service
You can look at the status of the sshd service by entering this command.
$ sudo systemctl status sshd.service
The status output will look like this. You will have to do a ctrl-c to exit the status output.
● ssh.service - OpenBSD Secure Shell server Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2020-08-17 23:49:26 UTC; 7min ago Process: 11975 ExecReload=/bin/kill -HUP $MAINPID (code=exited, status=0/SUCCESS) Process: 11974 ExecReload=/usr/sbin/sshd -t (code=exited, status=0/SUCCESS) Main PID: 1176 (sshd) Tasks: 1 (limit: 1151) CGroup: /system.slice/ssh.service └─1176 /usr/sbin/sshd -D Aug 17 23:49:54 My-OpenVPN-Droplet1 sshd[1684]: Disconnected from authenticating user root 112.85.42.186 port 26900 [pre Aug 17 23:51:22 My-OpenVPN-Droplet1 sshd[5427]: Accepted publickey for root from 201.220.115.136 port 61324 ssh2: RSA SH Aug 17 23:51:22 My-OpenVPN-Droplet1 sshd[5427]: pam_unix(sshd:session): session opened for user root by (uid=0) Aug 17 23:52:40 My-OpenVPN-Droplet1 sshd[11952]: Received disconnect from 222.186.190.14 port 51102:11: [preauth] Aug 17 23:52:40 My-OpenVPN-Droplet1 sshd[11952]: Disconnected from authenticating user root 222.186.190.14 port 51102 [p Aug 17 23:56:41 My-OpenVPN-Droplet1 systemd[1]: Reloading OpenBSD Secure Shell server. Aug 17 23:56:41 My-OpenVPN-Droplet1 sshd[1176]: Received SIGHUP; restarting. Aug 17 23:56:41 My-OpenVPN-Droplet1 sshd[1176]: Server listening on 0.0.0.0 port 22. Aug 17 23:56:41 My-OpenVPN-Droplet1 systemd[1]: Reloaded OpenBSD Secure Shell server. Aug 17 23:56:41 My-OpenVPN-Droplet1 sshd[1176]: Server listening on :: port 22. lines 1-20/20 (END) root@My-OpenVPN-Droplet1:~#
You might not have realize it, but OpenVPN is built on OpenBSD and they are serious about security. OpenSSH also comes from the OpenBSD group.
7. Now you need to use the OpenVPN web interface to define users that can access the VPN. The URL will be dependent on your OpenVPN Droplet’s IP address or a defined hostname (example: https://123.45.67.89:943/admin/).
When you first login, you will see an SSL certificate warning which is normal. You can override it. Here are more details about the SSL certificates from OpenVPN.
Login with the “openvpn” user. I hope you remembered the password that you set. Next add users in the User Permission table and other setting. Note that you don’t have to add users to the Ubuntu instance that is hosting OpenVPN.
8. You can now start using your OpenVPN Access server. The URL will be dependent on your OpenVPN Droplet’s IP address or a defined hostname (example: https://123.45.67.89:943/).
9. After a while you might need to delete the OpenVPN Droplet that you created. There are two ways you can do that using the curl on the command line. One way is by its ID. Here is the command to do that. Substitute your Droplets ID with the 999999999 in the command
$ curl -X DELETE -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ "https://api.digitalocean.com/v2/droplets/999999999"
The second way is by its Tag Name. You might not have noticed but when I initially created the Droplet, I gave it a tag name of awesome. If you had created a group of Droplets that you gave the same tag name to, like a tag name of awesome. You can delete all of the Droplets at the same time using this curl command.
$ curl -X DELETE -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ "https://api.digitalocean.com/v2/droplets?tag_name=awesome"
10. If you need to delete/destroy the ssh pub key that you added to your DO account, this is the command you would enter. Remember to substitute your ssh key id with the 555555 below.
$ curl -X DELETE -H "Content-Type: application/json" \ -H "Authorization: Bearer $TOKEN" \ "https://api.digitalocean.com/v2/account/keys/555555"
11. You can include and then run a command in your droplet creation step. I will save that exercise for another blog post.
Well that wraps it up. I might piece together a bash script that incorporates the various curl commands. Remember that a Droplet can still cost you money. If you aren’t using it, then delete it. It doesn’t take that long to create another one. Catch you later.
