0
0

More than 3 years have passed since last update.

CloudFormation でオンプレ環境を模した NW を造ってみる

Last updated at Posted at 2021-03-30

はじめに

_s__o_ です。
AWS で検証をする際、お客様オンプレ環境が必要になる場合があります (Site-to-Site VPN 経由での接続など)。

とは言えど、おいそれと簡単に用意できるものではないので、代替として「オンプレ環境を模した」 AWS の NW を構築します。手動でポチポチと作成してもいいのですが、あくまで検証用途 (=使い終わったらすぐに消す) の想定のため、環境の改廃がしやすい CloudFormation を使いたいと思います。

検証 NW の構築

構成イメージ

赤太字の箇所が、CloudFormation で作成する部分です。
cf.png

CloudFormation のコード (YAML)

細かい中身は [前提事項] をご確認ください。

AWSTemplateFormatVersion: 2010-09-09
# ------------------------------------------------------------#
#  [前提事項]
#  ・疑似オンプレ環境 (以下、疑似オンプレ) を想定した VPC。
#  ・Site-to-Site VPN を用いて AWS (以下、接続先 AWS) に接続する想定。
#  ・ALB にアクセスさせる (=名前解決必要) ため、AWS の Route53 Resolver を参照させる想定。
#  ・このテンプレートで作成するオブジェクトは下記の通り。無料、且つ、作りきり (変更の可能性が低い) のものを対象としている (故に、すべて NW 系のオブジェクト)
#    - DHCP オプションセット x 1
#    - VCP x 1
#    - サブネット x 2
#    - ルートテーブル x 2
#    - インターネット GW x 1
#    - ENI x 2
#
#  ・このテンプレートで対象外のオブジェクト (=自分で作成する必要がある) は下記の通り。
#    - 疑似オンプレ側
#      -- セキュリティグループ
#      -- VPN ルータ@パブリック NW ※VyOS など
#      -- EC2 サーバ@プライベート NW
#    - 接続先 AWS 側
#      -- CGW 設定
#      -- VPN 設定
#      -- VGW or TGW 設定
#      -- Route53 設定
#      -- Route53 Resolver 設定
#
#  [留意事項]
#  ・VPC の名前解決を Off にすると、SSH の接続に時間がかかる。下記 URL を参考にして、
#    sshd_config の修正を推奨する (「UseDNS=no」、「GSSAPIAuthentication no」)
#    https://yuyarin.hatenadiary.org/entry/20090410/1239298235
#  ・VyOS の場合は「set service ssh disable-host-validation」で DNS 名前解決を無効化できる。
# ------------------------------------------------------------#

# ------------------------------------------------------------#
#  Parameter
# ------------------------------------------------------------#

Parameters:

  # 疑似オンプレの VPC 名。
  VpcNAME:
    Type: String
    Description: VPC name.

  # 疑似オンプレの CIDR (例 : 172.31.0.0/16)
  VpcCIDR:
    Type: String
    Description: VPC CIDR address.

  # 疑似オンプレのパブリック NW (例 : 172.31.1.0/24)
  PublicNwCIDR:
    Type: String
    Description: Public NW CIDR address.

  # 疑似オンプレのプライベート NW (例 : 172.31.101.0/24)
  PrivateNwCIDR:
    Type: String
    Description: Private NW CIDR address.

  # 疑似オンプレの VPN ルータ@パブリック NW の IP アドレス (例 : 172.31.1.254)
  PublicVpnrt1IP:
    Type: String
    Description: Public VPN Router01 IP address (Private IP address).

  # 疑似オンプレの サーバ@プライベート NW の IP アドレス (例 : 172.31.101.51)
  PrivateSv1IP:
    Type: String
    Description: Private Server01 IP address.

  # 接続先 AWS の Route53 Resolver の IP。DHCP オプションセットで使用する。複数の場合はコンマ区切りで記入する (例 : 192.168.100.100, 192.168.101.100)
  Route53ResolverIP:
    Type: String
    Description: Route53Resolver IP address.

  # 接続先 AWS の CIDR。ルートテーブルで使用する。
  RemoteSiteNwCIDR:
    Type: String
    Description: Remote NW CIDR address.

# ------------------------------------------------------------#
#  Resources
# ------------------------------------------------------------#

Resources:

# ------------------------------------------------------------#
#  1. AWS::EC2::DHCPOptions
# ------------------------------------------------------------#

# オンプレ想定の VPC のため、AWS の DNS (Route53 Resolver) を
# サーバの DNS として指定する。
  DHCP:
    Type: AWS::EC2::DHCPOptions
    Properties:
      DomainNameServers:
        - !Ref Route53ResolverIP
      Tags:
        - Key: Name
          Value: !Sub "dhcp-${VpcNAME}"

