DZone
Thanks for visiting DZone today,
Edit Profile
  • Manage Email Subscriptions
  • How to Post to DZone
  • Article Submission Guidelines
Sign Out View Profile
  • Post an Article
  • Manage My Drafts
Over 2 million developers have joined DZone.
Log In / Join
Refcards Trend Reports Events Over 2 million developers have joined DZone. Join Today! Thanks for visiting DZone today,
Edit Profile Manage Email Subscriptions Moderation Admin Console How to Post to DZone Article Submission Guidelines
View Profile
Sign Out
Refcards
Trend Reports
Events
Zones
Culture and Methodologies Agile Career Development Methodologies Team Management
Data Engineering AI/ML Big Data Data Databases IoT
Software Design and Architecture Cloud Architecture Containers Integration Microservices Performance Security
Coding Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
Culture and Methodologies
Agile Career Development Methodologies Team Management
Data Engineering
AI/ML Big Data Data Databases IoT
Software Design and Architecture
Cloud Architecture Containers Integration Microservices Performance Security
Coding
Frameworks Java JavaScript Languages Tools
Testing, Deployment, and Maintenance
Deployment DevOps and CI/CD Maintenance Monitoring and Observability Testing, Tools, and Frameworks
  1. DZone
  2. Software Design and Architecture
  3. Cloud Architecture
  4. Create a VPN-Secured VPC With Packer and Terraform

Create a VPN-Secured VPC With Packer and Terraform

Learn to create a VPN-secured VPC by deploying Terraform infrastructure with Packer.

Alberto Roura user avatar by
Alberto Roura
·
Nov. 02, 18 · Tutorial
Like (2)
Save
Tweet
Share
5.11K Views

Join the DZone community and get the full member experience.

Join For Free

In this tutorial, we will deploy a Debian 9 machine running OpenVPN and use Packer and to deploy the Terraform infrastructure.

Securing a web application in terms of access management can be tricky, as there are multiple ways to do it in an acceptable way. We can use Security Groups to limit the available ports for a given instance and leaving a specific company IP to have unrestricted access, but in this way, we are giving reachability to anyone connected to that network, which in most occasions is not ideal. A problem of limiting the access to a given IP will be the fact of blocking-out an engineer trying to fix a problem from the outside during after-hours. Another way to approach access management would be to set up a key-server with a very limited set of authorized users registered. With a key-server, we have the problem of the need to set it up in every instance we want to be secured, which in some situations is not very feasible due to network size or other multiple factors.

Today we are going to approach this using a VPN, giving an authorized user a tunnel to a VPC and making it fell like if its devices were directly connected to the network.

What Is a VPN?

VPN stands for Virtual Private Network. Usually, VPNs are used in corporate environments to protect the data transmission between branches located remotely in different cities or even countries. A VPN makes every computer connected to it operate like they were all in the same local network, making routing and maintenance very easy for the IT teams, as they can build an entire Intranet with many critical machines completely isolated from the Internet.

Do I Need a VPN?

The short answer is yes. Focusing on the use-case of this tutorial, we will benefit from a VPN connection because our computers, as IT engineers, are going to have access to the resources in machines that don't even have public IPs. But what's more, VPN provides more security as data that travels through the VPN is encrypted and private.

Preparing the Deployment

Now that we have a clear idea what a VPN is and why we need one, let's plan the deployment. The system will be a Debian 9 machine running OpenVPN. To build the image we will use Packer and to finally deploy the infrastructure, Terraform. You'll need to have an Alibaba Cloud Elastic Compute Service (ECS) server ready, so check out this tutorial if you are not sure how to set up one. Now just create a folder for the config files... and go!

Generate and Upload Your Key

If you haven't uploaded your key yet, you will need to complete this part. Otherwise, you can just jump to the next step. This part will be completed using the Alibaba Cloud console. Once you log in, go to the Elastic Compute Service Management Console and then, from the menu in the left side, click in the Key Pairs link.

To generate your key, in Mac and Linux, open the terminal and type ssh-keygen -t rsa and follow the process it launches. When your key is created, run cat ~/.ssh/id_rsa.pub and copy the output it throws.

Let's go back to the online console. Once in Key Pairs, click Create Key Pair. If is your personal computer, you can name it personal, but I guess here you can just put your preferred name, as long as you can identify it later if you upload more keys. In Creation Type, select Import an Existing Key Pair and a new text area will show up. Paste here the output we copied before and then OK to save it.

