Edit Page

Lab 7: Virtual Private Network (VPN)

Install and configure a virtual private network (VPN) server to restrict access to your cloud VM instances to VPN only.

Networking Security Cloud-Computing

You will install and configure a secure VPN server called OpenVPN to create a secure point-to-point connection and protect your VM instances. This VPN Server serves as the gateway to our protected VM instances. We will limit SSH access to our instances to VPN only. We can also block/revoke access to our entire private network via our VPN Server.

Note

Note: In addition to the cost of the computing resources such as VM instances, setting up a VPN server on the cloud has an additional cost for bandwidth overuses. For this reason, please refer to the pricing page of your cloud provider and be mindful of how much traffic your server is handling.

Disclaimer

The purpose of this lab is to secure your VM instances and protect access to your internal resources when using otherwise insecure or untrusted networks. This is a common practice in the IT industry.

VPN has many other security and privacy applications some of which may violate local laws. It's your responsibility to abide by applicable laws and become educated. The instructor is not responsible for other uses that may violate any local laws.

Setup/Prerequisites

Note

  • Most cloud providers feature a web-based SSH client accessible from the dashboard/portal. This is in particular useful in situations when you’re behind a firewall and the default SSH port 22 is blocked.

Step 1: Create a VM instance for the VPN server

  1. Create a Linux (Ubuntu server) VM instance (1GB of memory is required) and generate your SSH key pair using ssh-keygen -t rsa.
  2. In your cloud provider dashboard, go to the network settings and find the option that controls which ports are open to the public (security groups). Open the following inbound ports:
  • Protocol: UDP, Port: 1194 (for VPN)
  • Protocol: TCP, Port: 22 (for SSH)
  1. Log in to your VM instances using SSH.
ssh -i /path/to/your/private/key/file azureuser@public-ip-or-DNS-name
  • Type the passphrase you entered when generating the SSH key pair and you should be logged into your remote VM instance.
  • First, do an update and upgrade to ensure we have the latest software packages and apply any security fixes
sudo apt update
sudo apt upgrade -y

If you’re not familiar with the text editor vim, you need to change the default editor on Linux from vim to nano:

sudo select-editor
Select an editor.  To change later, run 'select-editor'.
  1. /bin/nano        <---- easiest
  2. /usr/bin/vim.basic
  3. /usr/bin/vim.tiny
  4. /bin/ed

Choose 1-4 [1]: 1
  1. It is important to note that a VPN server requires a static IP address assigned to your VM instance. This is important because we want the IP address of our VPN Server to remain static/unchanged when restarting the VPN server. This IP address will be the Public IP Address of your VPN Server. However, since this lab activity is for learning purposes, we are not going to assign a static IP address to the VM instance.

Step 2: Install OpenVPN

  1. Install OpenVPN
sudo apt install openvpn -y
  1. Install easy-rsa
  • Easy RSA is a public key infrastructure management tool. We need it to set up an internal certificate authority (CA) for our VPN and create SSL key pairs to secure the VPN connection.
sudo apt install easy-rsa -y

If you get an error, please be sure to run sudo apt update.

  • Create a symbolic link for easyrsa so we can call it directly without absoulte path name.
sudo ln -s /usr/share/easy-rsa/easyrsa /usr/bin/easyrsa

Step 3: Generating keys and certificates

The first step in building an OpenVPN server is to establish a PKI (public key infrastructure). The PKI consists of:

  • A separate certificate (also known as a public key) and private key for the server and each client that connects to the VPN server.
  • A primary Certificate Authority (CA) certificate and key, utilized to sign each of the server and client certificates.

OpenVPN authentication uses a bidirectional authentication model based on certificates. That’s it, the client must authenticate the server certificate and the server must authenticate the client certificate before mutual trust is established. It’s important to note that the loss of the CA key destroys the security of the entire PKI.

Setting up a PKI for the Certificate Authority (CA)

  1. Set up a CA PKI
mkdir ~/ca
cd ~/ca
sudo easyrsa init-pki
init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /home/azureuser/ca/pki
  1. Build a root CA with an encrypted CA key Construct the Certificate Authority (CA). During this process, you will be prompted to provide a PEM passphrase and a common name.
