Installing OpenVPN server in AWS EC2 with User data and Terraform

David Cheong
6 min readNov 22, 2020

This is the terraform version of installing OpenVPN in the EC2 with user data, and it’s the 2nd part from the previous post to install the OpenVPN using the AWS EC2 console.

Everything will be work the same but I’m using the terraform script to deploy the resources.

I will use the terraform script to create the following resources in this post:

  1. An Elastic IP for the EC2
  2. 2 Security group which allow the SSH to the OpenVPN server as well as the access for the VPN client to connect to the OpenVPN server
  3. 1 EC2 which install the OpenVPN server using the user data script

For the simplicity, I will just hardcode the value in the script such as the AMI and SSH Key, this stack will be deploy the resources to the ap-southeast-1 (Singapore) as this is my default region. If you want to reuse this script, you may just edit the script to pass in all the parameter using the variables or variable file.

To start the demo, just create a file call main.tf in your working directory, than copy and paste the following script to the .tf file.

provider "aws" {
region = "ap-southeast-1"
}


resource "aws_eip" "openVPN-eip" {
instance = aws_instance.openVPN-ec2.id
}


resource "aws_security_group" "allow_ssh" {
name = "openVPN-allow_ssh"
description = "OpenVPN allow ssh to the server"

# It's not recommended to allow SSH from all public IP, you should only allow your own public IP or organisation IPs
ingress {
from_port = 22
to_port = 22
protocol = "tcp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow SSH to OpenVPN server"
}

egress {
protocol = "-1"
from_port = 0
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
}


resource "aws_security_group" "allow_vpn" {
name = "openVPN-allow_vpn-connection"
description = "OpenVPN allow VPN client to connect"

ingress {
from_port = 1194
to_port = 1194
protocol = "udp"
cidr_blocks = ["0.0.0.0/0"]
description = "Allow VPN Client to connect to OpenVPN server"
}

egress {
protocol = "-1"
from_port = 0
to_port = 0
cidr_blocks = ["0.0.0.0/0"]
}
}


resource "aws_instance" "openVPN-ec2" {

ami = "ami-0c20b8b385217763f" # Ubuntu AMI in ap-southeast-1
instance_type = "t3a.micro"
key_name = "keangwei83@gmail.com" # change to the keypair name in your account

vpc_security_group_ids = [aws_security_group.allow_ssh.id,
aws_security_group.allow_vpn.id]

tags = {
Name = "OpenVPN Demo"
}

user_data = <<-EOF
#! /bin/bash
apt-get update
curl -O https://raw.githubusercontent.com/angristan/openvpn-install/master/openvpn-install.sh
chmod +x openvpn-install.sh
APPROVE_INSTALL=y ENDPOINT=$(curl -4 ifconfig.co) APPROVE_IP=y IPV6_SUPPORT=n PORT_CHOICE=1 PROTOCOL_CHOICE=1 DNS=1 COMPRESSION_ENABLED=n CUSTOMIZE_ENC=n CLIENT=david PASS=1 ./openvpn-install.sh
EOF

depends_on = [aws_security_group.allow_ssh, aws_security_group.allow_vpn]

}


output "OpenVPN-public-ip" {
value = aws_eip.openVPN-eip.public_ip
}

If you wish to add more user during the bootup installation, you may just copy and paste the following script to the end of the user data, just add as much as number of user you wish to add to the OpenVPN server. Each line should only consist of one user only.

MENU_OPTION="1" CLIENT="Candy" PASS="1" ./openvpn-install.sh

After create the script, we need to first initialise the terraform project by using the terraform init command. The terraform init will go and pull all the dependency and module which we include in the project.

We get the following sample output if the initialization is success.

Before we deploy our resources to the AWS, it’s always a good practise to run the terraform plan and see what are the resources that will be deploy to the destination as well as what resources will be destroy or change.

If you are happy and confident with what’s resources will be create, change or destroy, than you can run the terraform apply -auto-approve to deploy the resources to the destination. The -auto-approve flag will auto confirm the pop up that terraform will ask before they actually deploy the resources.

You should see the following output from you console showing that 4 resources added, 0 changed and 0 destroyed, the public IP of the EC2 will be output on the screen as well.

Now, we can try to login to the server to check the installation of the OpenVPN server, you should see the following detail once you manage to SSH into your OpenVPN server.

$ ssh -i ~/mykey.pem ubuntu@54.169.194.200

Always remember that the ec2 user data script is run on root credential, so you may need to switch to the root account to get the .ovpn file.

You may use the command ps aux | grep vpn to double check is the OpenVPN service running.

Next we may need to download the .ovpn file to your local machine to try connect. First, we may need to switch over to the root credential, than go to the root directory of the user, list out the content. You may just display out the content of the file, copy and paste in your location machine or using the scp to copy the file to your local machine.

$ sudo su - 
$ cd ~
$ ls
david.ovpn snap

To connect to the VPN server, you need to install the VPN client in your machine, for MacOS, you may download and install the Tunnelblick at https://tunnelblick.net/downloads.html. For the window user, you may just download the OpenVPN client at https://openvpn.net/community-downloads/.

Once the installation done, just go to the downloaded .ovpn file and double click it, the configuration will be import to the Tunnelblick apps, then you are ready to connect, just click on the connect button at the right bottom to connect to the OpenVPN server.

In MacOS, when you hover over the Tunnelblick apps on the top bar, you will see this small message box show up showing that you are connected to the VPN and your inbound/outbound speed and bandwidth.

You can double confirm the VPN connection by checking the local machine public IP by curl to the ipinfo.io website, now the public IP is display as 52.169.194.200, which is the same IP as the OpenVPN server, this show that the current outbound internet connection is over the VPN server in the AWS.

$ curl ipinfo.io/ip 54.169.194.200

Always remember to destroy your resources if you just testing it at your test environment by issue the command terraform destroy -auto-approve, else you may need to pay for the EC2 that running in your account. You should see all the resources that just created already clean up.

You also can verify the EC2 has been clean up by the terraform by visit to the EC2 console and check the instance state, it’s should be Terminate now.

It’s a very convenient to use the terraform to deploy th and to clean up the environment, because every deployment and cleaning up process will be work exactly the same no matter how many time you run the deploy. If you are using console to do the deployment and cleaning up, you may leave behind some resources without delete it.

Not only that, by using terraform or any other IAC tools, you can easily share your script to any of your colleagues and they can just deploy the same stack again and again.

Originally published at https://tech.david-cheong.com on November 22, 2020.

--

--