Using Packer to Generate the ECS Image

As said, we are going to build OpenVPN on top of Debian 9 (stretch). Open the project folder and create a file named openvpn.json. I prepared for you a template so you can just copy and paste the following JSON into it, but try to understand it first using Packer Documentation.

{
  "variables": {
    "access_key": "{{env `ALICLOUD_ACCESS_KEY`}}",
    "region": "{{env `ALICLOUD_REGION`}}",
    "secret_key": "{{env `ALICLOUD_SECRET_KEY`}}"
  },
  "builders": [
    {
      "type": "alicloud-ecs",
      "access_key": "{{user `access_key`}}",
      "secret_key": "{{user `secret_key`}}",
      "region": "{{user `region`}}",
      "image_name": "openvpn-stretch",
      "source_image": "debian_9_02_64_20G_alibase_20171023.vhd",
      "ssh_username": "root",
      "instance_type": "ecs.t5-lc1m1.small",
      "internet_charge_type": "PayByTraffic",
      "io_optimized": "true"
    }
  ],
  "provisioners": [
    {
      "type": "shell",
      "script": "base-setup.sh"
    }
  ]
}

Next to it, make a file named base-setup.sh with the following contents:

#!/bin/bash
export DEBIAN_FRONTEND=noninteractive
echo "nameserver 1.1.1.1" >> /etc/resolv.conf
apt-get update && apt-get upgrade -y && apt-get install -y net-tools
wget -nv -O /opt/openvpn.deb http://swupdate.openvpn.org/as/openvpn-as-2.5.2-Debian9.amd_64.deb
cat <<- 'EOF' > /opt/start.sh
#!/bin/bash
dpkg -i /opt/openvpn.deb
EOF

Creating the Terraform Infrastructure Files

For this example, we will create two ECS instances, one new VPC, and one Security Group. One ECS will be the VPN and will have public IP; the other will be the machine with sensitive data and will be only accessible using the VPN, with no public IP. Create a file named main.tf with the following contents:

provider "alicloud" {}

variable "vpn_ecs_password" {
  default = "Test1234!"
}

data "alicloud_zones" "default" {}

resource "alicloud_vpc" "vpc" {
  name = "vpn_secured"
  cidr_block = "172.16.0.0/12"
}

resource "alicloud_vswitch" "vswitch" {
  name = "vsw_vpn"
  availability_zone = "${data.alicloud_zones.default.zones.0.id}"
  cidr_block = "172.16.0.0/16"
  vpc_id = "${alicloud_vpc.vpc.id}"
  depends_on = [
    "alicloud_vpc.vpc"
  ]
}

resource "alicloud_security_group" "vpn_sg" {
  name = "sg_vpn"
  vpc_id = "${alicloud_vpc.vpc.id}"
}

resource "alicloud_security_group_rule" "vpn_ssh" {
  type = "ingress"
  ip_protocol = "tcp"
  nic_type = "intranet"
  policy = "accept"
  port_range = "22/22"
  priority = 1
  security_group_id = "${alicloud_security_group.vpn_sg.id}"
  cidr_ip = "0.0.0.0/0"
}

resource "alicloud_security_group_rule" "vpn_web" {
  type = "ingress"
  ip_protocol = "tcp"
  nic_type = "intranet"
  policy = "accept"
  port_range = "943/943"
  priority = 1
  security_group_id = "${alicloud_security_group.vpn_sg.id}"
  cidr_ip = "0.0.0.0/0"
}

resource "alicloud_security_group_rule" "vpn_client" {
  type = "ingress"
  ip_protocol = "udp"
  nic_type = "intranet"
  policy = "accept"
  port_range = "1194/1194"
  priority = 1
  security_group_id = "${alicloud_security_group.vpn_sg.id}"
  cidr_ip = "0.0.0.0/0"
}

data "alicloud_images" "vpn_packer_image" {
  name_regex = "openvpn-stretch"
}

resource "alicloud_instance" "vpn_server" {
  instance_name = "vpn-server"
  image_id = "${data.alicloud_images.vpn_packer_image.images.0.id}"
  instance_type = "ecs.t5-lc1m1.small"

  vswitch_id = "${alicloud_vswitch.vswitch.id}"
  internet_max_bandwidth_out = 100
  security_groups = [
    "${alicloud_security_group.vpn_sg.id}"
  ]

  key_name = "personal"

  provisioner "remote-exec" {
    inline = [
      "sh /opt/start.sh"
    ]

    connection {
      host = "${alicloud_instance.vpn_server.public_ip}"
      private_key = "${file("~/.ssh/id_rsa")}"
    }
  }
}