sudo easyrsa build-ca
Using SSL: openssl OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)

Enter New CA Key Passphrase: 
Re-Enter New CA Key Passphrase: 
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [Easy-RSA CA]:myvpn

CA creation complete and you may now import and sign cert requests.
Your new CA certificate file for publishing is at:
/home/azureuser/ca/pki/ca.crt
Note

In a production environment and for security reasons, you should use the fully qualified domain name (FQDN) of your host as the common name for your CA.

  1. Generate the certificate revocation list A Certificate Revocation List (CRL) in OpenVPN is a list of digital certificates that have been revoked by the Certificate Authority (CA) before their scheduled expiration date. These certificates are no longer trusted, and should not be used for secure communication. If a client’s certificate is lost, stolen, or otherwise compromised, you can add that certificate to the CRL.
sudo easyrsa gen-crl

You will be prompted to enter the passphrase for CA.

Using SSL: openssl OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)
Using configuration from /home/azureuser/ca/pki/easy-rsa-10693.9JxQga/tmp.jgp19K
Enter pass phrase for /home/azureuser/ca/pki/private/ca.key:
40E7EA0EE5740000:error:0700006C:configuration file routines:NCONF_get_string:no value:../crypto/conf/conf_lib.c:315:group=<NULL> name=unique_subject

An updated CRL has been created.
CRL file: /home/azureuser/ca/pki/crl.pem

Setting up a PKI for the VPN Server

  1. Setup the server PKI. Configure a secondary PKI environment on the server at a separate directory:
mkdir ~/server
cd ~/server
sudo easyrsa init-pki
init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /home/centos/server/pki
  1. Generate the server keypair and request

You will be asked to enter a Common Name, you could enter something like your hostname. It’s important that each certificate should have a unique Common Name.

sudo easyrsa gen-req my-vpn-server nopass
Using SSL: openssl OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)
.....+.........+.+..+.........+.+..+.+...........
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [my-vpn-server]:

Keypair and certificate request completed. Your files are:
req: /home/azureuser/server/pki/reqs/my-vpn-server.req
key: /home/azureuser/server/pki/private/my-vpn-server.key
Warning

The nopass option means that the private key will not be encrypted. This is not recommended since unencrypted private keys can be used by anyone who obtain them. Encrypted keys offer stronger protection, but will require a passphrase on initial use.

Setting up a PKI for the Client

  1. On each client, setup the PKI and generate a keypair and request. Configure the PKI environment for the client:
mkdir ~/client-01
cd ~/client-01/
sudo easyrsa init-pki
init-pki complete; you may now create a CA or requests.
Your newly created PKI dir is: /home/azureuser/client-01/pki
  1. Generate the client keypair and request
sudo easyrsa gen-req client-01-key nopass
Using SSL: openssl OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)
..+...+...........+....+......+.........+...+...+..............+.......+........+...+...+.+..............
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Common Name (eg: your user, host, or server name) [client-01-key]:

Keypair and certificate request completed. Your files are:
req: /home/azureuser/client-01/pki/reqs/client-01-key.req
key: /home/azureuser/client-01/pki/private/client-01-key.key
Note

You should generate separate keys and certificates for each client you intend to connect to your VPN server. You shouldn't share keys and certificates with clients.

Step 4: Generating keys and signing the requests

Both the VPN server and client are requesting a certificate. In this step, we will import the certificate requests to the CA. Then the CA should sign the requests and return a valid certificate.

4.1: On the CA, import both the server and client request files.

We will copy/transfer the server and client files into the CA’s reqs/ directory in preparation for signing the certificate. Import the server request

cd ~/ca
sudo easyrsa import-req ~/server/pki/reqs/my-vpn-server.req vpn-server-01
The request has been successfully imported with a short name of: vpn-server-01
You may now use this name to perform signing operations on this request.

Import the client request

