Terraform module for deploying a best practice, HA OpenVPN Access Server on AWS.
This module deploys ready-to-go OpenVPN Access Server AMI with an RDS backend and Letsencrypt for SSL certificate generation.
The module requires the following:
terraform
version >= 0.12.0aws
provider ~> 2.7- OpenVPN Access Server AMI (we recommend building it with Codebuild)
The OpenVPN server sits inside of a autoscaling group and is deployed into public subnet within a nominated VPC in order to ring-fence the solution. VPN client users can connect to the OpenVPN server creating a dedicated layer 4 tunnels which the VPN users can then use to access internal services hosted in the nominated VPC or in adjacent VPC attached via VPC-peering. The OpenVPN server can also provide access to any internal Route53 hosted zone by DNS proprigation. Access to the OpnVPN server for administrative tasks can be done either through the admin GUI on port 943 or via the AWS System Manager, which creates an SSH session via the AWS console. Port 22 is not open on this server, access directly via SSH is not enabled for improved protection against attackers, we recommend to all our clients to use AWS Session Manager instead, to find out more please see the following page.
In this solution OpenVPN Access Server is configured to migrate its local SQLite database to Aurora RDS to allow for data persistance, the migration process is fully automated using Ansible playbooks which are stored in S3 and are generated during the Terraform run. These Ansible playbooks are later pulled down from S3 and run locally as part of the user-data boot procedure. This means that the no matter what happens to the EC2 instance the AutoScalingGroup will replace it with a new instance and during the boot up sequence of that instance, Ansible will check if it needs to migrate the database or update the configuration file on the EC2 instance to ensure OpenVPN Access Server is using the database stored in Aurora RDS. The ansible playbooks will also generate SSL certificates everytime a new EC2 instance is deployed and store the ceritifcates in S3 so they can be pulled down again and reused in case a new instance needs to be spun up.
Since developing this solution, Letsencrypt have reduced the longevity of thier SSL certificates, we now recommend terminating your EC2 instance on a regular basis allow for Letsencrypt to generate a new certificate.
To read the Ansible playbooks, please go here.
Include this repository as a module in your existing terraform code:
module "openvpn" {
source = "git::ssh:https://[email protected]/osodevops/aws-terraform-module-ssm-session-manager.git"
}
You might have to initialise the terraform workspace, in order to do so run:
terraform init -reconfigure
- Check that your code is good and what you are building, run:
terraform plan -refresh=true
You should see an output from terraform suggesting building a set of services;
- EC2 AutoScalingGroup for the OpenVPN server.
- S3 bucket with an s3 bucket policy.
- S3 objects for the Ansible playbooks.
- RDS Aurora cluster.
- When you are happy with the proposed creations, changes, execute the following:
terraform apply -auto-approve
OpenVPN Access Server is not very automation friendly, hence there are times when we may need to manually run the Ansible playbooks that configure the VPN service. There are currently 3 ansible playbooks that configure the OpenVPN server.
- db_tasks.yaml
- This playbook is used to both migrate the database of a new OpenVPN implementation to RDS and also restore the OpenVPN configuration against a current OpenVPN database in RDS. This is the default playbook run against the server during a deployment, there is conditional logic in the playbook to know when to migrate and when to restore the database.
- ssl_automation.yaml
- This playbook generates a custom SSL certificate using Letsencrypt, which gets ingested into OpenVPN. The certificate lasts for 60 days. Simply run the playbook to renew the certificate.
- openvpn_update_ansible_playbook.yaml
- This playbook will update the packages on the server. OpenVPN servers can become long-lived hence they need to be updated from time to time. You could setup a cron in Cloudwatch to run this command on a regular basis.
To invoke the playbooks listed above use the SSM documents generated here and with the following terraform command;
terraform apply -auto-approve -var="run_ssl_playbook=true" -target=module.vpn.aws_ssm_association.ssl_ansible_playbook[0]
Please adjust the SSM code to meet your needs, they are only examples of what is possible.
In order for the AutoScalingGroup's to run the Ansible playbooks as part of the user-data procedure all of the Ansible playbooks are stored in S3 and pulled down by the bash script and run locally as follows:
ansible-playbook -v /opt/openvpn_ssl_ansible_playbook.yaml
Should you wish you can also pull down and run the ansible playbooks locally on the EC2 instance via SSM. However be aware that due to the conditional logic used in the Ansible playbooks, you cannot use "Check Mode". You will recieve an error from Ansible if you use --check
when running the Ansible playbooks, this is expected.
WARNING
OpenVPN is an expert level program, the application is very unforgiving if mistakes are made. Only run the commands below if you know what you are doing. If debugging is required please logon via SSM directly to the server and check the /var/log/opevpnas.log
and query the database for configuration settings via the ./sacli
tool.
Please use the following guide for specific OpenVPN Access Server commands, there is a lot of good documentation in there.
Be aware that if you use Google Authentication with OpenVPN Access Server, you will need to run these commands locally on the EC2 instance in order to reset users tokens.
The following arguments are supported:
Name | Description | Type | Default | Required |
---|---|---|---|---|
ami_owner_account | Provide the AWS ID for the AMI owner | string | n/a | yes |
asg_min_size | Minimum size of ASG | string | 1 | no |
asg_max_size | Maximum size of ASG | string | 1 | no |
asg_desired_capacity | Desired capacity of ASG | string | 1 | no |
db_instance_type | Size of the RDS instance | string | db.t2.small | yes |
ec2_instance_type | Size of the EC2 instance | string | t2.small | yes |
environment | DEV/MGMT/TEST/PROD? | string | n/a | no |
iam_role_name | Name of the IAM role used | string | n/a | yes |
iam_policy_name | Name of the IAM policy used | string | n/a | yes |
iam_instance_profile_name | Name of the IAM instance policy used | string | n/a | yes |
key_name | EC2 SSH key used for deployment | string | n/a | yes |
rds_backup_retention_period | Set the rention period for the RDS backups | string | 7 | no |
rds_preferred_backup_window | Set the preferred backup window for the RDS instance | string | 01:00-03:00 | no |
rds_maintenance_window | Set the maintenance window for the RDS instance | string | sun:03:00-sun:04:00 | no |
rds_storage_encrypted | Encrypt RDS, yes/no? | string | true | no |
rds_master_name | Set the DB username | string | n/a | yes |
rds_master_password | Set the DB password | string | n/a | yes |
rds_database_name | Set the name of the DB | string | openvpndb | no |
rds_cluster_identifier | Name of the RDS cluster | string | openvpn-database-cluster | no |
rds_instance_name | RDS instance name | string | openvpn-database-instance | no |
rds_subnet_group | Subnet group used for the deployment | string | openvpn-db-subnet-group | no |
rds_final_snapshot | Set the name for the final snapshot if an RDS instance is terminated | string | openvpn-db-snapshot-final | no |
rds_port | RDS port for the database | string | 3306 | no |
r53_domain_name | Set the domain name used by the OpenVPN server | string | n/a | yes |
r53_hosted_zone_id | R53 hosted zone used by the OpenVPN server | string | n/a | yes |
vpc_id | Set the VPC ID | string | n/a | yes |
vpc_cidr_range | CIDR Range for the VPC | string | n/a | yes |
aws_region | Region used in AWS | string | n/a | yes |
common_tags | Common tags used for all AWS resources in the TF module | string | n/a | yes |
s3_bucket_acl | S3 Acess controls | string | private | no |
s3_bucket_force_destroy | Do you want to force destruction of S3 objects when rebuilding the TF stack? | string | n/a | yes |
s3_bucket_name_ansible | Set the name of the S3 bucket used | string | n/a | yes |
s3_bucket_policy | Set a custom S3 policy used by the S3 bucket | string | n/a | yes |
bucket_versioning | Set S3 bucket versioning? | string | false | no |
s3_sse_algorithm | Which algorithm to use for S3 encryption | string | AES256 | no |
mariadb_repo_url | Repo URL for MariaDB | string | https://yum.mariadb.org/10.1/centos7-amd64 | no |
mariadb_repo_enable | Enable repo for MariaDB | string | yes | no |
mariadb_repo_gpgcheck | GPG check MariaDB repo | string | yes | no |
mariadb_repo_gpg_url | GPG check key url | string | https://yum.mariadb.org/RPM-GPG-KEY-MariaDB | no |
openvpn_database_user | OpenVPN database user | string | openvpn-db-user | no |
openvpn_dns_name | URL for the OpenVPN database | string | n/a | yes |
ec2_hostname | hostname of the ec2 instance | string | n/a | yes |
ssl_admin_email | set an email for the ssl certificates, letsencrypt will notify you when certs expire | string | n/a | yes |
epel_repofile_path | EPEL repo file path | string | /etc/yum.repos.d/epel.repo | no |
epel_repo_gpg_key_url | EPEL GPG key URL | string | https://dl.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-7 | no |
epel_repo_url | EPEL Repo URL | string | https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm | no |
snapshot_identifier | Set the name for an existing RDS snapshot | string | n/a | yes |
ssm_parameter_name | Set the SSM parameter name for the openvpn password | string | n/a | yes |
private_network_access_1 | Set the network address that OpenVPN will allow routing access to | string | n/a | yes |
private_network_access_2 | Set the network address that OpenVPN will allow routing access to | string | n/a | yes |
deletion_protection | RDS delete protection | string | true | no |
multi_az | RDS multi AZ | string | false | no |
apply_immediately | RDS apply changes immediatly option | string | false | no |
aws_ami_filter | Set a custom filter for the OpenVPN access server | string | OPENVPN-* | no |
vpn_tunnel_setting | Set the VPN tunneling mode to be ON or OFF | string | false | no |
Check out these related projects.
- OpenVPN Access Server Admin Manual - Provides instructions and basic configuration examples for the commercial OpenVPN Access Server product
- OSO SSM Session Manager - Leverages SSM for ansible provisioning
File a GitHub issue, send us an email or tweet us.
Copyright © 2017-2021 OSO | See LICENCE for full details.
We at OSO help teams to adopt emerging technologies and solutions to boost their competitiveness, operational excellence and introduce meaningful innovations that drive real business growth. Our developer-first culture, combined with our cross-industry experience and battle-tested delivery methods allow us to implement the most impactful solutions for your business.
Looking for support applying emerging technologies in your business? We’d love to hear from you, get in touch by email
Start adopting new technologies by checking out our other projects, follow us on twitter, join our team of leaders and challengers, or contact us to find the right technology to support your business.