From dc4218924b2b8e27dc5800b3d3096a8f1e6e2082 Mon Sep 17 00:00:00 2001 From: Mihai Vultur Date: Mon, 24 Apr 2017 13:12:09 +0000 Subject: [PATCH] Version 1.5.0 Implement VPN configuration using a 'terraform module'. --- CHANGELOG.md | 3 ++ DevOpsVPC/infrastructure.conf | 1 + DevOpsVPC/variables.tf | 6 +++ DevOpsVPC/vpn.tf | 22 ++++++++++ README.md | 38 ++++++++++++------ files/provisioning/vpn_custom_attrib.tpl | 28 +++++++++++++ files/user-data/nat-vpn.cfg | 3 ++ modules/vpn/provision-scripts.tf | 51 ++++++++++++++++++++++++ modules/vpn/variables.tf | 44 ++++++++++++++++++++ 9 files changed, 184 insertions(+), 12 deletions(-) create mode 100644 DevOpsVPC/vpn.tf create mode 100644 files/provisioning/vpn_custom_attrib.tpl create mode 100644 files/user-data/nat-vpn.cfg create mode 100644 modules/vpn/provision-scripts.tf create mode 100644 modules/vpn/variables.tf diff --git a/CHANGELOG.md b/CHANGELOG.md index 95ec2e7..ffb702b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ CHANGELOG This file is used to list changes made in each version of the `en_infra_aws` project. +### Version 1.5.0 +Implement modular VPN configuration. + ### Version 1.4.0 Separate NAT instance configuration using a 'terraform module'. diff --git a/DevOpsVPC/infrastructure.conf b/DevOpsVPC/infrastructure.conf index 9d461e2..b7db1ee 100755 --- a/DevOpsVPC/infrastructure.conf +++ b/DevOpsVPC/infrastructure.conf @@ -42,3 +42,4 @@ ssh_public_key_file = "~/.ssh/id_rsa.pub" #-- ports open on the NAT instance #-- becase we will also have VPN, we also open '45654' nat_inbound_ports = "22,45654" +vpn_port = "45654" diff --git a/DevOpsVPC/variables.tf b/DevOpsVPC/variables.tf index 95daeae..5fd58b1 100644 --- a/DevOpsVPC/variables.tf +++ b/DevOpsVPC/variables.tf @@ -80,6 +80,12 @@ variable "nat_inbound_ports" { description = "Allow following TCP ports to NAT instance." default = "22,443" } +#-- +variable "vpn_port" { + description = "TCP port OpenVPN will listen to" + default = "1194" +} + ##-- Tags for accounting variable "default_tags" { description = "A map of tags to add to all resources" diff --git a/DevOpsVPC/vpn.tf b/DevOpsVPC/vpn.tf new file mode 100644 index 0000000..de758bf --- /dev/null +++ b/DevOpsVPC/vpn.tf @@ -0,0 +1,22 @@ +# +# Project Name:: en_infra_aws +# File:: vpn.tf +# +# Copyright (C) 2017 - Present +# Author: 'Mihai Vultur ' +# +# All rights reserved +# +# Description: +# Uses 'VPN module' to configure a OpenVPN server on the remote instance +# + +module "vpn" { + source = "../modules/vpn" + vpn_ip = "${module.nat.public_ip}" + vpn_port = "${var.vpn_port}" + vpc_cidr = "${var.vpc_cidr}" + ssh_user = "${var.ssh_user}" + #-- assuming 'private key name' by removing the '.pub' extension + private_key_file = "${replace(var.ssh_public_key_file, ".pub", "")}" +} diff --git a/README.md b/README.md index 6e22b8f..452279f 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,7 @@ This project uses Terraform to accomplish this goal. - [Other variables](#other-variables) - [Modules](#modules) - [NAT](#nat----modulesnat) + - [VPN](#vpn----modulesvpn) - [Usage](#usage) - [Inspect the infrastructure](#make-plan) - [Apply changes](#make-apply) @@ -137,21 +138,34 @@ Refer to the `variables.tf` file in the `DevOpsVPC` directory for the default va ### Exposed variables: |Variable |Type |Description |Comments | |:---------|:----|:-----------|:--------| -| `instance_name` | *String* | Name of the Nat instance that will appear in AWS Console | Mandatory | -| `instance_type` | *String* | Type of the instance used that will serve as NAT Purpose | Optional | +| `instance_name` | *String* | Name of the Nat instance that will appear in AWS Console. | Mandatory | +| `instance_type` | *String* | Type of the instance used that will serve as NAT Purpose. | Optional | | `vpc_name` | *String* | VPC name that the created instance will be assigned to. | Mandatory | | `vpc_id` | *String* | VPC ID that the instance will be assigned to. | Mandatory | | `subnet_id` | *String* | Subnet ID that will be `used for instance interface` creation. Eg. Public Subnet ID. | Mandatory | -| `private_subnets_cidr` | *String* | `CIDR of the private subnet` that the instance will do `NAT translation` for | Mandatory | -| `ami_id` | *String* | `AWS AMI ID` used for instance creation | Mandatory | -| `user_data` | *String* | `user_data` config used during instance creation | Mandatory | -| `sgs` | *String* | `Security groups IDs` that will be assigned to the NAT instance | Mandatory | -| `key_name` | *String* | `AWS Name of the ssh key` to be used during instance provisioning | Mandatory | -| `private_key_file` | *String* | Location for the private ssh key file that will be used to connect to the instance during provisioning | Mandatory | -| `number_of_instances` | *Integer* | Number of NAT instances to spawn | Optional, defaults to `1` | -| `root_volume_size` | *Integer* | Size in GBytes for the NAT instance root volume | Optional, defaults to `8` | -| `inbound_ports` | *String* | Comma separated list of ports that will be opened on the public facing IP of the NAT instance. Eg. SSH+VPN ports | Optional | - +| `private_subnets_cidr` | *String* | `CIDR of the private subnet` that the instance will do `NAT translation` for. | Mandatory | +| `ami_id` | *String* | `AWS AMI ID` used for instance creation. | Mandatory | +| `user_data` | *String* | `user_data` config used during instance creation. | Mandatory | +| `sgs` | *String* | `Security groups IDs` that will be assigned to the NAT instance. | Mandatory | +| `key_name` | *String* | `AWS Name of the ssh key` to be used during instance provisioning. | Mandatory | +| `private_key_file` | *String* | Location for the private ssh key file that will be used to connect to the instance during provisioning. | Mandatory | +| `number_of_instances` | *Integer* | Number of NAT instances to spawn. | Optional, defaults to `1` | +| `root_volume_size` | *Integer* | Size in GBytes for the NAT instance root volume. | Optional, defaults to `8` | +| `inbound_ports` | *String* | Comma separated list of ports that will be opened on the public facing IP of the NAT instance. Eg. SSH+VPN ports. | Optional | + + +### `VPN` -- `modules/vpn/` +- Terraform module used to configure OpenVPN server. It uses a chef cookbook to accomplish this goal. +### Exposed variables: +|Variable |Type |Description |Comments | +|:---------|:----|:-----------|:--------| +| `ssh_user` | *String* | Name of the ssh user used for configuring the remote instances. | Mandatory | +| `private_key_file` | *String* | Path to private key file used in combination with ssh_user. | Mandatory | +| `ovpn_cookbook_ver` | *String* | Version of the custom chef cookbook used to configure the OpenVPN service. | Optional, defaults to `1.1.0` | +| `vpn_ip` | *String* | IP Address of the OpenVPN server. It also connects to this IP during server configuration. | Mandatory | +| `vpn_port` | *String* | Port that the OpenVPN server will listen to. | Mandatory | +| `vpn_proto` | *String* | Protocol used for VPN transport: `udp` or `tcp`.. | Optional, defaults to `tcp` | +| `vpc_cidr` | *String* | CIDR block we want the OpenVPN server to add a route to facilitate traffic | Mandatory | --- ## **Usage** diff --git a/files/provisioning/vpn_custom_attrib.tpl b/files/provisioning/vpn_custom_attrib.tpl new file mode 100644 index 0000000..22d82bd --- /dev/null +++ b/files/provisioning/vpn_custom_attrib.tpl @@ -0,0 +1,28 @@ +{ + "openvpn": { + "tar_path": "/home/${client_prefix}/keys", + "script_security": 2, + "push_routes": [ + "${push_routes_array}" + ], + "gateway": "${gateway_address}", + "config": { + "proto": "${vpn_proto}", + "cipher": "AES-256-CBC", + "port": ${vpn_port} + }, + "client_prefix": "${client_prefix}", + "signing_ca_cert": "/etc/openvpn/keys/${client_prefix}.crt", + "signing_ca_key": "/etc/openvpn/keys/${client_prefix}.key", + "key": { + "country": "RO", + "province": "CJ", + "city": "Cluj Napoca", + "org": "Endava", + "email": "ROCLDDevOps@endava.com" + } + }, + "run_list": [ + "recipe[en_deploy_openvpn]" + ] +} diff --git a/files/user-data/nat-vpn.cfg b/files/user-data/nat-vpn.cfg new file mode 100644 index 0000000..b069a7f --- /dev/null +++ b/files/user-data/nat-vpn.cfg @@ -0,0 +1,3 @@ +#cloud-config +hostname: NAT-VPN +manage_etc_hosts: true diff --git a/modules/vpn/provision-scripts.tf b/modules/vpn/provision-scripts.tf new file mode 100644 index 0000000..bf6f535 --- /dev/null +++ b/modules/vpn/provision-scripts.tf @@ -0,0 +1,51 @@ +# +# Project Name:: en_infra_aws +# Module:: VPN +# +# Copyright (C) 2017 - Present +# Author: 'Mihai Vultur ' +# +# All rights reserved +# +# Description: +# VPN module configures a OpenVPN server on the remote instance +# + +data "template_file" "custom_attrib" { + template = "${file("../files/provisioning/vpn_custom_attrib.tpl")}" + vars { + push_routes_array = "${cidrhost(var.vpc_cidr, 0)} ${cidrnetmask(var.vpc_cidr)}" + gateway_address = "${var.vpn_ip}" + vpn_port = "${var.vpn_port}" + vpn_proto = "${var.vpn_proto}" + client_prefix = "devops_cluj" + } +} + +#-- Currently, as of terraform 0.9.2, it doesn't allow us +#-- to specify a common connection block to be used for all +#-- the provisioners, so we have to repeat that block for +#-- each provisioner + +resource "null_resource" "preparation" { + triggers { + always = "${uuid()}" + } + #-- + provisioner "remote-exec" { + inline = [ + "rm -rf /home/${var.ssh_user}/provision", + "curl -L --create-dirs -o /home/${var.ssh_user}/provision/en_ovpn.tar.gz https://github.com/xxmitsu/en_ovpn/archive/EN_OVPN-${var.ovpn_cookbook_ver}.tar.gz", + "tar -xzf /home/${var.ssh_user}/provision/en_ovpn.tar.gz -C /home/${var.ssh_user}/provision/", + "cat > /home/centos/provision/en_ovpn-EN_OVPN-${var.ovpn_cookbook_ver}/provision/custom_attrib.json <' +# +# All rights reserved +# +# Description: +# VPN module specific variables +# + +variable "ssh_user" { + description = "Name of the ssh user used for configuring the remote instances" + type = "string" +} + +variable "private_key_file" { + description = "Path to private key file used in combination with ssh_user" +} + +variable "ovpn_cookbook_ver" { + description = "Version of the custom chef cookbook used to configure the OpenVPN service." + default = "1.1.0" +} + +variable "vpn_ip" { + description = "IP Address of the OpenVPN server" +} + +variable "vpn_port" { + description = "Port that the OpenVPN server will listen to." + default = "1194" +} + +variable "vpn_proto" { + description = "Protocol used for VPN transport: 'udp' or 'tcp'." + default = "tcp" +} + +variable "vpc_cidr" { + description = "CIDR block we want the OpenVPN server to add a route to facilitate traffic." +}