sudo easyrsa import-req ~/client-01/pki/reqs/client-01-key.req  client-01
The request has been successfully imported with a short name of: client-01
You may now use this name to perform signing operations on this request.

4.2: Verify and review each request’s details.

  • Review the server request
cd ~/server
sudo easyrsa show-req my-vpn-server
Showing req details for 'my-vpn-server'.
This file is stored at:
/home/azureuser/server/pki/reqs/my-vpn-server.req

Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject:
            commonName                = my-vpn-server
        Attributes:
            (none)
            Requested Extensions:

Review the client request

cd ~/client-01/
sudo easyrsa show-req client-01-key
Showing req details for 'client-01-key'.
This file is stored at:
/home/azureuser/client-01/pki/reqs/client-01-key.req

Certificate Request:
    Data:
        Version: 1 (0x0)
        Subject:
            commonName                = client-01-key
        Attributes:
            (none)
            Requested Extensions:

4.3 Sign each request with the correct type either server or client.

Sign the server’s request file as a server. Type “yes” to confirm and enter the passphrase.

cd ~/ca
sudo easyrsa sign-req server vpn-server-01
Using SSL: openssl OpenSSL 3.0.2 15 Mar 2022 (Library: OpenSSL 3.0.2 15 Mar 2022)


You are about to sign the following certificate.
Please check over the details shown below for accuracy. Note that this request
has not been cryptographically verified. Please be sure it came from a trusted
source or that you have verified the request checksum with the sender.

Request subject, to be signed as a server certificate for 825 days:

subject=
    commonName                = my-vpn-server


Type the word 'yes' to continue, or any other input to abort.
  Confirm request details: yes
Using configuration from /home/azureuser/ca/pki/easy-rsa-11478.IJVNAE/tmp.O1nmqg
Enter pass phrase for /home/azureuser/ca/pki/private/ca.key:
4047CBFFAD760000:error:0700006C:configuration file routines:NCONF_get_string:no value:../crypto/conf/conf_lib.c:315:group=<NULL> name=unique_subject
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'my-vpn-server'
Certificate is to be certified until Jul 27 13:23:55 2026 GMT (825 days)

Write out database with 1 new entries
Data Base Updated

Certificate created at: /home/azureuser/ca/pki/issued/vpn-server-01.crt

Sign the client’s request file as a client:

sudo easyrsa sign-req client client-01
You are about to sign the following certificate.
Please check over the details shown below for accuracy. Note that this request
has not been cryptographically verified. Please be sure it came from a trusted
source or that you have verified the request checksum with the sender.

Request subject, to be signed as a client certificate for 825 days:

subject=
    commonName                = client-01-key


Type the word 'yes' to continue, or any other input to abort.
  Confirm request details: yes
Using configuration from /home/azureuser/ca/pki/easy-rsa-11544.HaqZNk/tmp.4V4Giw
Enter pass phrase for /home/azureuser/ca/pki/private/ca.key:
Check that the request matches the signature
Signature ok
The Subject's Distinguished Name is as follows
commonName            :ASN.1 12:'client-01-key'
Certificate is to be certified until Jul 27 13:25:21 2026 GMT (825 days)

Write out database with 1 new entries
Data Base Updated

Certificate created at: /home/azureuser/ca/pki/issued/client-01.crt      

4.4 Generates DH (Diffie-Hellman) parameters on the server

Diffie-Hellman parameters are used in the key exchange process to generate a shared secret without directly transmitting it. This allows the VPN server and client to establish a secure connection.

Generate the Diffie-Helllman parameters. This may take a few minutes to complete.

cd ~/server
sudo easyrsa gen-dh
Generating DH parameters, 2048 bit long safe prime
....................................................+...............

DH parameters of size 2048 created at /home/azureuser/server/pki/dh.pem

Step 5: Configuring the OpenVPN server

5.1 Create a directory to store the generated keys

sudo mkdir -p /etc/openvpn/keys

5.2 Copy the generated keys to the OpenVPN config directory.