# ------------------------------------------------------------#
#  2. AWS::EC2::VPC
# ------------------------------------------------------------#

# オンプレ想定の VPC のため、EnableDnsSupport (Amazon DNS の利用)、
# EnableDnsHostnames (Amazon DNS 名の付与) は false とする。
  VPC:
    Type: "AWS::EC2::VPC"
    Properties:
      CidrBlock: !Ref VpcCIDR
      EnableDnsSupport: "false"
      EnableDnsHostnames: "false"
      InstanceTenancy: default
      Tags:
        - Key: Name
          Value: !Sub "${VpcNAME}"

# ------------------------------------------------------------#
#  3. AWS::EC2::VPCDHCPOptionsAssociation
# ------------------------------------------------------------#
  VpcDhcpAssociation:
    Type: AWS::EC2::VPCDHCPOptionsAssociation
    DependsOn:
      - VPC
      - DHCP
    Properties:
      VpcId: !Ref VPC
      DhcpOptionsId: !Ref DHCP

# ------------------------------------------------------------#
#  4. AWS::EC2::Subnet
# ------------------------------------------------------------#

  NwPublic1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref PublicNwCIDR
      MapPublicIpOnLaunch: 'true'
      AvailabilityZone: "ap-northeast-1a"
      Tags:
        - Key: Name
          Value: !Sub "nw-${VpcNAME}-public1"

  NwPrivate1:
    Type: 'AWS::EC2::Subnet'
    Properties:
      VpcId: !Ref VPC
      CidrBlock: !Ref PrivateNwCIDR
      MapPublicIpOnLaunch: 'false'
      AvailabilityZone: "ap-northeast-1c"
      Tags:
        - Key: Name
          Value: !Sub "nw-${VpcNAME}-private1"

# ------------------------------------------------------------#
#  5. AWS::EC2::RouteTable
# ------------------------------------------------------------#

  RtPublic:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub "rt-${VpcNAME}-public"

  RtPrivate:
    Type: 'AWS::EC2::RouteTable'
    Properties:
      VpcId: !Ref VPC
      Tags:
        - Key: Name
          Value: !Sub "rt-${VpcNAME}-private"

# ------------------------------------------------------------#
#  6. AWS::EC2::InternetGateway
# ------------------------------------------------------------#

  IGW:
    Type: 'AWS::EC2::InternetGateway'
    Properties:
      Tags:
        - Key: Name
          Value: !Sub "igw-${VpcNAME}"

# ------------------------------------------------------------#
#  7. AWS::EC2::VPCGatewayAttachment
# ------------------------------------------------------------#

  IgwAttachGateway:
    Type: 'AWS::EC2::VPCGatewayAttachment'
    DependsOn:
      - VPC
      - IGW
    Properties:
      VpcId: !Ref VPC
      InternetGatewayId: !Ref IGW

# ------------------------------------------------------------#
#  8. AWS::EC2::SubnetRouteTableAssociation
# ------------------------------------------------------------#

  RouteTableAssociationPublic:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    DependsOn:
      - NwPublic1
      - RtPublic
    Properties:
      SubnetId: !Ref NwPublic1
      RouteTableId: !Ref RtPublic

  RouteTableAssociationPrivate:
    Type: 'AWS::EC2::SubnetRouteTableAssociation'
    DependsOn:
      - NwPrivate1
      - RtPrivate
    Properties:
      SubnetId: !Ref NwPrivate1
      RouteTableId: !Ref RtPrivate

# ------------------------------------------------------------#
#  9. AWS::EC2::SecurityGroup
# ------------------------------------------------------------#

# 変更が頻繁に発生して管理が面倒なので、セキュリティグループは作成しない。

  # SgPublicVpnrt:
  #   Type: 'AWS::EC2::SecurityGroup'
  #   DependsOn:
  #     - VPC
  #   Properties:
  #     GroupName: !Sub "sgr-${VpcNAME}-public-vpnrt"
  #     GroupDescription: 'For public VPN router.'
  #     VpcId: !Ref VPC
  #     Tags:
  #       - Key: Name
  #         Value: !Sub "sgr-${VpcNAME}-public-vpnrt"

  # SgPrivateSV:
  #   Type: 'AWS::EC2::SecurityGroup'
  #   DependsOn:
  #     - VPC
  #   Properties:
  #     GroupName: !Sub "sgr-${VpcNAME}-private-sv"
  #     GroupDescription: 'For private EC2 server.'
  #     VpcId: !Ref VPC
  #     Tags:
  #       - Key: Name
  #         Value: !Sub "sgr-${VpcNAME}-private-sv"

