Skip to content

Terraform module for production-ready HA Wireguard VPN server in AWS Amazon

Notifications You must be signed in to change notification settings

Globaldots/tf-wireguard-server

Repository files navigation

tf-wireguard-server

WireGuard® is an extremely simple yet fast and modern VPN that utilizes state-of-the-art cryptography. It aims to be faster, simpler, leaner, and more useful than IPsec, while avoiding the massive headache. It intends to be considerably more performant than OpenVPN.

This repository contains Terraform code to provision Wireguard server in a highly-available, scalable and secure manner, utilizing benefits of AWS infrastructure. The solution is built on top of such services as EC2, NLB, S3, SQS, Lambda, SSM, CloudWatch, SNS and more.

Design

Wireguard Multi AZ design

Above diagram demonstrates highly-available Wireguard setup in a single AWS region. Reference code is located under examples/multi-az folder.

Clients connections

Multiple EC2 instances are spread across several availability zones within a region. Clients connections get distributed to the instances through highly-available Network Load Balancer with Route53 DNS record attached (optional).

Configuration changes

Wireguard configuration file is being generated by Terraform and stored in S3 bucket with enabled versioning and access logs. Every S3 bucket content change triggers Lambda function through SQS queue. Lambda function executes predefined SSM document on all Wireguard EC2 instances. SSM document is configured to upload the latest configuration file to the instances and reload Wireguard interface. Also, Wireguard instances have PreUp hook enabled which additionally ensures that they use the latest configuration file available in S3.

Prerequisites

  • Terraform 0.15+
  • Terragrunt 0.28.7+ (optional but recommended)
  • Configured CLI access to target AWS account

Quick start

There are multiple examples under examples folder. Please, choose the one that fits your needs best. Every example comes with its own README.md file. Example code snippets for simplicity reasons don't define all variables which module exposes. So if you want to get a better understanding of all available options, please review the table below.

Requirements

Name Version
terraform >= 0.15.0
terraform >= 0.15.0
aws >= 2.70.0
random ~> 3.1.0

Providers

Name Version
archive 2.2.0
aws 3.45.0

Modules

No modules.

Resources

Name Type
aws_autoscaling_attachment.main resource
aws_autoscaling_group.main resource
aws_cloudwatch_log_group.main resource
aws_cloudwatch_log_metric_filter.main resource
aws_cloudwatch_metric_alarm.cpu_high resource
aws_cloudwatch_metric_alarm.disk_used resource
aws_cloudwatch_metric_alarm.lambda_failure resource
aws_cloudwatch_metric_alarm.memory_used resource
aws_cloudwatch_metric_alarm.status_checks resource
aws_iam_instance_profile.main resource
aws_iam_role.main resource
aws_iam_role.main_lambda resource
aws_iam_role_policy_attachment.main resource
aws_kms_alias.cloudwatch_logs resource
aws_kms_alias.main resource
aws_kms_key.cloudwatch_logs resource
aws_kms_key.main resource
aws_lambda_event_source_mapping.main resource
aws_lambda_function.main resource
aws_launch_template.main resource
aws_lb.main resource
aws_lb_listener.main resource
aws_lb_target_group.main resource
aws_route53_record.main resource
aws_s3_bucket.access_logs resource
aws_s3_bucket.main resource
aws_s3_bucket.main_logs resource
aws_s3_bucket_notification.main resource
aws_s3_bucket_object.main resource
aws_s3_bucket_public_access_block.access_logs resource
aws_s3_bucket_public_access_block.main resource
aws_s3_bucket_public_access_block.main_logs resource
aws_security_group.instance resource
aws_security_group_rule.instance-egress-1 resource
aws_security_group_rule.instance-ingress-1 resource
aws_security_group_rule.instance-ingress-2 resource
aws_security_group_rule.instance-ingress-3 resource
aws_sns_topic.main resource
aws_sns_topic.main_lambda resource
aws_sns_topic_subscription.email resource
aws_sns_topic_subscription.text resource
aws_sqs_queue.main resource
aws_sqs_queue.main_dead_letter resource
aws_sqs_queue_policy.main resource
aws_ssm_document.main resource
archive_file.main data source
aws_ami.ami data source
aws_caller_identity.current data source
aws_elb_service_account.main data source
aws_kms_alias.ebs data source
aws_kms_alias.s3 data source
aws_region.current data source
aws_route53_zone.main data source
aws_subnet.main_private data source
aws_subnet.main_public data source
aws_vpc.main data source

Inputs