sudo cp ~/ca/pki/ca.crt /etc/openvpn/keys/;
sudo cp ~/server/pki/dh.pem /etc/openvpn/keys/;
sudo cp ~/server/pki/private/my-vpn-server.key /etc/openvpn/keys/;
sudo cp ~/ca/pki/issued/vpn-server-01.crt /etc/openvpn/keys/;
sudo ls /etc/openvpn/keys/
ca.crt  dh.pem  my-vpn-server.key  vpn-server-01.crt

5.3 Configure the VPN server

Copy the example OpenVPN configuration file as a starting point for configuring our VPN server.

sudo cp /usr/share/doc/openvpn/examples/sample-config-files/server.conf /etc/openvpn/

Open the configuration file in your text editor:

sudo nano /etc/openvpn/server.conf

We need to point to the files that contain the keys. Edit or uncomment (by removing the semicolon) the following lines:

ca keys/ca.crt
cert keys/vpn-server-01.crt
key keys/my-vpn-server.key 
dh keys/dh.pem

topology subnet

push "redirect-gateway def1 bypass-dhcp"
push "dhcp-option DNS 1.1.1.1"
push "dhcp-option DNS 1.0.0.1"

log         /var/log/openvpn.log
log-append  /var/log/openvpn.log

user azureuser
group azureuser

The above lines reference the generated keys and issued certificates. We also redirect all the client’s network traffic through the VPN server and use CloudFlare’s public DNS resolver. We also changed the default syslog log file into a specific file for OpenVPN. Finally, we want to run OpenVPN with no privileges (non root user), so we told it to run as our user, azureuser. Please replace this user and group with the your user and group on Ubuntu server. To find your user name run whoami and to list the groups run groups <username>.

5.4 Add a shared secret key to enhance the security of the VPN server.

Generate the shared secret key to add an additional layer of symmetric-key cryptography. This key will be used to encrypt all control channel packets, including the packet’s payload and its header.

sudo openvpn --genkey secret /etc/openvpn/keys/tls-crypt.key

Open /etc/openvpn/server.conf in your text editor and remove the line that starts with

tls-auth ta.key 0 # This file is secret

and replace it with:

tls-crypt keys/tls-crypt.key 0

Step 6: Setting up Routing with iptables

Since we will set up a VPN server, we need to block most inbound connections, except over SSH and the OpenVPN port. We’ll also want to allow incoming network traffic from VPN clients to the Internet. If we do not do that, VPN clients could only talk to our VPN server itself. Thus, we need to add firewall rules and routing configurations.

UFW, or Uncomplicated Firewall, is a simple firewall on Linux systems. Its primary goal is to make managing firewall rules easier for users who are not familiar with firewall concepts.

Check if UFW is installed: sudo ufw --version. If it’s not installed, run sudo apt install ufw. Next, we want to make sure that ufw is not running:

sudo ufw status
Status: inactive

If UFW is running, stop it using sudo ufw disable

We can now configure UFW to allow traffic on the default OpenVPN server port, UDP 1194, and the SSH port, TCP 22.

sudo ufw allow 1194/udp
sudo ufw allow 22/tcp

Next we need to have UFW to allow forwarded packets

sudo nano /etc/default/ufw

and change the line with the value from DEFAULT_FORWARD_POLICY="DROP" to DEFAULT_FORWARD_POLICY="ACCEPT"

Finally, enable ufw, so it starts and all rules take effect.

sudo ufw enable

This command will start UFW and enable it to start at boot.

Step 7: Starting the OpenVPN service

Setup OpenVPN to start automatically at boot (i.e., when restarting the VPN server).

sudo systemctl -f enable openvpn@server.service

Start the OpenVPN service:

sudo systemctl start openvpn@server.service

Check OpenVPN’s log to make sure the VPN server started successfully.

sudo cat /var/log/openvpn/openvpn.log 

Look for any related keyword such as failed, fatal error, error. If there is no other errors, then you may start configuring clients.

Step 8: Setting up the client

You need to have an OpenVPN client to be able to connect to the OpenVPN server. Below is a list of some OpenVPN clients by operating system.

Create a profile file for the client on your client machine (desktop/laptop). You may use any text editor (e.g., VS code, nano, notepadd, etc.).

