【悪用厳禁!!】【AWS】【CloudFormation】EC2で海外にVPNサーバを構築して自分のPCから接続する方法

# 前提
- [AWS VPN](https://aws.amazon.com/jp/vpn/)とは関係ないのでご注意ください
- AWSアカウントが事前に作成済み、または自ら調べてアカウント作成の上、支払い設定までできること
- 完全に無料ではないこと(EC2やEIPが時間やデータ通信量で課金が発生します)
- AWSのムンバイリージョンにVPNサーバを立てていること(別リージョンにしたい場合は以下を変更すること)
    - 手順中のムンバイリージョンを選択の部分を任意のリージョンにする
    - CloudFormationテンプレート
        - PublicSubnetAAZ
        - EC2InstanceConnectRegionCIDRIp([AWSが提供するIPレンジ](https://ip-ranges.amazonaws.com/ip-ranges.json))
- 最後に、VPN接続を利用して発生した個人の問題に関しては自己責任でよろしくお願いします

# はじめに
世の中のあらゆるサービスはしばしば日本と海外で内容や価格が異なる場合があります。
｢海外Netflixだとジブリが見れる｣、｢YoutubePremiumが海外だと月あたり約1000円お得｣といった具体例を聞いたことがあるのではないでしょうか。
その差を日本にいながら払拭する一つの方法として、VPN接続があります。
利用したい国にサーバを立て、自分のPCからVPN接続することで、さもその国からアクセスしているかのように振る舞うことができます。

このVPC接続を月額〇〇円で使えるExpressVPNやNordVPNといったサービスが存在するのですが、今やクラウドで一般人が簡単にサーバを立てることができる時代です。今回は私がAWS上にCloudFormationを利用してVPC含むネットワークリソース、EC2でSoftEther VPNをインストールしたVPNサーバを構築し、MACから接続した方法を共有します。

# CloudFormationとは
AWSが提供するIaC(Infrastructure as Code)サービスのことです。
IaC自体は、アプリのインフラ部分をコード化・ファイル化して管理する手法を指し、再現性や可搬性、また再作成を簡単にしてくれます。

# SoftEther VPNとは
オープンソースの、無償で、複数プラットフォームおよび複数 VPN プロトコル対応の VPN ソフトウェアです。
筑波大学における研究プロジェクトとして運営されています。

# 手順
1. CloudFormationテンプレートファイルをローカルに作成(下記参考)
1. AWSマネジメントコンソールにログインし、ムンバイリージョンを選択
1. 検索フィールドからCloudFormationに移動
1. ｢新規スタックの作成>テンプレートファイルのアップロード｣からローカルのテンプレートファイルを選択
1. 任意のスタック名を入力し、他はデフォルトのままスタック作成
1. スタック作成完了を待つ
1. 完了後、検索フィールドからEC2に移動
1. 作成されたEC2インスタンスを選択し、｢接続>Instance Connect｣を実行
1. EC2内の操作からVPN接続までの手順は参考リンク[AWS EC2 でVPNサーバーを建てる](https://blog.odaryo.com/2021/08/create-vpn-in-ec2/#toc5)を参照とさせてください
1. 〜VPNサーバを使ってやりたいこと〜
1. 検索フィールドからCloudFormationに移動
1. スタックの削除(EC2やEIPが時間で課金されてしまうため)

# 参考リンク
- [CloudFormationでインドVPN用EC2構築してみた(Youtube Premium格安利用を目指して)](https://billest.hatenadiary.org/entry/2021/05/16/045210)
- [AWS EC2 でVPNサーバーを建てる](https://blog.odaryo.com/2021/08/create-vpn-in-ec2/#toc5)

# CloudFormationテンプレート(<任意のファイル名>.yamlでローカル上に保存してください)
```yaml
AWSTemplateFormatVersion: "2010-09-09"
Description: 
  VPN Resources Create

# ------------------------------------------------------------#
# Input Parameters
# ------------------------------------------------------------# 
Parameters:
  PJPrefix:
    Type: String
    Default: "vpn"

  VPCCIDR:
    Type: String
    Default: "10.1.0.0/16"

  PublicSubnetACIDR:
    Type: String
    Default: "10.1.10.0/24"

  PublicSubnetAAZ:
    Type: String
    Default: "ap-south-1a"

  EC2InstanceConnectRegionCIDRIp:
    Type: String
    Default: "13.233.177.0/29"

  EC2InstanceImageId:
    Type: String
    Default: "ami-010aff33ed5991201"

  EC2InstanceType:
    Type: String
    Default: "t2.micro"

Resources: 
# ------------------------------------------------------------#
#  VPC
# ------------------------------------------------------------#
# VPC Create
  VPC: 
    Type: "AWS::EC2::VPC"
    Properties: 
      CidrBlock: !Ref VPCCIDR
      EnableDnsSupport: "true"
      EnableDnsHostnames: "true"
      InstanceTenancy: default
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-vpc"

# InternetGateway Create
  InternetGateway: 
    Type: "AWS::EC2::InternetGateway"
    Properties: 
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-igw"

# IGW Attach
  InternetGatewayAttachment: 
    Type: "AWS::EC2::VPCGatewayAttachment"
    Properties: 
      InternetGatewayId: !Ref InternetGateway
      VpcId: !Ref VPC 

# ------------------------------------------------------------#
#  Subnet
# ------------------------------------------------------------#          
# Public SubnetA Create
  PublicSubnetA: 
    Type: "AWS::EC2::Subnet"
    Properties: 
      AvailabilityZone: !Ref PublicSubnetAAZ
      CidrBlock: !Ref PublicSubnetACIDR
      VpcId: !Ref VPC
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-public-subnet-a"

# ------------------------------------------------------------#
#  RouteTable
# ------------------------------------------------------------#          
# Public RouteTableA Create
  PublicRouteTableA: 
    Type: "AWS::EC2::RouteTable"
    Properties: 
      VpcId: !Ref VPC
      Tags: 
        - Key: Name
          Value: !Sub "${PJPrefix}-public-route-a"

# ------------------------------------------------------------#
# Routing
# ------------------------------------------------------------# 
# PublicRouteA Create
  PublicRouteA: 
    Type: "AWS::EC2::Route"
    Properties: 
      RouteTableId: !Ref PublicRouteTableA 
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref InternetGateway

# ------------------------------------------------------------#
# RouteTable Associate
# ------------------------------------------------------------# 
# PublicRouteTable Associate SubnetA
  PublicSubnetARouteTableAssociation: 
    Type: "AWS::EC2::SubnetRouteTableAssociation"
    Properties: 
      SubnetId: !Ref PublicSubnetA
      RouteTableId: !Ref PublicRouteTableA

# ------------------------------------------------------------#
# SecurityGroup
# ------------------------------------------------------------# 
# SGEC2 Create
  SGEC2:
    Type: 'AWS::EC2::SecurityGroup'
    Properties:
      VpcId: !Ref VPC
      GroupDescription: ssh login
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 22
          ToPort: 22
          CidrIp: !Ref EC2InstanceConnectRegionCIDRIp
        - IpProtocol: udp
          FromPort: 4500
          ToPort: 4500
          CidrIp: 0.0.0.0/0
        - IpProtocol: udp
          FromPort: 500
          ToPort: 500
          CidrIp: 0.0.0.0/0

# ------------------------------------------------------------#
# EC2 Instance
# ------------------------------------------------------------# 
# EC2VPN Create
  EC2VPN:
    Type: 'AWS::EC2::Instance'
    Properties:
      ImageId: !Ref EC2InstanceImageId
      InstanceType: !Ref EC2InstanceType
      SubnetId: !Ref PublicSubnetA
      SecurityGroupIds:
        - !Ref SGEC2

# ------------------------------------------------------------#
# EIP
# ------------------------------------------------------------# 
# EIPEC2 Create
  EIPEC2:
    Type: AWS::EC2::EIP
    Properties:
      Domain: "vpc"

# ------------------------------------------------------------#
# EIPAssociation
# ------------------------------------------------------------# 
# EIPAssociation Create
  EIPAssociation:
    Type: AWS::EC2::EIPAssociation
    Properties: 
      AllocationId: !GetAtt EIPEC2.AllocationId
      InstanceId: !Ref EC2VPN
```

# おわりに
私は以前、NordVPNを使ったことがあります。しかし、その際はなんやかんや1000円程度かかった記憶があり、コスト削減と勉強も兼ねて自分で構築してみました。みなさんのVPN利用の選択肢の一つになれば嬉しいです。

最後まで読んでくださりありがとうございます。
この投稿が参考になりましたら｢いいね｣いただけると励みになります。