プライベートサブネット内のインスタンスをALBにアタッチする

プライベートサブネット内のインスタンスをELBにアタッチする

プライベートサブネット内のインスタンスをALBにアタッチする構成

プライベートサブネット内に設置されたインスタンスを、ALBにアタッチする方法を確認します。

AWS公式では、以下の方法が紹介されています。

プライベートサブネットにある Amazon EC2 インスタンスをアタッチするには、バックエンドインスタンスで使用されるプライベートサブネットと同じアベイラビリティーゾーンにパブリックサブネットを作成します。次に、パブリックサブネットをロードバランサーに関連付けます。

プライベート IP アドレスを持つバックエンドインスタンスを ELB のインターネット向けロードバランサーにアタッチするにはどうすればよいですか?

ALBにアタッチするインスタンスをプライベートサブネットに配置することで、インスタンスに不正にアクセスされるリスクを下げることができます。
プライベートサブネット内のインスタンスをALBにアタッチすることで、システム全体のセキュリティを高めることができます。

構築する環境

Diagram of attaching instances in private subnets to ELB.

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リポジトリにアクセスすることができます。

詳細は以下のページをご確認ください。

あわせて読みたい
プライベートサブネットのインスタンスでyum/dnfを実行する 【プライベートサブネット内のインスタンスでyum/dnfを実行する構成】 プライベートサブネット内のインスタンスで、yum/dnfを実行する方法を確認します。 今回は以下の2...

今回は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はユーザデータによるインスタンスの初期化処理の一環として実行します。

ユーザデータに関する詳細は以下のページをご確認ください。

あわせて読みたい
Linuxインスタンスの初期化方法4選 【Linuxインスタンスを初期化する4つの方法】 EC2インスタンスの起動時に初期化処理を実行する方法を考えます。 EC2インスタンスを構築時に初期化する以下の4つの手法を...

今回は初期化処理として以下を実行します。

  • Apacheのインストールおよび起動設定。
  • インスタンスIDをindex.htmlに書き込む。

環境構築

CloudFormationを使用して、本環境を構築し、実際の挙動を確認します。

CloudFormationスタックを作成し、スタック内のリソースを確認する

CloudFormationスタックを作成します。

AWS CLIからCloudFormationを実行する手順については、以下のページをご確認ください。

あわせて読みたい
CloudFormationのネストされたスタックで環境を構築する 【CloudFormationのネストされたスタックで環境を構築する方法】 CloudFormationにおけるネストされたスタックを検証します。 CloudFormationでは、スタックをネストす...

今回作成された主要リソースは以下の通りです。

  • ALB名:fa-001-ALB
  • インスタンス1のID:i-055e2682f0c464b0b
  • インスタンス2のID:i-092734beb5c18a4dd
  • PublicSubnet1:subnet-0f6fc4befd33069d6
  • PublicSubnet2:subnet-096122b720cf20e72

AWS Managemet Consoleでもリソースの作成状況を確認します。
ALBを確認します。

ALB is associated with a public subnet.

ALBに2つのパブリックサブネットが紐付いていることがわかります。
加えて、ALBに割り当てられたDNS名を確認することもできます。

続いてALBのターゲットグループを確認します。

ALB target group includes instances in private subnets.

こちらはプライベートサブネット内のインスタンスが含まれていることがわかります。

挙動確認

準備が整いましたので、実際に挙動を確認します。

$ 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にアタッチするインスタンスをプライベートサブネットに配置することで、インスタンスに不正にアクセスされるリスクを下げることができます。そしてシステム全体のセキュリティを向上できます。