{ "AWSTemplateFormatVersion": "2010-09-09", "Mappings": { "OS": { "Ubuntu1804": { "HelperInstallationCommands": "export DEBIAN_FRONTEND=noninteractive\napt-get -yq update\napt-get -yq install python3-pip\npython3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz\n", "InstallationLinks": "https://git.io/vpnsetup" }, "Ubuntu2004": { "HelperInstallationCommands": "export DEBIAN_FRONTEND=noninteractive\napt-get -yq update\napt-get -yq install python3-pip\npython3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz\n", "InstallationLinks": "https://git.io/vpnsetup" }, "Debian9": { "HelperInstallationCommands": "export DEBIAN_FRONTEND=noninteractive\napt-get -yq update\napt-get -yq install python3-pip\npython3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz\n", "InstallationLinks": "https://git.io/vpnsetup" }, "CentOS7": { "HelperInstallationCommands": "yum -y install python3 wget\npython3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz\n", "InstallationLinks": "https://git.io/vpnsetup-centos" }, "CentOS8": { "HelperInstallationCommands": "yum -y install python3 wget\npython3 -m pip install https://s3.amazonaws.com/cloudformation-examples/aws-cfn-bootstrap-py3-latest.tar.gz\n", "InstallationLinks": "https://git.io/vpnsetup-centos" }, "AmazonLinux2": { "HelperInstallationCommands": "export PATH=\"$PATH:/opt/aws/bin\"\n", "InstallationLinks": "https://git.io/vpnsetup-amzn" } } }, "Metadata": { "AWS::CloudFormation::Designer": { "0a162613-8f2e-4864-be99-75d946934a4a": { "size": { "width": 350, "height": 440 }, "position": { "x": 290, "y": 70 }, "z": 1, "embeds": [ "5198eb6d-da4f-43e2-8a4b-b9bff02b26a2" ] }, "5198eb6d-da4f-43e2-8a4b-b9bff02b26a2": { "size": { "width": 290, "height": 360 }, "position": { "x": 310, "y": 110 }, "z": 2, "parent": "0a162613-8f2e-4864-be99-75d946934a4a", "embeds": [ "9d4cbbc2-f521-436d-bb4a-85b82cf22a2a", "464ea4ae-199c-4917-9404-aed674a8615a", "ec256f27-66c3-423c-9d98-b9f0f634e7b8", "4731d93c-f3fc-420a-b535-f0b99840f356", "40c2d4e7-f01a-45b2-8878-a06680aa2216" ], "dependson": [ "0a162613-8f2e-4864-be99-75d946934a4a", "464ea4ae-199c-4917-9404-aed674a8615a" ] }, "4731d93c-f3fc-420a-b535-f0b99840f356": { "size": { "width": 230, "height": 130 }, "position": { "x": 350, "y": 320 }, "z": 3, "parent": "5198eb6d-da4f-43e2-8a4b-b9bff02b26a2", "embeds": [ "5262ea47-2337-4be8-a4d1-1f0af38a1731" ], "iscontainedinside": [ "0a162613-8f2e-4864-be99-75d946934a4a" ], "dependson": [ "5198eb6d-da4f-43e2-8a4b-b9bff02b26a2" ] }, "5262ea47-2337-4be8-a4d1-1f0af38a1731": { "size": { "width": 60, "height": 60 }, "position": { "x": 440, "y": 350 }, "z": 4, "parent": "4731d93c-f3fc-420a-b535-f0b99840f356", "embeds": [], "isassociatedwith": [ "db7c3441-9f9a-4677-a14d-bccfc06714d1" ], "dependson": [ "4731d93c-f3fc-420a-b535-f0b99840f356", "9d3d19ab-d561-4f59-89de-73498eeeebda", "464ea4ae-199c-4917-9404-aed674a8615a" ] }, "464ea4ae-199c-4917-9404-aed674a8615a": { "size": { "width": 60, "height": 60 }, "position": { "x": 510, "y": 220 }, "z": 3, "parent": "5198eb6d-da4f-43e2-8a4b-b9bff02b26a2", "embeds": [], "dependson": [ "0a162613-8f2e-4864-be99-75d946934a4a" ] }, "40c2d4e7-f01a-45b2-8878-a06680aa2216": { "size": { "width": 60, "height": 60 }, "position": { "x": 430, "y": 140 }, "z": 3, "parent": "5198eb6d-da4f-43e2-8a4b-b9bff02b26a2", "embeds": [], "iscontainedinside": [ "5198eb6d-da4f-43e2-8a4b-b9bff02b26a2" ], "dependson": [ "4731d93c-f3fc-420a-b535-f0b99840f356", "9d4cbbc2-f521-436d-bb4a-85b82cf22a2a", "99fce86e-18b8-4b1b-a572-7bef3c5cece7", "58a1ab6f-49ac-4ffa-93c7-3f708bf65871", "ec256f27-66c3-423c-9d98-b9f0f634e7b8" ] }, "9d4cbbc2-f521-436d-bb4a-85b82cf22a2a": { "size": { "width": 60, "height": 60 }, "position": { "x": 350, "y": 140 }, "z": 3, "parent": "5198eb6d-da4f-43e2-8a4b-b9bff02b26a2", "embeds": [] }, "ec256f27-66c3-423c-9d98-b9f0f634e7b8": { "size": { "width": 60, "height": 60 }, "position": { "x": 430, "y": 220 }, "z": 3, "parent": "5198eb6d-da4f-43e2-8a4b-b9bff02b26a2", "embeds": [], "iscontainedinside": [ "0a162613-8f2e-4864-be99-75d946934a4a" ] }, "5bb16646-dc1e-4661-9164-6ecc6848dc83": { "source": { "id": "4731d93c-f3fc-420a-b535-f0b99840f356" }, "target": { "id": "5198eb6d-da4f-43e2-8a4b-b9bff02b26a2" }, "z": 3 }, "99fce86e-18b8-4b1b-a572-7bef3c5cece7": { "size": { "width": 60, "height": 60 }, "position": { "x": 150, "y": 250 }, "z": 1, "embeds": [] }, "58a1ab6f-49ac-4ffa-93c7-3f708bf65871": { "size": { "width": 60, "height": 60 }, "position": { "x": 150, "y": 170 }, "z": 1, "embeds": [] }, "d3fab7a7-d694-435e-930d-ff7693dffbbc": { "size": { "width": 60, "height": 60 }, "position": { "x": 110, "y": 90 }, "z": 1, "embeds": [] }, "2c5cc5a9-5a17-4d54-80ea-56e204c9c1a1": { "size": { "width": 60, "height": 60 }, "position": { "x": 70, "y": 170 }, "z": 1, "embeds": [] }, "e81dfbbc-e8ee-4f4b-adb0-b314056ab0b3": { "size": { "width": 60, "height": 60 }, "position": { "x": 70, "y": 250 }, "z": 1, "embeds": [] }, "9d3d19ab-d561-4f59-89de-73498eeeebda": { "source": { "id": "0a162613-8f2e-4864-be99-75d946934a4a" }, "target": { "id": "464ea4ae-199c-4917-9404-aed674a8615a" }, "z": 3 }, "361e0035-6c5a-48df-8339-3e31f19bf032": { "source": { "id": "9d4cbbc2-f521-436d-bb4a-85b82cf22a2a" }, "target": { "id": "40c2d4e7-f01a-45b2-8878-a06680aa2216" }, "z": 3 } } }, "Resources": { "VpnVpc": { "Type": "AWS::EC2::VPC", "Properties": { "CidrBlock": "10.0.0.0/24" }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "0a162613-8f2e-4864-be99-75d946934a4a" } } }, "VpnSubnet": { "Type": "AWS::EC2::Subnet", "Properties": { "VpcId": { "Ref": "VpnVpc" }, "CidrBlock": "10.0.0.0/24", "MapPublicIpOnLaunch": true, "AvailabilityZone": { "Fn::Select": [ "0", { "Fn::GetAZs": "" } ] } }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "5198eb6d-da4f-43e2-8a4b-b9bff02b26a2" } }, "DependsOn": [ "VpnVpc", "VpcInternetGateway" ] }, "VpnRouteTable": { "Type": "AWS::EC2::RouteTable", "Properties": { "VpcId": { "Ref": "VpnVpc" } }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "4731d93c-f3fc-420a-b535-f0b99840f356" } }, "DependsOn": [ "VpnSubnet" ] }, "PublicInternetRoute": { "Type": "AWS::EC2::Route", "Properties": { "DestinationCidrBlock": "0.0.0.0/0", "RouteTableId": { "Ref": "VpnRouteTable" }, "GatewayId": { "Ref": "VpcInternetGateway" } }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "5262ea47-2337-4be8-a4d1-1f0af38a1731" } }, "DependsOn": [ "VpnRouteTable", "VpcInternetGateway", "InternetGatewayAttachment" ] }, "VpnInstance": { "Type": "AWS::EC2::Instance", "CreationPolicy": { "ResourceSignal": { "Timeout": "PT15M" } }, "Properties": { "UserData": { "Fn::Base64": { "Fn::Join": [ "", [ "#!/bin/bash -xe\n", "trap 'cfn-signal -e 1 ", " --stack ", { "Ref": "AWS::StackName" }, " --resource VpnInstance ", " --region ", { "Ref": "AWS::Region" }, "' ERR\n", "sleep 60\n", { "Fn::FindInMap": [ "OS", { "Ref": "OS" }, "HelperInstallationCommands" ] }, "export VPN_IPSEC_PSK='", { "Ref": "VpnIpsecPsk" }, "'\n", "export VPN_USER='", { "Ref": "VpnUser" }, "'\n", "export VPN_PASSWORD='", { "Ref": "VpnPassword" }, "'\n", "wget -t 3 -T 30 -nv -O vpn.sh ", { "Fn::FindInMap": [ "OS", { "Ref": "OS" }, "InstallationLinks" ] }, "\n", "sh vpn.sh\n", "cfn-signal -e 0 ", " --stack ", { "Ref": "AWS::StackName" }, " --resource VpnInstance ", " --region ", { "Ref": "AWS::Region" }, "\n" ] ] } }, "SecurityGroupIds": [ { "Fn::GetAtt": [ "VpnSecurityGroup", "GroupId" ] } ], "SubnetId": { "Ref": "VpnSubnet" }, "AvailabilityZone": { "Fn::Select": [ "0", { "Fn::GetAZs": "" } ] }, "InstanceType": { "Ref": "InstanceType" }, "KeyName": { "Fn::GetAtt": [ "KeyPairInfo", "KeyName" ] }, "ImageId": { "Fn::GetAtt": [ "AMIInfo", "AMIId" ] } }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "40c2d4e7-f01a-45b2-8878-a06680aa2216" } }, "DependsOn": [ "VpnRouteTable", "VpnServerVolume", "KeyPairCreation", "AMIInfoFunction", "VpnSecurityGroup" ] }, "VpnSecurityGroup": { "Type": "AWS::EC2::SecurityGroup", "Properties": { "GroupDescription": "The VPN Security Group, allowing ingress UDP traffic at port 4500 and 500.", "GroupName": "VpnSecurityGroup", "VpcId": { "Ref": "VpnVpc" }, "SecurityGroupIngress": [ { "CidrIp": "0.0.0.0/0", "IpProtocol": "tcp", "FromPort": 22, "ToPort": 22 }, { "CidrIp": "0.0.0.0/0", "IpProtocol": "udp", "FromPort": 500, "ToPort": 500 }, { "CidrIp": "0.0.0.0/0", "IpProtocol": "udp", "FromPort": 4500, "ToPort": 4500 } ], "SecurityGroupEgress": [ { "CidrIp": "0.0.0.0/0", "IpProtocol": -1 } ] }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "ec256f27-66c3-423c-9d98-b9f0f634e7b8" } } }, "VpnServerVolume": { "Type": "AWS::EC2::Volume", "Properties": { "AvailabilityZone": { "Fn::Select": [ "0", { "Fn::GetAZs": "" } ] }, "Size": 8 }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "9d4cbbc2-f521-436d-bb4a-85b82cf22a2a" } } }, "VpcInternetGateway": { "Type": "AWS::EC2::InternetGateway", "Properties": {}, "Metadata": { "AWS::CloudFormation::Designer": { "id": "464ea4ae-199c-4917-9404-aed674a8615a" } }, "DependsOn": [ "VpnVpc" ] }, "EC2SRTA4VJU5": { "Type": "AWS::EC2::SubnetRouteTableAssociation", "Properties": { "RouteTableId": { "Ref": "VpnRouteTable" }, "SubnetId": { "Ref": "VpnSubnet" } }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "5bb16646-dc1e-4661-9164-6ecc6848dc83" } } }, "KeyPairCreation": { "Type": "AWS::Lambda::Function", "Properties": { "Handler": "index.handler", "Runtime": "python3.7", "Role": { "Fn::GetAtt": [ "LambdaExecutionRole", "Arn" ] }, "Timeout": 30, "Code": { "ZipFile": { "Fn::Join": [ "\n", [ "import boto3", "import cfnresponse", "import string", "import random", "'''", "This python program should be embedded into its designated cloudformation", "template as the inline code of one of the lambda functions.", "'''", "def handler(event, context):", " try:", " keyName = 'setup-ipsec-vpn-' + ''.join(random.SystemRandom().choice(string.ascii_letters + string.digits) for _ in range(10))", " region = event['ResourceProperties']['Region']", " ec2 = boto3.client('ec2',region)", " response = ec2.create_key_pair(", " KeyName=keyName", " )", " keyMaterial = response['KeyMaterial']", " cfnresponse.send(event, context, cfnresponse.SUCCESS, {'KeyMaterial':keyMaterial, 'KeyName':keyName}, 'KeyPairInfo')", " except Exception:", " cfnresponse.send(event, context, cfnresponse.FAILED, {})" ] ] } } }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "99fce86e-18b8-4b1b-a572-7bef3c5cece7" } }, "DependsOn": [ "LambdaExecutionRole" ] }, "AMIInfo": { "Type": "Custom::AMIInfo", "Properties": { "Region": { "Ref": "AWS::Region" }, "ServiceToken": { "Fn::GetAtt": [ "AMIInfoFunction", "Arn" ] }, "Distribution": { "Ref": "OS" } }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "2c5cc5a9-5a17-4d54-80ea-56e204c9c1a1" } }, "DependsOn": [ "AMIInfoFunction" ] }, "AMIInfoFunction": { "Type": "AWS::Lambda::Function", "Properties": { "Handler": "index.handler", "Runtime": "python3.7", "Role": { "Fn::GetAtt": [ "LambdaExecutionRole", "Arn" ] }, "Code": { "ZipFile": { "Fn::Join": [ "\n", [ "import boto3", "import cfnresponse", "'''", "This python script should be embeded into its designated cloudformation template.", "Its function is to sort out the correct AMI image to use for each of the distribution options available.", "'''", "def creation_date(e):", " return e['CreationDate']", "", "def handler(event, context):", " try:", " regionName = event['ResourceProperties']['Region']", " distribution = event['ResourceProperties']['Distribution']", " ec2 = boto3.client('ec2',regionName)", " AMIName = {", " 'Ubuntu1804': 'ubuntu/images/hvm-ssd/ubuntu-bionic-18.04-amd64-server-*',", " 'Ubuntu2004': 'ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*',", " 'Debian9': 'debian-stretch-hvm-x86_64-gp2-*',", " 'CentOS7': 'CentOS 7.9.2009 x86_64',", " 'CentOS8': 'CentOS 8.3.2011 x86_64',", " 'AmazonLinux2': 'amzn2-ami-hvm-*.*-x86_64-gp2',", " }[distribution]", " response = ec2.describe_images(Filters=[{'Name':'name', 'Values':[AMIName]}], Owners=['099720109477', '379101102735', '125523088429', 'amazon'])", " images = response['Images']", " images.sort(key=creation_date,reverse=True)", " AMIId = images[0]['ImageId']", " cfnresponse.send(event, context, cfnresponse.SUCCESS, {'AMIId':AMIId}, 'AMIInfo')", " except Exception:", " cfnresponse.send(event, context, cfnresponse.FAILED, {})" ] ] } }, "Timeout": 30 }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "58a1ab6f-49ac-4ffa-93c7-3f708bf65871" } }, "DependsOn": [ "LambdaExecutionRole" ] }, "LambdaExecutionRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": "lambda.amazonaws.com" }, "Action": [ "sts:AssumeRole" ] }, { "Effect": "Allow", "Principal": { "Service": [ "ec2.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "root", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": "*", "Resource": "*" } ] } } ] }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "d3fab7a7-d694-435e-930d-ff7693dffbbc" } } }, "KeyPairInfo": { "Type": "Custom::KeyPairInfo", "Properties": { "Region": { "Ref": "AWS::Region" }, "ServiceToken": { "Fn::GetAtt": [ "KeyPairCreation", "Arn" ] } }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "e81dfbbc-e8ee-4f4b-adb0-b314056ab0b3" } }, "DependsOn": [ "KeyPairCreation" ] }, "InternetGatewayAttachment": { "Type": "AWS::EC2::VPCGatewayAttachment", "Properties": { "InternetGatewayId": { "Ref": "VpcInternetGateway" }, "VpcId": { "Ref": "VpnVpc" } }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "9d3d19ab-d561-4f59-89de-73498eeeebda" } } }, "EC2VA41EUF": { "Type": "AWS::EC2::VolumeAttachment", "Properties": { "Device": "/dev/sdh", "VolumeId": { "Ref": "VpnServerVolume" }, "InstanceId": { "Ref": "VpnInstance" } }, "Metadata": { "AWS::CloudFormation::Designer": { "id": "361e0035-6c5a-48df-8339-3e31f19bf032" } } } }, "Parameters": { "VpnUser": { "Type": "String", "Description": "Your VPN username" }, "VpnIpsecPsk": { "Type": "String", "Description": "Your VPN IPsec PSK (pre-shared key)" }, "VpnPassword": { "Type": "String", "Description": "Your VPN password" }, "OS": { "Type": "String", "Description": "The OS of your VPN server. Default: Ubuntu 20.04", "Default": "Ubuntu2004", "AllowedValues": [ "Ubuntu2004", "Ubuntu1804", "Debian9", "CentOS7", "CentOS8", "AmazonLinux2" ] }, "InstanceType": { "Type": "String", "Description": "The instance type of your VPN server. Using t2.micro may qualify for the AWS Free Tier.", "AllowedValues": [ "t2.micro", "t3.nano", "m5.large", "t3.micro", "t3.small", "t2.nano", "t2.small", "t3a.nano", "t3a.micro", "t3a.small", "m5a.large", "t1.micro" ], "Default": "t2.micro" } }, "Outputs": { "VPNAddress": { "Description": "This is the public IP of your newly-launched VPN server.", "Value": { "Fn::GetAtt": [ "VpnInstance", "PublicIp" ] } }, "VPNUsername": { "Description": "Your VPN username", "Value": { "Ref": "VpnUser" } }, "VPNPassword": { "Description": "Your VPN password", "Value": { "Ref": "VpnPassword" } }, "VPNKey": { "Description": "Your VPN IPsec PSK (pre-shared key)", "Value": { "Ref": "VpnIpsecPsk" } }, "EC2PrivateKeyMaterial": { "Description": "The content of your private key for accessing the VPN server via SSH. Save it as a file for use when connecting.", "Value": { "Fn::GetAtt": [ "KeyPairInfo", "KeyMaterial" ] } }, "NextStep": { "Description": "Learn how to configure VPN clients.", "Value": "https://github.com/hwdsl2/setup-ipsec-vpn#next-steps" } } }