cd ~/client-01
nano ~/client-01.ovpn

Insert the following content into the OpenVPN client configuration file, making modifying the values as per the instructions provided below:

client
nobind
dev tun
remote-cert-tls server
persist-key
auth-nocache
remote 34.207.77.21 1194 udp

<key>

</key>
<cert>

</cert>
<ca>

</ca>
key-direction 1
<tls-crypt>

</tls-crypt>
redirect-gateway def1
  • Change the IP address that is written after remote to your VPN server’s public IP address.
  • Copy the content of the client’s certificate private key file.
  • sudo cat ~/client-01/pki/private/client-01-key.key and paste it inside the tag <key>.
  • save and exit
  • Copy the content of the client’s certificate file
    • sudo cat ~/ca/pki/issued/client-01.crt and paste it inside the tag <cert>
    • save and exit
  • Copy the content of the Certificate Authority (CA) certificate
    • sudo cat /etc/openvpn/keys/ca.crt and paste it inside the tag <ca>.
    • save and exit
  • Copy the content of the TLS key file, which is used to encrypt and authenticate all control channel packets with the static key defined in the file adding additional layer of security
    • sudo cat /etc/openvpn/keys/tls-crypt.key and paste it inside the tag tag <tls-crypt>.
    • save and exit
  • Your config file, client-01.ovpn, should look like:
client
nobind
dev tun
remote-cert-tls server

remote 172.26.9.180 1194 udp

<key>
-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDgw/7lAOyl6le2
.....    .....    .....    .....   .... .  .....   .....   .....
PUIX4mrkcJviRiqW5Vzh/Z4sgqlMHckx2ZDHf2mI4BaGk2QQ587fOlUbg0TnFdlp
-----END PRIVATE KEY-----
</key>
<cert>
  -----BEGIN CERTIFICATE-----
MIIDZzCCAk+gAwIBAgIRAODTK0mT8iiHXpQmwiGVZeIwDQYJKoZIhvcNAQELBQAw
.....    .....    .....    .....   .... .  .....   .....   .....
EDEOMAwGA1UEAwwFbXl2cG4wHhcNMTgxMDI3MTEwNTQ4WhcNMjgxMDI0MTEwNTQ4
-----END CERTIFICATE-----
</cert>
<ca>
  -----BEGIN CERTIFICATE-----
MIIDITCCAgmgAwIBAgIJAOn8Fb9CWvnVMA0GCSqGSIb3DQEBCwUAMBAxDjAMBgNV
.....    .....    .....    .....   .... .  .....   .....   .....
BAMMBW15dnBuMB4XDTE4MTAyNzA1MDIxMVoXDTI4MTAyNDA1MDIxMVowEDEOMAwG
-----END CERTIFICATE-----
</ca>
  key-direction 1
<tls-crypt>
  #
  # 2048 bit OpenVPN static key
  #
-----BEGIN OpenVPN Static key V1-----
cd741158706bca6ccbe105f4a916855f
.....    .....    .....    .....
7359257c94167046586710321ad7123b
-----END OpenVPN Static key V1-----
</tls-crypt>
  redirect-gateway def1
  1. Download the OpenVPN profile file using scp Open the Terminal on your client machine and download the file using scp:
scp -i ~/path/to/ssh/key user-name@public-ip-address:~/client-01/client-01.ovpn ./
  1. Import the client-01.ovpn file into your VPN client.

  2. Connect to the VPN server from your VPN client.

Step 9: Restrict SSH access to only over VPN

  • Log in to the dashboard of your cloud provider.
  • Create another VM instance and restrict SSH access to the public IP address of the VPN server instance.
    • Find the option that limits access to the new VM instance to a specific or range of IP addresses. Add the public IP address of your VPN server to restrict access to the VPN instance.
  • Try to access the new instance without via the VPN and without using the VPN.
  • Clean up resources and delete the VM instances and disks.

Submission

Submit your answers with screenshots showing the commands you executed as a PDF file by the due date.

Lab submissions are due one hour before the next week’s lab begins.