セキュリティグループがアタッチできるタイプのNetwork Load Balancer(NLB)へ移行する手法[Elastic Load Balancing +Amazon Elastic Compute Cloud + AWS CloudFormation]

こんにちは。SCSKのふくちーぬです。

皆さんは、Network Load Balancer(NLB)に対してセキュリティグループをアタッチして利用していますでしょうか。

今回は、セキュリティグループがアタッチされていないNetwork Load Balancer(NLB)をIPアドレスを保持したまま、セキュリティグループがアタッチできるNetwork Load Balancer(NLB)へ移行する手法をご紹介します。

Network Load Balancer(NLB)がセキュリティグループをサポートした件

2023/8/11にNetwork Load Balancer(NLB)に対して、Application Load Balancer(ALB)と同様にセキュリティグループをアタッチできるようになりました。多くの方が待ち望んでいたアップデートだったのではないでしょうか。
セキュリティグループがアタッチできるようになるまでの以前の状況は、IPアドレス制御を行うためにはAWS Network FirewallやネットワークACLを利用する必要がありました。サブネットレベルまで考慮する必要があるため、大変面倒でした。

注意事項としては、Network Load Balancer(NLB)にセキュリティグループをアタッチできるタイミングは作成時のみということです。一度セキュリティグループをアタッチできるタイプとしてNetwork Load Balancer(NLB)を作成さえすれば、セキュリティグループの付け替えは任意のタイミングで実施できます。

Network Load Balancer を作成するときに、セキュリティグループを Network Load Balancer に関連付けることができます。セキュリティグループを関連付けずに Network Load Balancer を作成した場合、後でセキュリティグループをロードバランサーに関連付けることはできません。ロードバランサーを作成するときに、セキュリティグループをロードバランサーに関連付けることをお勧めします。

 

アーキテクチャ

  • 内部向けNetwork Load Balancer(NLB)では、TCP:80をリスナーとして受付し、ターゲットグループとしてEC2を指定しています。
  • 移行前のNetwork Load Balancer(NLB)には、セキュリティグループがアタッチされていないため、フルオープンのアクセスを許可しています。
  • 移行後のNetwork Load Balancer(NLB)には、セキュリティグループをアタッチします。

 

移行シナリオとポイント

下記を実現するためには、旧Network Load Balancer(NLB)を削除後に新Network Load Balancer(NLB)を再作成する必要があります。AWSサポートに問い合わせた結果、現時点でプライベートIPアドレスを確保しておく技術やサービスはありません。

  • 静的プライベートIPアドレスを維持すること
  • Network Load Balancer(NLB)にセキュリティグループがアタッチできるタイプへ変更すること
  • Network Load Balancer(NLB)のセキュリティグループのインバウンドルールには、指定されたIPアドレスからのみ通信を許可すること
  • EC2のセキュリティグループのインバウンドルールには、Network Load Balancer(NLB)にアタッチされたセキュリティグループからの許可をすること

Network Load Balancer(NLB)をIPアドレスを保持したまま移行するためには、以下のポイントを念頭に置いて実施することが重要です。

  • プライベートIPアドレスが他のサービス(EC2,VPC Lambda,RDS等)に奪われないように移行時間帯を設けて、関係者へAWSアカウントの利用時間帯を周知すること
  • 旧Network Load Balancer(NLB)の削除、新Network Load Balancer(NLB)の再作成を短期間で実施すること

このポイントを押さえておかないと、例えばNetwork Load Balancer(NLB)の移行タイミングと他のIAMユーザによるEC2作成等が重なってしまうことにより、プライベートIPアドレスを奪われてしまう可能性があります。

 

移行の検証

事前準備

VPC、サブネット、インターネットゲートウェイ、NATゲートウェイ、ネットワークACL、ルートテーブルが作成済みであることを確認してください。

初期構築(旧Network Load Balancerの作成)

以下のテンプレートを使用して、デプロイします。

AWSTemplateFormatVersion: 2010-09-09
Description: NLB Create
Parameters:
  ResourceName:
    Type: String
  VpcId:
    Type: String     
  PrivateSubnetA:
    Type: String  
  PrivateSubnetC:
    Type: String  
  PrivateIPAddressA:
    Type: String  
  PrivateIPAddressC:
    Type: String      
Resources:  
  # ------------------------------------------------------------#
  #  Network Load Balancer
  # ------------------------------------------------------------#
  LoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Sub ${ResourceName}-NLB
      SubnetMappings: 
      - SubnetId:
          !Ref PrivateSubnetA
        PrivateIPv4Address: !Ref PrivateIPAddressA
      - SubnetId:
          !Ref PrivateSubnetC
        PrivateIPv4Address: !Ref PrivateIPAddressC
      Scheme: internal
      Type: network
  LoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref LoadBalancer
      Port: 80
      Protocol: TCP
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref TargetGroup
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub ${ResourceName}-targetgroup
      VpcId: !Ref VpcId
      Port: 80
      Protocol: TCP
      TargetType: instance
      Targets: 
        - Id: !Ref EC2
          Port: 80      
  # ------------------------------------------------------------#
  #  EC2
  # ------------------------------------------------------------#   
  EC2:
    Type: AWS::EC2::Instance
    Properties: 
      ImageId: ami-0b193da66bc27147b
      InstanceType: t2.micro
      NetworkInterfaces: 
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PrivateSubnetA
          GroupSet:
            - !Ref EC2SecurityGroup
      UserData: !Base64 |
        #!/bin/bash
        yum update -y
        yum install httpd -y        
        systemctl start httpd
        systemctl enable httpd
        touch /var/www/html/index.html
        echo "Hello,World!" | tee -a /var/www/html/index.html        
      Tags:
          - Key: Name
            Value: !Sub "${ResourceName}-ec2"         
  EC2SecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: !Sub "${PrivateIPAddressA}/32"
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: !Sub "${PrivateIPAddressC}/32"                  
      GroupName: !Sub "${ResourceName}-ec2-sg"
      GroupDescription: !Sub "${ResourceName}-ec2-sg"
      Tags:
        - Key: "Name"
          Value: !Sub "${ResourceName}-ec2-sg" 

セキュリティグループがアタッチされていないNetwork Load Balancer(NLB)が作成されたことを確認します。

併せてプライベートIPアドレスの値も確認しておきます。

移行中(旧Network Load Balancerの削除)

セキュリティグループがアタッチされていないNetwork Load Balancer(NLB)に対して、セキュリティグループをアタッチするためには、一度”AWS::ElasticLoadBalancingV2::LoadBalancer”及び”AWS::ElasticLoadBalancingV2::Listener”を削除する必要があります。

理由としては、AWSドキュメント記載の通り、”AWS::ElasticLoadBalancingV2::LoadBalancer”の”SecurityGroups”プロパティを変更しても置換が発生しないためとなります。

“AWS::ElasticLoadBalancingV2::LoadBalancer”及び”AWS::ElasticLoadBalancingV2::Listener”に対してコメントアウトすることで、削除することができます。以下のテンプレートを使用して、スタックを更新します。

AWSTemplateFormatVersion: 2010-09-09
Description: NLB Delete
Parameters:
  ResourceName:
    Type: String
  VpcId:
    Type: String   
  PrivateSubnetA:
    Type: String  
  PrivateSubnetC:
    Type: String  
  PrivateIPAddressA:
    Type: String  
  PrivateIPAddressC:
    Type: String      
Resources:  
  # ------------------------------------------------------------#
  #  Network Load Balancer
  # ------------------------------------------------------------#
  # LoadBalancer:
  #   Type: AWS::ElasticLoadBalancingV2::LoadBalancer
  #   Properties:
  #     Name: !Sub ${ResourceName}-NLB
  #     SubnetMappings: 
  #     - SubnetId:
  #         !Ref PrivateSubnetA
  #       PrivateIPv4Address: !Ref PrivateIPAddressA
  #     - SubnetId:
  #         !Ref PrivateSubnetC
  #       PrivateIPv4Address: !Ref PrivateIPAddressC
  #     Scheme: internal
  #     Type: network
  #     SecurityGroups: 
  #       - !Ref NLBSecurityGroup
  # LoadBalancerListener:
  #   Type: AWS::ElasticLoadBalancingV2::Listener
  #   Properties:
  #     LoadBalancerArn: !Ref LoadBalancer
  #     Port: 80
  #     Protocol: TCP
  #     DefaultActions:
  #       - Type: forward
  #         TargetGroupArn: !Ref TargetGroup
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub ${ResourceName}-targetgroup
      VpcId: !Ref VpcId
      Port: 80
      Protocol: TCP
      TargetType: instance
      Targets: 
        - Id: !Ref EC2
          Port: 80      
  # ------------------------------------------------------------#
  #  EC2
  # ------------------------------------------------------------#   
  EC2:
    Type: AWS::EC2::Instance
    Properties: 
      ImageId: ami-0b193da66bc27147b
      InstanceType: t2.micro
      NetworkInterfaces: 
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PrivateSubnetA
          GroupSet:
            - !Ref EC2SecurityGroup
      UserData: !Base64 |
        #!/bin/bash
        yum update -y
        yum install httpd -y        
        systemctl start httpd
        systemctl enable httpd
        touch /var/www/html/index.html
        echo "Hello,World!" | tee -a /var/www/html/index.html        
      Tags:
          - Key: Name
            Value: !Sub "${ResourceName}-ec2"         
  EC2SecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: !Sub "${PrivateIPAddressA}/32"
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: !Sub "${PrivateIPAddressC}/32"                  
      GroupName: !Sub "${ResourceName}-ec2-sg"
      GroupDescription: !Sub "${ResourceName}-ec2-sg"
      Tags:
        - Key: "Name"
          Value: !Sub "${ResourceName}-ec2-sg"