# ------------------------------------------------------------#
#  10. AWS::EC2::NetworkInterface
# ------------------------------------------------------------#

  EniPublicVpnrt1:
    Type: AWS::EC2::NetworkInterface
    DependsOn:
      - NwPublic1
    Properties:
      SourceDestCheck: 'false'
      SubnetId: !Ref NwPublic1
      PrivateIpAddress: !Ref PublicVpnrt1IP
      Tags:
        - Key: 'Name'
          Value: !Sub "eni-${VpcNAME}-public-vpnrt1"

  EniPrivateSv1:
    Type: AWS::EC2::NetworkInterface
    DependsOn:
      - NwPrivate1
    Properties:
      SourceDestCheck: 'true'
      SubnetId: !Ref NwPrivate1
      PrivateIpAddress: !Ref PrivateSv1IP
      Tags:
        - Key: 'Name'
          Value: !Sub "eni-${VpcNAME}-private-sv1"

# ------------------------------------------------------------#
#  11. AWS::EC2::Route
# ------------------------------------------------------------#

# Default : 0.0.0.0/0

  RtPublicDefault:
    Type: 'AWS::EC2::Route'
    DependsOn:
      - RtPublic
      - IGW
    Properties:
      RouteTableId: !Ref RtPublic
      DestinationCidrBlock: "0.0.0.0/0"
      GatewayId: !Ref IGW

# Remote Site

  RtPublicRemoteSite:
    Type: 'AWS::EC2::Route'
    DependsOn:
      - RtPublic
      - EniPublicVpnrt1
    Properties:
      RouteTableId: !Ref RtPublic
      DestinationCidrBlock: !Ref RemoteSiteNwCIDR
      NetworkInterfaceId: !Ref EniPublicVpnrt1

  RtPrivateRemoteSite:
    Type: 'AWS::EC2::Route'
    DependsOn:
      - RtPrivate
      - EniPublicVpnrt1
    Properties:
      RouteTableId: !Ref RtPrivate
      DestinationCidrBlock: !Ref RemoteSiteNwCIDR
      NetworkInterfaceId: !Ref EniPublicVpnrt1

# ------------------------------------------------------------#
#  Outputs
# ------------------------------------------------------------#

Outputs:

  VpcID:
    Value: !Ref VPC
    Export:
      Name: !Sub "${VpcNAME}-VPC"

  NwPublic1ID:
    Value: !Ref NwPublic1
    Export:
      Name: !Sub "${VpcNAME}-NW-Public1"

  NwPrivate1ID:
    Value: !Ref NwPrivate1
    Export:
      Name: !Sub "${VpcNAME}-NW-Private1"

  # SgPublicVpnrt:
  #   Value: !Ref SgPublicVpnrt
  #   Export:
  #     Name: !Sub "${VpcNAME}-SG-Public-VPNRT"

  # SgPrivateSv:
  #   Value: !Ref SgPrivateSV
  #   Export:
  #     Name: !Sub "${VpcNAME}-SG-Private-SV"

  EniPublicVpnrt1:
    Value: !Ref EniPublicVpnrt1
    Export:
      Name: !Sub "${VpcNAME}-ENI-Public-VPNRT1"

  EniPrivateSv1:
    Value: !Ref EniPrivateSv1
    Export:
      Name: !Sub "${VpcNAME}-ENI-Private-SV1"

ポイント解説

DHCP オプションセット

疑似オンプレ環境から、接続先 AWS の Route53 Resolver を参照させるため、DHCP オプションセットを新規作成しています。デフォルトの DHCP オプションセットは Amazon DNS を参照するようになっているので、参照先を Route53 Resolver に変更しています。

VPC

オンプレ想定のため、Amazon DNS を参照しないように「DNS による名前解決」と「ホスト名の使用」を false にしています。

Security Group

最初はセキュリティグループも CloudFormation で定義していましたが、ちょこちょこ内容に変更が入って、そのたびにコードを更新するのが面倒だったので、CloudFormation の対象から外しました。Security Group のように中身の変更頻度が多いオブジェクトは、CloudFormation の管理対象にしない方がいいかもしれないです。

Outputs

今後、クロススタックの利用も想定し、作成したオブジェクトを Export しています。

その他の注意事項

コードの [前提事項] に記載していますが、VPC で「DNS による名前解決」を Off にすると、Linux などに SSH ログインする際に時間がかかります。そのため、サーバを構築する際は、sshd_config の修正を推奨します (「UseDNS=no」、「GSSAPIAuthentication no」)。参考

おまけ

今回、VPN ルータとして VyOS を使用しました。どうやら、VyOS でルーティングが「静的」の場合、ルータ投入用の config がダウンロードできないみたいです (というか、そもそもダウンロードの項目に存在しない)。

config の修正に関しては、こちら のサイトが参考になるので、あわせてご参照ください。

まとめ

以上、オンプレ環境を模した検証 NW の構築でした。

いつも必要ではないですが、時々ふと必要になったりするので、こういったものは CloudFormation でテンプレート化しておくと色々捗ります。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0