resource "alicloud_security_group" "secret_machine_sg" {
  name = "sg_vpn"
  vpc_id = "${alicloud_vpc.vpc.id}"
}

resource "alicloud_security_group_rule" "ssh_from_vpn" {
  type = "ingress"
  ip_protocol = "tcp"
  nic_type = "intranet"
  policy = "accept"
  port_range = "22/22"
  priority = 1
  security_group_id = "${alicloud_security_group.secret_machine_sg.id}"
  cidr_ip = "${alicloud_vswitch.vswitch.cidr_block}"
}

data "alicloud_images" "debian_9" {
  name_regex = "^debian_9*"
}

resource "alicloud_instance" "secret_machine" {
  instance_name = "secret-machine"
  image_id = "${data.alicloud_images.debian_9.images.0.id}"
  instance_type = "ecs.t5-lc1m1.small"

  vswitch_id = "${alicloud_vswitch.vswitch.id}"
  security_groups = [
    "${alicloud_security_group.secret_machine_sg.id}"
  ]

  key_name = "personal"
}

output "do_next" {
  value = "Go to https://${alicloud_instance.vpn_server.public_ip}:943/admin"
}


output "secret_machine_ip" {
  value = "${alicloud_instance.secret_machine.private_ip}"
}

Build the Image and Deploy the Infrastructure

For this to work, you need to have 3 environment variables in your machine with the relevant values for you, ALICLOUD_REGION, ALICLOUD_ACCESS_KEY and
ALICLOUD_SECRET_KEY. After creating the Packer json and the Terraform tf files, we can make this work. Navigate into the project folder with cd and run packer build openvpn.json. After the image is created, run terraform init and then terraform apply. This will take a while, so patiently look to the command outputs to see if everything goes well. At the end, the Terraform process will output the public IP of the instance, let's assume 123.123.123.123 in this case.

Create a VPN Profile

First of all, we need to set up the openvpn user password in the machine. For this, go ssh root@123.123.123.123 and run passwd openvpn, this will prompt for a password.

Now, using your browser, navigate to https://123.123.123.123:943/admin and log in using the user openvpn and the password you just set. We still need to tweak one more thing, as the server is not aware of its public IP, so click in Network Settings and update the Hostname or IP Address field with the public IP.

Its time to download the profile, go to https://123.123.123.123:943 and click in Yourself (user-locked profile).

Connect to the VPN

There are multiple options to connect our devices to a VPN, but here I'll describe only one, as you can really choose your favorite, the final result won't change at this point. In general, I personally like GUI clients when they give good functionality and SO integration. For VPN clients, I like Tunnelblick, as it lets you manage multiple profiles easily and the ability to switch quickly between them.

After downloading the *.ovpn file, Tunnelblick recognizes the format and with just double-clicking in the file it will assist you setting it up. This app, when running, shows an icon in the menu bar to access to its options. The icon will change the look depending in the connection status as well.

SSH Into the Web Server Using Its Private IP

From now, our computer will route all the connections to IPs belonging to the VPC through the VPN. This is a big thing, as we are logging in a machine that belongs to another network using its private IP. Do ssh root@PRIVATE_IP and enjoy your setup!

Virtual private cloud Terraform (software) vpn Cloud computing Machine

Published at DZone with permission of Alberto Roura, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

Popular on DZone

  • 2023 Software Testing Trends: A Look Ahead at the Industry's Future
  • SAST: How Code Analysis Tools Look for Security Flaws
  • Automated Performance Testing With ArgoCD and Iter8
  • Top Authentication Trends to Watch Out for in 2023

Comments

Partner Resources

X

ABOUT US

  • About DZone
  • Send feedback
  • Careers
  • Sitemap

ADVERTISE

  • Advertise with DZone

CONTRIBUTE ON DZONE

  • Article Submission Guidelines
  • Become a Contributor
  • Visit the Writers' Zone

LEGAL

  • Terms of Service
  • Privacy Policy

CONTACT US

  • 600 Park Offices Drive
  • Suite 300
  • Durham, NC 27709
  • support@dzone.com
  • +1 (919) 678-0300

Let's be friends: