こんにちは。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(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)の移行を無事成功させることができました。稼働中のシステムの場合には、必ず検証を実施の上、ユーザーとの合意及び移行期間を設けてください。
本記事が皆様のお役にたてば幸いです。
ではサウナラ~🔥