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