プライベートサブネット内のインスタンスをALBにアタッチする構成
プライベートサブネット内に設置されたインスタンスを、ALBにアタッチする方法を確認します。
AWS公式では、以下の方法が紹介されています。
プライベートサブネットにある Amazon EC2 インスタンスをアタッチするには、バックエンドインスタンスで使用されるプライベートサブネットと同じアベイラビリティーゾーンにパブリックサブネットを作成します。次に、パブリックサブネットをロードバランサーに関連付けます。
プライベート IP アドレスを持つバックエンドインスタンスを ELB のインターネット向けロードバランサーにアタッチするにはどうすればよいですか?
ALBにアタッチするインスタンスをプライベートサブネットに配置することで、インスタンスに不正にアクセスされるリスクを下げることができます。
プライベートサブネット内のインスタンスをALBにアタッチすることで、システム全体のセキュリティを高めることができます。
構築する環境
EC2インスタンスの前面にELBを配置します。ELBはALBタイプとします。
インスタンスはAmazon Linux 2023とします。
インスタンスはプライベートサブネットに設置しますが、AZごとにパブリックサブネットも作成します。
環境構築用のCloudFormationテンプレートファイル
上記の構成をCloudFormationで構築します。
以下のURLにCloudFormationテンプレートを配置しています。
https://github.com/awstut-an-r/awstut-fa/tree/main/001
テンプレートファイルのポイント解説
プライベートサブネット内のインスタンスをALBにアタッチするためには、パブリックサブネットを作成する – VPC側
パブリックサブネット関係のリソースを確認します。
ポイントはパブリックサブネットと同サブネット用のルートテーブルです。
Resources:
IGW:
Type: AWS::EC2::InternetGateway
IGWAttachment:
Type: AWS::EC2::VPCGatewayAttachment
Properties:
VpcId: !Ref VPC
InternetGatewayId: !Ref IGW
PublicSubnet1:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !Ref CidrIp1
VpcId: !Ref VPC
AvailabilityZone: !Sub ${AWS::Region}${AvailabilityZone1}
PublicSubnet2:
Type: AWS::EC2::Subnet
Properties:
CidrBlock: !Ref CidrIp2
VpcId: !Ref VPC
AvailabilityZone: !Sub ${AWS::Region}${AvailabilityZone2}
PublicRouteTable:
Type: AWS::EC2::RouteTable
Properties:
VpcId: !Ref VPC
RouteToInternet:
Type: AWS::EC2::Route
Properties:
RouteTableId: !Ref PublicRouteTable
DestinationCidrBlock: 0.0.0.0/0
GatewayId: !Ref IGW
PublicSubnetRouteTableAssociation1:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet1
RouteTableId: !Ref PublicRouteTable
PublicSubnetRouteTableAssociation2:
Type: AWS::EC2::SubnetRouteTableAssociation
Properties:
SubnetId: !Ref PublicSubnet2
RouteTableId: !Ref PublicRouteTable
Code language: YAML (yaml)
今回構築する環境では、プライベートサブネットにEC2インスタンスが作成されます。ただしプライベートサブネットに配置したEC2インスタンスをALBと関連づけるためには、最初の引用の通り、ALB用にパブリックサブネットを用意する必要があります。
パブリックサブネットは、プライベートサブネットを作成したAZごとに作成する必要があります。今回ですと、インスタンスを配置するプライベートサブネットは、2つのAZに1つずつあります。ですからパブリックサブネットも、2つのAZに1つずつ作成する必要があります。
またパブリックサブネット用のルートテーブルを用意し、インターネットゲートウェイ向けのルートを定義します。
プライベートサブネット内のインスタンスをALBにアタッチするためには、パブリックサブネットを作成する – ALB側
ALB側のサブネットの設定を確認します。
Resources:
ALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Name: !Sub ${Prefix}-ALB
Scheme: internet-facing
SecurityGroups:
- !Ref ALBSecurityGroup
Subnets:
- !Ref PublicSubnet1
- !Ref PublicSubnet2
Type: application
Code language: YAML (yaml)
先ほどのパブリックサブネットの扱いの続きです。ALBに関連付けます。
Subnetsプロパティにパブリックサブネットを指定します。これで同じAZのプライベートサブネット内のEC2インスタンスを、ALBに関連づけることができます。
加えてALBのターゲットグループおよびリスナーも作成します。
Resources:
ALBTargetGroup:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
VpcId: !Ref VPC
Name: !Sub ${Prefix}-ALBTargetGroup
Protocol: HTTP
Port: !Ref HTTPPort
HealthCheckProtocol: HTTP
HealthCheckPath: /
HealthCheckPort: traffic-port
HealthyThresholdCount: !Ref HealthyThresholdCount
UnhealthyThresholdCount: !Ref UnhealthyThresholdCount
HealthCheckTimeoutSeconds: !Ref HealthCheckTimeoutSeconds
HealthCheckIntervalSeconds: !Ref HealthCheckIntervalSeconds
Matcher:
HttpCode: !Ref HttpCode
Targets:
- Id: !Ref Instance1
- Id: !Ref Instance2
ALBListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- TargetGroupArn: !Ref ALBTargetGroup
Type: forward
LoadBalancerArn: !Ref ALB
Port: !Ref HTTPPort
Protocol: HTTP
Code language: YAML (yaml)
今回はALBリスナーでHTTP(tcp/80)を受け付け、2インスタンスが所属するターケットグループにルーティングさせるように設定します。
VPCエンドポイント経由でdnf(yum)を実行する
EC2インスタンスをWebサーバとして動作させるために、dnf(yum)を使ってApacheをインストールします。
通常、dnfを実行するためには、インターネット上にあるyumリポジトリにアクセスする必要があります。ただ例外的に、EC2インスタンスのOSがAmazon Linux (2, 2023)の場合、S3用のVPCエンドポイントを設置することで、インターネットを経由することなく、同OS用のdnf/yumリポジトリにアクセスすることができます。
詳細は以下のページをご確認ください。
今回はdnfを使用して、Apacheをインストールします。
Resources:
Instance1:
Type: AWS::EC2::Instance
Properties:
ImageId: !Ref ImageId
InstanceType: !Ref InstanceType
NetworkInterfaces:
- DeviceIndex: 0
SubnetId: !Ref PrivateSubnet1
GroupSet:
- !Ref InstanceSecurityGroup
UserData: !Base64 |
#!/bin/bash -xe
dnf update -y
dnf install -y httpd
systemctl start httpd
systemctl enable httpd
ec2-metadata -i > /var/www/html/index.html
Code language: YAML (yaml)
dnfはユーザデータによるインスタンスの初期化処理の一環として実行します。
ユーザデータに関する詳細は以下のページをご確認ください。
今回は初期化処理として以下を実行します。
- Apacheのインストールおよび起動設定。
- インスタンスIDをindex.htmlに書き込む。
環境構築
CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。
CloudFormationスタックを作成し、スタック内のリソースを確認する
CloudFormationスタックを作成します。
AWS CLIからCloudFormationを実行する手順については、以下のページをご確認ください。
今回作成された主要リソースは以下の通りです。
- ALB名:fa-001-ALB
- インスタンス1のID:i-055e2682f0c464b0b
- インスタンス2のID:i-092734beb5c18a4dd
- PublicSubnet1:subnet-0f6fc4befd33069d6
- PublicSubnet2:subnet-096122b720cf20e72
AWS Managemet Consoleでもリソースの作成状況を確認します。
ALBを確認します。
ALBに2つのパブリックサブネットが紐付いていることがわかります。
加えて、ALBに割り当てられたDNS名を確認することもできます。
続いてALBのターゲットグループを確認します。
こちらはプライベートサブネット内のインスタンスが含まれていることがわかります。
挙動確認
準備が整いましたので、実際に挙動を確認します。
$ curl http://fa-001-ALB-592982493.ap-northeast-1.elb.amazonaws.com
instance-id: i-009d1a1926b8f3041
$ curl http://fa-001-ALB-592982493.ap-northeast-1.elb.amazonaws.com
instance-id: i-04a1be5fb6ea67d60
$ curl http://fa-001-ALB-592982493.ap-northeast-1.elb.amazonaws.com
instance-id: i-009d1a1926b8f3041
$ curl http://fa-001-ALB-592982493.ap-northeast-1.elb.amazonaws.com
instance-id: i-04a1be5fb6ea67d60
Code language: Bash (bash)
正常にALBにアクセスできました。
出力結果から、プライベートサブネット内に配置された2つのインスタンスに、交互にアクセスしていることがわかります。
まとめ
プライベートサブネット内のインスタンスをELBにアタッチするためには、パブリックサブネットを作成する必要があることがわかりました。
ALBにアタッチするインスタンスをプライベートサブネットに配置することで、インスタンスに不正にアクセスされるリスクを下げることができます。そしてシステム全体のセキュリティを向上できます。