Name Description Type Default Required
cloudwatch_alerts_emails Email addresses to get monitoring alerts from CloudWatch. Email alert configuration must be manually approved by clicking on the button in confirmation email. Ignored when cloudwatch_monitoring_enable = false list(string) [] no
cloudwatch_alerts_phone_numbers Phone numbers to get monitoring alerts from CloudWatch. Ignored when cloudwatch_monitoring_enable = false list(string) [] no
cloudwatch_log_retention_days For how long CloudWatch will store log files (days) number 180 no
cloudwatch_monitoring_enable Enable CloudWatch monitoring of Wireguard resources. Disable if you don't plan to use CloudWatch monitoring solution bool true no
dns_zone_name Route53 DNS zone name for Wireguard server endpoint. If not set, AWS LB DNS record is used string "" no
ec2_iam_policy_names Additional IAM policies to assign to EC2 instances through instance profiles if needed list(string) [] no
ec2_instance_main_interface_name EC2 instance primary network interface name string "eth0" no
ec2_instance_type EC2 instance type string "t3.micro" no
enable_termination_protection Enable termination protection for resources bool true no
name_suffix Suffix to be added to all resources to uniquely identify this setup string n/a yes
private_subnet_cidrs VPC private subnets CIDR to create EC2 instances in. AZs of public & private subnets must match list(string) n/a yes
prometheus_exporters_enable Run Prometheus Exporters (Node Exporter & Wireguard Exporter) on EC2 instances. Disable if you don't plan to use Prometheus monitoring solution bool true no
public_subnet_cidrs VPC public subnets CIDR to create NLB in. Multiple subnets are used for HA. AZs of public & private subnets must match list(string) n/a yes
s3_bucket_name_prefix Prefix to be added to S3 bucket name string n/a yes
ssh_keypair_name EC2 SSH key pair name string n/a yes
tags Tags to assign to all resources map(string) {} no
vpc_id AWS VPC ID for EC2 instances and all other resources string n/a yes
wg_allow_connections_from_subnets Allow inbound connections to Wireguard server from these networks. To allow all networks set to 0.0.0.0/0 list(string) n/a yes
wg_cidr Wireguard network subnet CIDR string "10.0.44.0/24" no
wg_dns_server DNS server for Wireguard network string "8.8.8.8" no
wg_ha_instance_desired_count Desired number of Wireguard EC2 instances (HA configuration) number 2 no
wg_ha_instance_max_count Maximum number of Wireguard EC2 instances (HA configuration) number 2 no
wg_ha_instance_min_count Minimum number of Wireguard EC2 instances (HA configuration) number 2 no
wg_listen_ports Wireguard listen ports. These ports will be opened for inbound Wireguard client connections list(string)
[
"51820",
"4500",
"53"
]
no
wg_mtu MTU value for Wireguard network number "1420" no
wg_peers Wireguard clients (peers) configuration. Public_key is optional — will be automatically generated if empty. Peer_ip — desired client IP-address or subnet in CIDR notation within Wireguard network (must be within wg_cidr range). Allowed_subnets — controls what subnets peer will be able to access through Wireguard network (for bounce server mode set to 0.0.0.0/0). Isolated — if true peer won't be able to access other Wireguard peers. map(object({ public_key = string, peer_ip = string, allowed_subnets = list(string), isolated = bool })) {} no
wg_private_key WireGuard server private key string n/a yes
wg_public_key WireGuard server public key string n/a yes
wg_restart_lambda_max_errors_count Lambda which restarts Wireguard instances when configuration changes detected will stop execution if number of errors exceed this value number 0 no
wg_restart_lambda_timeout_sec Timeout for Lambda which restarts Wireguard instances when configuration changes occurred number 300 no

Outputs

Name Description
autoscaling_group_arn EC2 autoscaling group ARN
autoscaling_group_name EC2 autoscaling group name
iam_instance_profile_arn ARN of IAM instance profile to access S3 bucket
iam_instance_profile_id ID of IAM instance profile to access S3 bucket
iam_role_arn ARN of IAM role to access S3 bucket
iam_role_name Name of IAM role to access S3 bucket
launch_template_arn EC2 launch template ARN
launch_template_id EC2 launch template ID
lb_arn Load balancer ARN
lb_dns_name Load balancer DNS name
lb_zone_id Load balancer DNS zone ID
s3_bucket_access_logs_arn Load balancer access logs S3 bucket ARN
s3_bucket_access_logs_name Load balancer access logs S3 bucket name
s3_bucket_arn Wireguard configuration S3 bucket ARN
s3_bucket_name Wireguard configuration S3 bucket name
sqs_queue_arn SQS queue for S3 notifications ARN
sqs_queue_dead_letter_arn SQS dead letter queue for S3 notifications ARN
sqs_queue_dead_letter_id SQS dead letter queue for S3 notifications ID
sqs_queue_id SQS queue for S3 notifications ID
wireguard_client_configs Example configuration files for Wireguard clients
wireguard_server_endpoints Wireguard server endpoints
wireguard_server_host Wireguard server host
wireguard_server_name Wireguard server name
wireguard_server_ports Wireguard server ports

Contribute

Any reasonable pull requests are always welcomed. All PRs are subject to automated checks, so please make sure that your changes pass all configured pre-commit hooks. If you found a bug or need support of any kind, please start a new conversation in Issues section.

License

The code is licensed under GNU GPL license.