first pass at a wireguard-as vpn module
parent
6cf51ee982
commit
d6a0a96841
@ -0,0 +1,7 @@
|
|||||||
|
# WireGuard Access Server
|
||||||
|
|
||||||
|
TODO
|
||||||
|
|
||||||
|
## Helpful links
|
||||||
|
|
||||||
|
https://fabianlee.org/2017/05/21/golang-running-a-go-binary-as-a-systemd-service-on-ubuntu-16-04/
|
@ -0,0 +1,35 @@
|
|||||||
|
module "vpn_asg" {
|
||||||
|
source = "terraform-aws-modules/autoscaling/aws"
|
||||||
|
|
||||||
|
name = "${var.prefix}-vpn"
|
||||||
|
image_id = data.aws_ami.ubuntu.image_id
|
||||||
|
instance_type = var.instance_type
|
||||||
|
security_groups = [aws_security_group.vpn.id]
|
||||||
|
iam_instance_profile = aws_iam_instance_profile.vpn.name
|
||||||
|
asg_name = "${var.prefix}-vpn"
|
||||||
|
lc_name = "${var.prefix}-vpn"
|
||||||
|
health_check_type = "EC2"
|
||||||
|
vpc_zone_identifier = var.public_subnets
|
||||||
|
min_size = 1
|
||||||
|
max_size = 1
|
||||||
|
desired_capacity = 1
|
||||||
|
wait_for_capacity_timeout = 0
|
||||||
|
default_cooldown = 120
|
||||||
|
health_check_grace_period = 120
|
||||||
|
key_name = var.key_name
|
||||||
|
|
||||||
|
|
||||||
|
user_data = templatefile("${path.module}/files/vpn_user_data.sh", {
|
||||||
|
EIP_ID = aws_eip.vpn.id
|
||||||
|
REGION = data.aws_region.current.name
|
||||||
|
CONFIG_BUCKET = aws_s3_bucket.configs.id
|
||||||
|
WIREGUARD_INTERFACE = var.wireguard_interface
|
||||||
|
WIREGUARD_PORT = var.wireguard_vpn_port
|
||||||
|
})
|
||||||
|
|
||||||
|
tags_as_map = {
|
||||||
|
"Name" = "${var.prefix}-vpn"
|
||||||
|
"App" = "WireGuard"
|
||||||
|
"Terraform" = "true"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,87 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
set -x
|
||||||
|
|
||||||
|
# Elastic IP attachment
|
||||||
|
INSTANCE_ID=$(curl -s 169.254.169.254/latest/meta-data/instance-id)
|
||||||
|
aws ec2 associate-address --allocation-id ${EIP_ID} --instance-id $INSTANCE_ID --region ${REGION}
|
||||||
|
|
||||||
|
|
||||||
|
# Install WireGuard and other dependencies
|
||||||
|
apt-get install -y software-properties-common
|
||||||
|
add-apt-repository -y ppa:wireguard/wireguard
|
||||||
|
apt-get update
|
||||||
|
apt-get install -y "linux-headers-$(uname -r)"
|
||||||
|
apt-get install -y wireguard iptables resolvconf awscli git sudo
|
||||||
|
|
||||||
|
# Initialization WireGuard configs
|
||||||
|
aws s3api head-object --bucket ${CONFIG_BUCKET} --key wg0.conf
|
||||||
|
if [[ "$?" -eq 0 ]]; then
|
||||||
|
echo "[+] Copying existing WireGuard config to system from s3://${CONFIG_BUCKET}"
|
||||||
|
aws s3 cp s3://${CONFIG_BUCKET}/wg0.conf /etc/wireguard/wg0.conf
|
||||||
|
else
|
||||||
|
echo "[+] Generating new WireGuard config"
|
||||||
|
wg genkey | tee /opt/privkey | wg pubkey > /opt/pubkey
|
||||||
|
cat << EOF > /etc/wireguard/wg0.conf
|
||||||
|
[Interface]
|
||||||
|
Address = ${WIREGUARD_INTERFACE}
|
||||||
|
ListenPort = ${WIREGUARD_PORT}
|
||||||
|
PostUp = iptables -A FORWARD -i wg0 -j ACCEPT; iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE;
|
||||||
|
PostDown = iptables -D FORWARD -i wg0 -j ACCEPT; iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE;
|
||||||
|
PrivateKey = $(cat /opt/privkey)
|
||||||
|
SaveConfig = true
|
||||||
|
EOF
|
||||||
|
aws s3 cp /etc/wireguard/wg0.conf s3://${CONFIG_BUCKET}/wg0.conf
|
||||||
|
fi
|
||||||
|
|
||||||
|
|
||||||
|
# Install Rust and app as a systemd service
|
||||||
|
sudo apt install build-essential -y
|
||||||
|
|
||||||
|
cat << EOF > /opt/install_app.sh
|
||||||
|
#!/bin/bash
|
||||||
|
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | RUSTUP_HOME=~/.rustup sh -s -- -y
|
||||||
|
source ~/.cargo/env
|
||||||
|
git clone https://github.com/lalanza808/wgas-rs ~/wgas-rs
|
||||||
|
cd ~/wgas-rs
|
||||||
|
rustup override set nightly
|
||||||
|
cargo build --release
|
||||||
|
EOF
|
||||||
|
chmod +x /opt/install_app.sh
|
||||||
|
sudo -u ubuntu /opt/install_app.sh
|
||||||
|
useradd wgas-rs -s /sbin/nologin -M
|
||||||
|
cat << EOF > /lib/systemd/system/wgas-rs.service
|
||||||
|
[Unit]
|
||||||
|
Description=WireGuard Access Server Service
|
||||||
|
ConditionPathExists=/home/ubuntu/wgas-rs/target/release/wgas-rs
|
||||||
|
After=network.target
|
||||||
|
|
||||||
|
[Service]
|
||||||
|
Type=simple
|
||||||
|
User=wgas-rs
|
||||||
|
Group=wgas-rs
|
||||||
|
LimitNOFILE=1024
|
||||||
|
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=10
|
||||||
|
startLimitIntervalSec=60
|
||||||
|
|
||||||
|
WorkingDirectory=/home/ubuntu/wgas-rs
|
||||||
|
ExecStart=/home/ubuntu/wgas-rs/target/release/wgas-rs
|
||||||
|
|
||||||
|
# make sure log directory exists and owned by syslog
|
||||||
|
PermissionsStartOnly=true
|
||||||
|
ExecStartPre=/bin/mkdir -p /var/log/wgas-rs
|
||||||
|
ExecStartPre=/bin/chown syslog:adm /var/log/wgas-rs
|
||||||
|
ExecStartPre=/bin/chmod 755 /var/log/wgas-rs
|
||||||
|
StandardOutput=syslog
|
||||||
|
StandardError=syslog
|
||||||
|
SyslogIdentifier=wgas-rs
|
||||||
|
|
||||||
|
[Install]
|
||||||
|
WantedBy=multi-user.target
|
||||||
|
EOF
|
||||||
|
chmod 755 /lib/systemd/system/wgas-rs.service
|
||||||
|
systemctl daemon-reload
|
||||||
|
systemctl enable wgas-rs
|
||||||
|
systemctl start wgas-rs
|
@ -0,0 +1,77 @@
|
|||||||
|
data "aws_iam_policy_document" "vpn_assume_role" {
|
||||||
|
statement {
|
||||||
|
actions = ["sts:AssumeRole"]
|
||||||
|
|
||||||
|
principals {
|
||||||
|
type = "Service"
|
||||||
|
identifiers = [
|
||||||
|
"ec2.amazonaws.com"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "vpn" {
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"route53:ListHostedZones",
|
||||||
|
"route53:GetChange"
|
||||||
|
]
|
||||||
|
resources = [
|
||||||
|
"*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"route53:ChangeResourceRecordSets"
|
||||||
|
]
|
||||||
|
resources = [
|
||||||
|
"arn:aws:route53:::hostedzone/${data.aws_route53_zone.domain.zone_id}"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"ec2:AssociateAddress",
|
||||||
|
"ec2:DescribeInstances",
|
||||||
|
"ec2:DescribeNetworkInterfaces"
|
||||||
|
]
|
||||||
|
resources = [
|
||||||
|
"*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"s3:Put*",
|
||||||
|
"s3:Get*"
|
||||||
|
]
|
||||||
|
resources = [
|
||||||
|
"${aws_s3_bucket.configs.arn}/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_policy" "vpn" {
|
||||||
|
name_prefix = aws_iam_role.vpn.name
|
||||||
|
description = "WireGuard VPN server policy for managing resources on AWS"
|
||||||
|
policy = data.aws_iam_policy_document.vpn.json
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role" "vpn" {
|
||||||
|
name_prefix = "${var.prefix}-vpn-"
|
||||||
|
assume_role_policy = data.aws_iam_policy_document.vpn_assume_role.json
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy_attachment" "vpn" {
|
||||||
|
role = aws_iam_role.vpn.name
|
||||||
|
policy_arn = aws_iam_policy.vpn.arn
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_role_policy_attachment" "ssm" {
|
||||||
|
role = aws_iam_role.vpn.name
|
||||||
|
policy_arn = "arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore"
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_iam_instance_profile" "vpn" {
|
||||||
|
name = aws_iam_role.vpn.name
|
||||||
|
role = aws_iam_role.vpn.name
|
||||||
|
}
|
@ -0,0 +1,23 @@
|
|||||||
|
data "aws_route53_zone" "domain" {
|
||||||
|
name = var.domain_name
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_region" "current" {}
|
||||||
|
|
||||||
|
data "aws_caller_identity" "current" {}
|
||||||
|
|
||||||
|
data "aws_ami" "ubuntu" {
|
||||||
|
most_recent = true
|
||||||
|
|
||||||
|
filter {
|
||||||
|
name = "name"
|
||||||
|
values = ["ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*"]
|
||||||
|
}
|
||||||
|
|
||||||
|
filter {
|
||||||
|
name = "virtualization-type"
|
||||||
|
values = ["hvm"]
|
||||||
|
}
|
||||||
|
|
||||||
|
owners = ["099720109477"] # Canonical
|
||||||
|
}
|
@ -0,0 +1,63 @@
|
|||||||
|
resource "aws_security_group" "vpn" {
|
||||||
|
name_prefix = "${var.prefix}-vpn-"
|
||||||
|
description = "Allow connectivity to and from the WireGuard VPN instance."
|
||||||
|
vpc_id = var.vpc_id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group_rule" "vpn_access" {
|
||||||
|
type = "ingress"
|
||||||
|
from_port = var.wireguard_vpn_port
|
||||||
|
to_port = var.wireguard_vpn_port
|
||||||
|
protocol = "udp"
|
||||||
|
cidr_blocks = var.vpn_access_cidrs
|
||||||
|
security_group_id = aws_security_group.vpn.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group_rule" "management_access_80" {
|
||||||
|
type = "ingress"
|
||||||
|
from_port = 80
|
||||||
|
to_port = 80
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = var.management_access_cidrs
|
||||||
|
security_group_id = aws_security_group.vpn.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group_rule" "management_access_8000" {
|
||||||
|
type = "ingress"
|
||||||
|
from_port = 8000
|
||||||
|
to_port = 8000
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = var.management_access_cidrs
|
||||||
|
security_group_id = aws_security_group.vpn.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group_rule" "management_access_443" {
|
||||||
|
type = "ingress"
|
||||||
|
from_port = 443
|
||||||
|
to_port = 443
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = var.management_access_cidrs
|
||||||
|
security_group_id = aws_security_group.vpn.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group_rule" "management_access_22" {
|
||||||
|
type = "ingress"
|
||||||
|
from_port = 22
|
||||||
|
to_port = 22
|
||||||
|
protocol = "tcp"
|
||||||
|
cidr_blocks = var.management_access_cidrs
|
||||||
|
security_group_id = aws_security_group.vpn.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_security_group_rule" "vpn_egress" {
|
||||||
|
type = "egress"
|
||||||
|
from_port = 0
|
||||||
|
to_port = 65535
|
||||||
|
protocol = "-1"
|
||||||
|
cidr_blocks = ["0.0.0.0/0"]
|
||||||
|
security_group_id = aws_security_group.vpn.id
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_eip" "vpn" {
|
||||||
|
vpc = true
|
||||||
|
}
|
@ -0,0 +1,26 @@
|
|||||||
|
resource "aws_s3_bucket" "configs" {
|
||||||
|
bucket_prefix = "${var.prefix}-config-"
|
||||||
|
acl = "private"
|
||||||
|
}
|
||||||
|
|
||||||
|
data "aws_iam_policy_document" "config_policy" {
|
||||||
|
statement {
|
||||||
|
actions = [
|
||||||
|
"s3:*"
|
||||||
|
]
|
||||||
|
principals {
|
||||||
|
type = "AWS"
|
||||||
|
identifiers = [
|
||||||
|
aws_iam_role.vpn.arn
|
||||||
|
]
|
||||||
|
}
|
||||||
|
resources = [
|
||||||
|
"${aws_s3_bucket.configs.arn}/*"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
resource "aws_s3_bucket_policy" "configs" {
|
||||||
|
bucket = aws_s3_bucket.configs.id
|
||||||
|
policy = data.aws_iam_policy_document.config_policy.json
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
variable "prefix" {
|
||||||
|
default = "wireguard"
|
||||||
|
description = "String to use as a prefix when naming resources"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "domain_name" {
|
||||||
|
description = "Domain name to use for setting up Route 53 records"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "instance_type" {
|
||||||
|
default = "t3.small"
|
||||||
|
description = "EC2 instance type to provision for VPN server"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "key_name" {
|
||||||
|
description = "Key pair to use for provisioning EC2 instance"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "vpn_access_cidrs" {
|
||||||
|
default = ["0.0.0.0/0"]
|
||||||
|
description = "IP addresses which should be able to connect to the VPN"
|
||||||
|
type = list
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "management_access_cidrs" {
|
||||||
|
default = []
|
||||||
|
description = "IP addresses which should be able to reach the administrative interfaces (web/ssh)"
|
||||||
|
type = list
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "wireguard_vpn_port" {
|
||||||
|
default = 51820
|
||||||
|
description = "Port to use for WireGuard VPN (udp)"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "vpc_id" {
|
||||||
|
description = "ID of the VPC to deploy network resources into"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "public_subnets" {
|
||||||
|
description = "List of subnets for deploying WireGuard VPN servers into"
|
||||||
|
}
|
||||||
|
|
||||||
|
variable "wireguard_interface" {
|
||||||
|
default = "10.66.66.1/24"
|
||||||
|
description = "VPN tunnel interface IP and CIDR"
|
||||||
|
}
|
Loading…
Reference in New Issue