変更セットにて”AWS::ElasticLoadBalancingV2::LoadBalancer”及び”AWS::ElasticLoadBalancingV2::Listener”が削除予定であることを確認後、”送信”を押下します。

Network Load Balancer(NLB)が削除されていることを確認します。

移行完了(新Network Load Balancerの作成)

以下のテンプレートを使用して、スタックを更新します。

AWSTemplateFormatVersion: 2010-09-09
Description: NLB Recreate
Parameters:
  ResourceName:
    Type: String
  VpcId:
    Type: String  
  VpcAddress:
    Type: String  
  PrivateSubnetA:
    Type: String  
  PrivateSubnetC:
    Type: String  
  PrivateIPAddressA:
    Type: String  
  PrivateIPAddressC:
    Type: String      
Resources:  
  # ------------------------------------------------------------#
  #  Network Load Balancer
  # ------------------------------------------------------------#
  LoadBalancer:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: !Sub ${ResourceName}-NLB
      SubnetMappings: 
      - SubnetId:
          !Ref PrivateSubnetA
        PrivateIPv4Address: !Ref PrivateIPAddressA
      - SubnetId:
          !Ref PrivateSubnetC
        PrivateIPv4Address: !Ref PrivateIPAddressC
      Scheme: internal
      Type: network
      SecurityGroups: 
        - !Ref NLBSecurityGroup
  LoadBalancerListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      LoadBalancerArn: !Ref LoadBalancer
      Port: 80
      Protocol: TCP
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref TargetGroup
  TargetGroup:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: !Sub ${ResourceName}-targetgroup
      VpcId: !Ref VpcId
      Port: 80
      Protocol: TCP
      TargetType: instance
      Targets: 
        - Id: !Ref EC2
          Port: 80      
  NLBSecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: !Ref VpcAddress
      GroupName: !Sub "${ResourceName}-nlb-sg"
      GroupDescription: !Sub "${ResourceName}-nlb-sg"
      Tags:
        - Key: "Name"
          Value: !Sub "${ResourceName}-nlb-sg"  
  # ------------------------------------------------------------#
  #  EC2
  # ------------------------------------------------------------#   
  EC2:
    Type: AWS::EC2::Instance
    Properties: 
      ImageId: ami-0b193da66bc27147b
      InstanceType: t2.micro
      NetworkInterfaces: 
        - AssociatePublicIpAddress: "true"
          DeviceIndex: "0"
          SubnetId: !Ref PrivateSubnetA
          GroupSet:
            - !Ref EC2SecurityGroup
      UserData: !Base64 |
        #!/bin/bash
        yum update -y
        yum install httpd -y        
        systemctl start httpd
        systemctl enable httpd
        touch /var/www/html/index.html
        echo "Hello,World!" | tee -a /var/www/html/index.html        
      Tags:
          - Key: Name
            Value: !Sub "${ResourceName}-ec2"         
  EC2SecurityGroup:
    Type: "AWS::EC2::SecurityGroup"
    Properties:
      VpcId: !Ref VpcId
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref NLBSecurityGroup
      GroupName: !Sub "${ResourceName}-ec2-sg"
      GroupDescription: !Sub "${ResourceName}-ec2-sg"
      Tags:
        - Key: "Name"
          Value: !Sub "${ResourceName}-ec2-sg"         

Network Load Balancer(NLB)が新規に作成されました。

セキュリティグループがアタッチされていることを確認します。

プライベートIPアドレスが変更されていないことを確認します。

正常にNetwork Load Balancer(NLB)経由で疎通できていることも確認できました。

 

最後に

いかがだったでしょうか。AWSのベストプラクティスとしても、Network Load Balancer(NLB)にはセキュリティグループをアタッチしておくことを推奨しています。これを機に、移行を検討していただくと幸いです。

実際のプロジェクトでも、Network Load Balancer(NLB)の移行を無事成功させることができました。稼働中のシステムの場合には、必ず検証を実施の上、ユーザーとの合意及び移行期間を設けてください。

本記事が皆様のお役にたてば幸いです。

ではサウナラ~🔥

タイトルとURLをコピーしました