はじめに
AWS のパブリック IPv4 アドレスが有償化になりましたが、
検証でなるべくお金をかけたくなかったので、IPv6 を使用する検証環境用の CFn を作成しました。
本記事は、その IPv6 の検証環境の使い方(IPv6アドレスを設定したEC2への接続方法)について解説した記事になります。
全体図
上記が本 CFn で作成する検証環境のイメージになります。
インスタンスの図を記載してますが、本 CFn を使用してもインスタンスは構築されません。
※インスタンスへの接続方法を記載する都合上、図があった方がわかりやすいため、インスタンスの図を記載しています。
イメージ図の中で重要なサービスについて、簡単に記載します。
- EC2 Instance Connect Endpoint
- パブリック IPv4 アドレスがないインスタンスに接続できる機能。
- プライベートサブネットの EC2 にも接続可能
- 使用料金がなんと無料!
- Internet gateway
- IPv6 のインスタンスでインターネットからの Ingress(受信)、Egress(送信)用に使用
- Egress Only インターネットゲートウェイ
- プライベートサブネットに配置しているインスタンスの Egress(送信)用に使用。簡単に説明すると NAT ゲートウェイの IPv6 バージョン。
- 追加費用なし!
プライベートサブネットでは Egress Only インターネットゲートウェイが、
パブリックサブネットではインターネットゲートウェイのルートが設定してありますので
どちらのサブネットでインスタンスを立てた場合でも、インターネットへは接続できる状態です。
CFn
本検証環境の構築で使用する CFn はこちらになります。
CFnコード
AWSTemplateFormatVersion: "2010-09-09"
Description: "IPv6 VPC"
Metadata:
AWS::CloudFormation::Interface:
ParameterGroups:
- Label:
default: "Network Configuration"
Parameters:
- CIDR
- Label:
default: "Normal Configuration"
Parameters:
- Prefix
- Regiton
Parameters:
Prefix:
Type: String
Default: test-Ipv6
CIDR:
Description: Please type the CidrBlock.
Type: String
Default: 192.168.0.0/16
Resources:
# ------------------------------------------------------------#
# VPC
# ------------------------------------------------------------#
Vpc:
Type: AWS::EC2::VPC
Properties:
CidrBlock: !Ref CIDR
EnableDnsHostnames: true
EnableDnsSupport: true
Tags:
- Key: Name
Value: !Sub ${Prefix}-vpc
# ------------------------------------------------------------#
# IPv6 Cidr
# ------------------------------------------------------------#
VpcIpv6:
Type: AWS::EC2::VPCCidrBlock
Properties:
AmazonProvidedIpv6CidrBlock: true
VpcId: !Ref Vpc
# ------------------------------------------------------------#
# Subnets
# ------------------------------------------------------------#
PublicSubnet1a:
DependsOn: VpcIpv6
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
AvailabilityZone: !Sub "${AWS::Region}a"
CidrBlock: !Select [0, !Cidr [!GetAtt Vpc.CidrBlock, 2, 8]] # 192.168.0.0/24
AssignIpv6AddressOnCreation: true
Ipv6CidrBlock:
!Select [0, !Cidr [!Select [0, !GetAtt Vpc.Ipv6CidrBlocks], 2, 64]]
Tags:
- Key: Name
Value: !Sub ${Prefix}-subnet-public-a
PrivateSubnet1a:
DependsOn: VpcIpv6
Type: AWS::EC2::Subnet
Properties:
VpcId: !Ref Vpc
AvailabilityZone: !Sub "${AWS::Region}a"
CidrBlock: !Select [1, !Cidr [!GetAtt Vpc.CidrBlock, 2, 8]]
AssignIpv6AddressOnCreation: true
Ipv6CidrBlock:
!Select [1, !Cidr [!Select [0, !GetAtt Vpc.Ipv6CidrBlocks], 2, 64]]
Tags:
- Key: Name
Value: !Sub ${Prefix}-subnet-private-a
# ------------------------------------------------------------#
# Security Groups
# ------------------------------------------------------------#
EICSecurityGroup:
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref Vpc
GroupDescription: EIC SG
GroupName: !Sub ${Prefix}-eic-sg
Tags:
- Key: Name
Value: !Sub ${Prefix}-eic-sg
EICSecurityGroupEgress1:
Type: AWS::EC2::SecurityGroupEgress
DependsOn: Ec2SecurityGroup
Properties:
Description: EC2 ssh egress
IpProtocol: tcp
GroupId: !Ref EICSecurityGroup
FromPort: 22
ToPort: 22
DestinationSecurityGroupId: !Ref Ec2SecurityGroup
EICSecurityGroupEgress2:
Type: AWS::EC2::SecurityGroupEgress
DependsOn: Ec2SecurityGroup
Properties:
Description: EC2 rdp egress
IpProtocol: tcp
GroupId: !Ref EICSecurityGroup
FromPort: 3389
ToPort: 3389
DestinationSecurityGroupId: !Ref Ec2SecurityGroup
Ec2SecurityGroup:
DependsOn: EICSecurityGroup
Type: AWS::EC2::SecurityGroup
Properties:
VpcId: !Ref Vpc
GroupDescription: EC2 SG
GroupName: !Sub ${Prefix}-ec2-sg
SecurityGroupIngress:
- IpProtocol: tcp
FromPort: 22
ToPort: 22
SourceSecurityGroupId: !Ref EICSecurityGroup
- IpProtocol: tcp
FromPort: 3389
ToPort: 3389
SourceSecurityGroupId: !Ref EICSecurityGroup
SecurityGroupEgress:
- IpProtocol: -1
DestinationSecurityGroupId: !Ref EICSecurityGroup
- IpProtocol: -1
CidrIp: 0.0.0.0/0
- IpProtocol: -1
CidrIpv6: ::/0
Tags:
- Key: Name
Value: !Sub ${Prefix}-ec2-sg
# ------------------------------------------------------------#
# EC2 Instance Connect Endpoint
# ------------------------------------------------------------#
EicEndpointPrivate:
Type: AWS::EC2::InstanceConnectEndpoint
DependsOn: EICSecurityGroup
Properties:
SubnetId: !Ref PrivateSubnet1a
SecurityGroupIds:
- !Ref EICSecurityGroup
# ------------------------------------------------------------#
# Internet Gateway
# ------------------------------------------------------------#
InternetGateway:
Type: AWS::EC2::InternetGateway
InternetGatewayAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref Vpc
InternetGatewayId: !Ref InternetGateway
# ------------------------------------------------------------#
# Egress Only Internet Gateway
# ------------------------------------------------------------#
EgressOnlyInternetGateway:
Type: AWS::EC2::EgressOnlyInternetGateway
Properties:
VpcId: !Ref Vpc
# ------------------------------------------------------------#
# Route Tables
# ------------------------------------------------------------#
PublicRouteTable:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: !Sub ${Prefix}-public-rtb
PrivateRouteTable:
Type: "AWS::EC2::RouteTable"
Properties:
VpcId: !Ref Vpc
Tags:
- Key: Name
Value: !Sub ${Prefix}-private-rtb
# ------------------------------------------------------------#
# Subnet Route Table Associations
# ------------------------------------------------------------#
PublicSubnet1aRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet1a
RouteTableId: !Ref PublicRouteTable
PrivateSubnet1aRouteTableAssociation:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PrivateSubnet1a
RouteTableId: !Ref PrivateRouteTable
# ------------------------------------------------------------#
# Routing
# ------------------------------------------------------------#
PublicRoute:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationIpv6CidrBlock: ::/0
GatewayId: !Ref InternetGateway
PublicRoute1:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref InternetGateway
PrivateRoute1:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PrivateRouteTable
DestinationIpv6CidrBlock: ::/0
EgressOnlyInternetGatewayId: !Ref EgressOnlyInternetGateway
Outputs:
VpcId:
Description: The VPC ID
Value: !Ref Vpc
Export:
Name: VpcId
PublicSubnetId:
Description: The public subnet ID
Value: !Ref PublicSubnet1a
Export:
Name: PublicSubnetId
PrivateSubnetId:
Description: The private subnet ID
Value: !Ref PrivateSubnet1a
Export:
Name: PrivateSubnetId
EICSecurityGroupId:
Description: The EIC SG ID
Value: !Ref EICSecurityGroup
Export:
Name: EICSecurityGroupId
Ec2SecurityGroupId:
Description: The EC2 SG ID
Value: !Ref Ec2SecurityGroup
Export:
Name: Ec2SecurityGroupId
CFnのパラメータ
CFnのパラメータについて簡単に説明します。
- CIDR
プライベートIPv4のCIDR範囲。デフォルトで192.168.0.0/16を設定されている。 - Prefix
各リソース名の接頭辞。Nameタグなどで使用する。 - Regiton
構築するリージョン先。本CFnのデフォルト値は、東京リージョンで構築するよう設定しています。
本検証環境に起動したEC2への接続方法
① EC2 Instance Connect Endpoint を利用して、パブリック IPv4 がない Linux インスタンスに接続する。
-
AWS マネジメントコンソール等から、CFn で作成した環境内に Linux インスタンスを起動する。
- VPC: CFn で作成した VPC を選択
- サブネット: プライベート、パブリックどちらのサブネットでも可
- キーペア:適宜設定。
- パブリック IP の自動割り当て: 無効
- IPv6IP を自動で割り当てる: 有効化
- セキュリティグループ: [『Prefix}-ec2-sg]を選択
-
インスタンス起動後、[インスタンス]から起動したインスタンスを選択し、[接続]を選択する。
-
[EC2 Instance Connect]タブを選択し、[EC2 Instance Connect エンドポイントを使用して接続する]を選択し、[接続]を選択する。
EIC エンドポイントが選択されていない場合は、CFn で作成したエンドポイントを選択する。
パブリック IPv4 がなくても Linux に接続することができました!また、インターネットへの接続も問題なさそうです。
ちなみにですが、EIC エンドポイントと AWS CLI を使用することによって、ローカル環境から ssh ができるようになります。
以下が接続する際のコマンドになります。IP アドレスを指定せずともインスタンス ID の指定だけで接続できるようです。
ssh -i my-key-pair.pem ec2-user@{instance_id} \
-o ProxyCommand='aws ec2-instance-connect open-tunnel --instance-id {instance_id}'
② EC2 Instance Connect Endpoint を利用して、パブリック IPv4 がない Windows インスタンスに RDP 接続する。
警告
本手順は AWS CLI を設定する必要がありますので、ご注意ください。
-
AWS マネジメントコンソール等から、CFn で作成した環境内に Windows インスタンスを起動する。
- VPC: CFn で作成した VPC を選択
- サブネット: プライベート、パブリックどちらのサブネットでも可
- キーペア:適宜設定。
- パブリック IP の自動割り当て: 無効
- IPv6IP を自動で割り当てる: 有効化
- セキュリティグループ: [{Prefix}-ec2-sg]を選択
-
以下のコマンドを実行し、WebSocket のトンネルを張る。
aws ec2-instance-connect open-tunnel --instance-id {instance_id} --remote-port 3389 --local-port {任意のポート}
-
手順 2 実行後、[Listening for connections on port <任意のポート>]が表示されることを確認する。
-
RDP ソフトを起動し、[localhost:<任意のポート>]に接続する。
まとめ
パブリック IPv4 アドレスを使用せずとも、Linux、Windows に接続できるようになりました。
また、IPv6アドレスを設定したインスタンスの外部へ通信も、設定することができました。
これで、パブリック IPv4 とはお別れすることができそうです。