Set up a Network Load Balancer for API Gateway private integrations

Set up a Network Load Balancer for API Gateway private integrations

avatar

Phong Nguyen

2025.06.28

Bài viết này giúp bạn hiểu rõ về NLB, và trường hợp sử dụng thực tế. Hướng dẫn cách set up một API Gateway API liên kết với private Network Load Balancer thông qua VpC Link

NLB And ALB

The components:

Cả ALB và NLB đều có các thành phần giống nhau:

  • Load Balancer: Entry point vào hệ thống
  • Listener: Lắng nghe incoming connections
  • Target Group: Nhóm các targets (EC2, containers, services)
  • Health Check: Giám sát tình trạng targets

→ Dễ dàng chuyển đổi giữa ALB và NLB nếu không dùng tính năng đặc biệt

Mặc định:

"Khi bạn nghi ngờ, chọn ALB" vì:

  1. ALB có nhiều tính năng built-in
  2. NLB phức tạp hơn, cần kinh nghiệm và cẩn thận hơn

Ngoại trừ:

Chọn NLB khi câu trả lời cho một trong các câu hỏi sau là "Yes":

Clients có kết nối qua UDP hoặc giao thức không phải HTTP không?

  • ALB: Chỉ hỗ trợ HTTP/1.1, HTTP/2, gRPC
  • NLB: Hỗ trợ UDP, TCP, HTTP/3
  • Use case: Gaming (UDP), IoT protocols, HTTP/3

Bạn có cần tối ưu hóa hiệu suất không?

  • ALB: Layer 7 - inspect HTTP request details → latency cao hơn
  • NLB: Layer 4 - forward TCP/UDP connection → latency thấp hơn
  • Use case: High-performance applications cần độ trễ thấp

Bạn có dự kiến lưu lượng truy cập tăng đột biến khổng lồ và không thể dự đoán không?

  • ALB: Scale tự động nhưng mất vài phút → có thể không kịp xử lý
  • NLB: Xử lý traffic spikes ngay lập tức mà không cần scale
  • Use case: Super Bowl ads, flash sales (PlayStation launch), viral content

Bạn có yêu cầu địa chỉ IP tĩnh cho lưu lượng truy cập đến không?

  • ALB: DNS name với IP động (có thể thay đổi khi scale)
  • NLB: Static IP addresses out-of-the-box
  • Use case: Third-party firewall rules, legacy systems không resolve hostname

The comparison

ALBNLB
ProtocolsHTTP/1, HTTP/2, gRPCTCP, UDP
PerformanceLow LatencyVery Low Latency
Traffic Spikes⚠️ Inform AWS Support about huge traffic spikes✅ Deals with huge and unexpected traffic spikes
Static IP Addresses❌ No. However, you could place an NLB in front of an ALB.✅ Yes
TLS Termination✅ Yes✅ Yes
TargetsEC2 Instance, IP Address, LambdaEC2 Instance, IP Address, ALB
Client IP preservationUse HTTP header X-Forwarded-ForOptional, but comes with limitations
Routing AlgorithmRound Robin or Least Outstanding RequestsRandom
Deregistering targetsALB stops sending requests and waits for open requestsNLB stops opening new connections, but the application needs to terminate connections properly
Multiplexing✅ Yes, reuses connections to targets❌ No, does not reuse connections to targets
Maximum number of targets1000-5000500-1000
Security GroupSecurity group of ALB controls inbound traffic, targets reachable from ALB onlySecurity group of targets control inbound traffic, targets reachable from clients
Request based routing✅ Yes, based on hostname, path, header, …❌ No
WAF✅ Yes❌ No
Authentication✅ Yes (OpenID Connect, SAML, …)❌ No
Slow Start Mode✅ Yes❌ No
Sticky Session✅ Yes❌ No
IPv6✅ Yes✅ Yes
Costs💰💰💰💰💰 (But causes more connections and therefore higher load on targets.)

NLB Use Case

  1. API Gateway + VPC Link + NLB (Bài thực hành trong blog này)
  2. Gaming/Real-time Applications
Game ClientsNLB (UDP)Game Servers (EC2/ECS)
  1. High-Performance Trading/Financial Systems
Trading AppsNLBTrading Engines (ultra-low latency)
  1. Legacy Applications với Static IP
Legacy SystemsFirewall (whitelist static IPs)NLBModern Services
  1. Multi-Protocol Load Balancing
HTTP/TCP/UDP ClientsNLBMixed Protocol Services
  1. Global Load Balancing với Route 53
Global UsersRoute 53NLB (multiple regions)Services
  1. Container/Kubernetes Ingress
External TrafficNLBAWS Load Balancer ControllerEKS Pods
  1. Database Load Balancing
ApplicationsNLBDatabase Cluster (MySQL/PostgreSQL)
  1. Hybrid Cloud Architectures
On-premises → VPN/Direct ConnectNLBAWS Services
  1. Event-Driven/Streaming Architectures
Event ProducersNLBKafka/KinesisEvent Consumers
  1. Use Cases – PrivateLink

Lab Introduction

  • AWS experience: Intermediate
  • Time to complete: 40 minutes
  • AWS Region: US East (N. Virginia) us-east-1
  • Services used: VPC resource, EC2, IAM, NLB, API Gateway

Prerequisites

  • AWS Account với quyền Admin
  • Account của bạn đã có sẵn key pair
  • Kiến thức cơ bản về Cloudformation
  • Kiến thức về API gateway, Load Balancer, Asuto Scaling group
  • SSH để connect vào EC2

Architecture Diagram

Task Details

  1. Tạo VPC resource, NLB, ASG, Web-server vv sử dụng Cloudformation
  2. Test kết nối đến NLB
  3. Tạo VPC Link
  4. Tạo và config API Gateway
  5. Turn off security group evaluation for PrivateLink
  6. Test kết nối đến API Gateway

1. Tạo VPC resource, NLB, ASG, Web-server vv sử dụng Cloudformation

Chúng ta sẽ tạo các resource theo hình sau:

Tải file Cloudformation template tại đây

AWSTemplateFormatVersion: '2010-09-09'
Description: 'Private NLB with Auto Scaling Group for Web API'

Parameters:
  KeyPairName:
    Type: AWS::EC2::KeyPair::KeyName
    Description: Name of an existing EC2 KeyPair to enable SSH access to the instances
    ConstraintDescription: Must be the name of an existing EC2 KeyPair

Resources:
  # 1. VPC
  SoaVpcMain:
    Type: AWS::EC2::VPC
    Properties:
      CidrBlock: 10.7.0.0/16
      EnableDnsHostnames: true
      EnableDnsSupport: true
      Tags:
        - Key: Name
          Value: soa-vpc-main

  # 2. Public Subnets
  SoaSubnetPublic01:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref SoaVpcMain
      CidrBlock: 10.7.1.0/24
      AvailabilityZone: !Sub ${AWS::Region}a
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: soa-subnet-public-01

  SoaSubnetPublic02:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref SoaVpcMain
      CidrBlock: 10.7.2.0/24
      AvailabilityZone: !Sub ${AWS::Region}b
      MapPublicIpOnLaunch: true
      Tags:
        - Key: Name
          Value: soa-subnet-public-02

  # 3. Private Subnets
  SoaSubnetPrivate01:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref SoaVpcMain
      CidrBlock: 10.7.3.0/24
      AvailabilityZone: !Sub ${AWS::Region}a
      Tags:
        - Key: Name
          Value: soa-subnet-private-01

  SoaSubnetPrivate02:
    Type: AWS::EC2::Subnet
    Properties:
      VpcId: !Ref SoaVpcMain
      CidrBlock: 10.7.4.0/24
      AvailabilityZone: !Sub ${AWS::Region}b
      Tags:
        - Key: Name
          Value: soa-subnet-private-02

  # 4. Internet Gateway
  SoaIgwMain:
    Type: AWS::EC2::InternetGateway
    Properties:
      Tags:
        - Key: Name
          Value: soa-igw-main

  SoaIgwMainAttachment:
    Type: AWS::EC2::VPCGatewayAttachment
    Properties:
      VpcId: !Ref SoaVpcMain
      InternetGatewayId: !Ref SoaIgwMain

  # 5. NAT Gateway
  SoaEipNatGateway:
    Type: AWS::EC2::EIP
    DependsOn: SoaIgwMainAttachment
    Properties:
      Domain: vpc
      Tags:
        - Key: Name
          Value: soa-eip-nat-gateway

  SoaNatGatewayPublic01:
    Type: AWS::EC2::NatGateway
    Properties:
      AllocationId: !GetAtt SoaEipNatGateway.AllocationId
      SubnetId: !Ref SoaSubnetPublic01
      Tags:
        - Key: Name
          Value: soa-nat-gateway-public-01

  # 6. Public Route Table
  SoaRtPublic:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref SoaVpcMain
      Tags:
        - Key: Name
          Value: soa-rt-public

  SoaRoutePublicInternet:
    Type: AWS::EC2::Route
    DependsOn: SoaIgwMainAttachment
    Properties:
      RouteTableId: !Ref SoaRtPublic
      DestinationCidrBlock: 0.0.0.0/0
      GatewayId: !Ref SoaIgwMain

  SoaRtPublicAssociation01:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SoaSubnetPublic01
      RouteTableId: !Ref SoaRtPublic

  SoaRtPublicAssociation02:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SoaSubnetPublic02
      RouteTableId: !Ref SoaRtPublic

  # 7. Private Route Table
  SoaRtPrivate:
    Type: AWS::EC2::RouteTable
    Properties:
      VpcId: !Ref SoaVpcMain
      Tags:
        - Key: Name
          Value: soa-rt-private

  SoaRoutePrivateInternet:
    Type: AWS::EC2::Route
    Properties:
      RouteTableId: !Ref SoaRtPrivate
      DestinationCidrBlock: 0.0.0.0/0
      NatGatewayId: !Ref SoaNatGatewayPublic01

  SoaRtPrivateAssociation01:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SoaSubnetPrivate01
      RouteTableId: !Ref SoaRtPrivate

  SoaRtPrivateAssociation02:
    Type: AWS::EC2::SubnetRouteTableAssociation
    Properties:
      SubnetId: !Ref SoaSubnetPrivate02
      RouteTableId: !Ref SoaRtPrivate

  # 8. IAM Role cho SSM Session Manager
  SoaRoleEc2SsmAccess:
    Type: AWS::IAM::Role
    Properties:
      RoleName: soa-role-ec2-ssm-access
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service: ec2.amazonaws.com
            Action: sts:AssumeRole
      ManagedPolicyArns:
        - arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
      Tags:
        - Key: Name
          Value: soa-role-ec2-ssm-access

  SoaInstanceProfileEc2SsmAccess:
    Type: AWS::IAM::InstanceProfile
    Properties:
      InstanceProfileName: soa-instance-profile-ec2-ssm-access
      Roles:
        - !Ref SoaRoleEc2SsmAccess

  # 9. Security Group cho NLB
  SoaSgNlbPrivate:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: soa-sg-nlb-private
      GroupDescription: Security group for private NLB
      VpcId: !Ref SoaVpcMain
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          CidrIp: 10.7.0.0/16
          Description: HTTP access from VPC
      Tags:
        - Key: Name
          Value: soa-sg-nlb-private

  # 10. Security Group cho Web API
  SoaSgWebApi:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: soa-sg-web-api
      GroupDescription: Security group for web API instances
      VpcId: !Ref SoaVpcMain
      SecurityGroupIngress:
        - IpProtocol: tcp
          FromPort: 80
          ToPort: 80
          SourceSecurityGroupId: !Ref SoaSgNlbPrivate
          Description: HTTP access from NLB
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0
          Description: All outbound traffic
      Tags:
        - Key: Name
          Value: soa-sg-web-api

  # 11. Target Group
  SoaTgWebApi:
    Type: AWS::ElasticLoadBalancingV2::TargetGroup
    Properties:
      Name: soa-tg-web-api
      Port: 80
      Protocol: TCP
      VpcId: !Ref SoaVpcMain
      TargetType: instance
      HealthCheckEnabled: true
      HealthCheckPath: /
      HealthCheckProtocol: HTTP
      HealthCheckIntervalSeconds: 30
      HealthyThresholdCount: 2
      UnhealthyThresholdCount: 2
      Tags:
        - Key: Name
          Value: soa-tg-web-api

  # 12. Private Network Load Balancer
  SoaNlbPrivateWebApi:
    Type: AWS::ElasticLoadBalancingV2::LoadBalancer
    Properties:
      Name: soa-nlb-private-web-api
      Type: network
      Scheme: internal
      SecurityGroups:
        - !Ref SoaSgNlbPrivate
      Subnets:
        - !Ref SoaSubnetPrivate01
        - !Ref SoaSubnetPrivate02
      Tags:
        - Key: Name
          Value: soa-nlb-private-web-api

  SoaNlbListener:
    Type: AWS::ElasticLoadBalancingV2::Listener
    Properties:
      DefaultActions:
        - Type: forward
          TargetGroupArn: !Ref SoaTgWebApi
      LoadBalancerArn: !Ref SoaNlbPrivateWebApi
      Port: 80
      Protocol: TCP

  # 13. Launch Template
  SoaLtWebApiTemplate:
    Type: AWS::EC2::LaunchTemplate
    Properties:
      LaunchTemplateName: soa-lt-web-api-template
      VersionDescription: web api
      LaunchTemplateData:
        ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64}}'
        InstanceType: t2.micro
        KeyName: !Ref KeyPairName
        IamInstanceProfile:
          Arn: !GetAtt SoaInstanceProfileEc2SsmAccess.Arn
        SecurityGroupIds:
          - !Ref SoaSgWebApi
        UserData:
          Fn::Base64: !Sub |
            #!/bin/bash
            yum update -y
            yum install -y httpd.x86_64
            systemctl start httpd.service
            systemctl enable httpd.service
            echo "Hello World from $(hostname -f)" > /var/www/html/index.html
            
            # Signal CloudFormation that instance is ready
            /opt/aws/bin/cfn-signal -e $? --stack ${AWS::StackName} --resource SoaAsgWebApi --region ${AWS::Region}
        TagSpecifications:
          - ResourceType: instance
            Tags:
              - Key: Name
                Value: soa-ec2-web-api

  # 14. Auto Scaling Group
  SoaAsgWebApi:
    Type: AWS::AutoScaling::AutoScalingGroup
    DependsOn: 
      - SoaRoutePrivateInternet
      - SoaNatGatewayPublic01
    Properties:
      AutoScalingGroupName: soa-asg-web-api
      LaunchTemplate:
        LaunchTemplateId: !Ref SoaLtWebApiTemplate
        Version: !GetAtt SoaLtWebApiTemplate.LatestVersionNumber
      VPCZoneIdentifier:
        - !Ref SoaSubnetPrivate01
        - !Ref SoaSubnetPrivate02
      TargetGroupARNs:
        - !Ref SoaTgWebApi
      DesiredCapacity: 1
      MinSize: 1
      MaxSize: 2
      HealthCheckType: ELB
      HealthCheckGracePeriod: 300
      Tags:
        - Key: Name
          Value: soa-asg-web-api
          PropagateAtLaunch: false
    CreationPolicy:
      ResourceSignal:
        Count: 1
        Timeout: PT10M
    UpdatePolicy:
      AutoScalingRollingUpdate:
        MinInstancesInService: 0
        MaxBatchSize: 1
        PauseTime: PT10M
        WaitOnResourceSignals: true

  # 15. Auto Scaling Policy
  SoaAsgPolicyTargetTracking:
    Type: AWS::AutoScaling::ScalingPolicy
    Properties:
      AutoScalingGroupName: !Ref SoaAsgWebApi
      PolicyType: TargetTrackingScaling
      TargetTrackingConfiguration:
        PredefinedMetricSpecification:
          PredefinedMetricType: ASGAverageCPUUtilization
        TargetValue: 50.0

  # 16. Bastion Host để test
  SoaSgBastion:
    Type: AWS::EC2::SecurityGroup
    Properties:
      GroupName: soa-sg-bastion
      GroupDescription: Security group for bastion host
      VpcId: !Ref SoaVpcMain
      SecurityGroupEgress:
        - IpProtocol: -1
          CidrIp: 0.0.0.0/0
          Description: All outbound traffic
      Tags:
        - Key: Name
          Value: soa-sg-bastion

  SoaEc2Bastion:
    Type: AWS::EC2::Instance
    DependsOn:
      - SoaRoutePublicInternet
      - SoaIgwMainAttachment
    Properties:
      ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-6.1-x86_64}}'
      InstanceType: t2.micro
      KeyName: !Ref KeyPairName
      SubnetId: !Ref SoaSubnetPublic01
      IamInstanceProfile: !Ref SoaInstanceProfileEc2SsmAccess
      SecurityGroupIds:
        - !Ref SoaSgBastion
      UserData:
        Fn::Base64: !Sub |
          #!/bin/bash
          yum update -y
          yum install -y curl
          
          # Install SSM agent (should be pre-installed on AL2023)
          yum install -y amazon-ssm-agent
          systemctl enable amazon-ssm-agent
          systemctl start amazon-ssm-agent
      Tags:
        - Key: Name
          Value: soa-ec2-bastion

Outputs:
  VpcId:
    Description: VPC ID
    Value: !Ref SoaVpcMain
    Export:
      Name: !Sub ${AWS::StackName}-VpcId

  NlbDnsName:
    Description: Private NLB DNS Name
    Value: !GetAtt SoaNlbPrivateWebApi.DNSName
    Export:
      Name: !Sub ${AWS::StackName}-NlbDnsName

  BastionPublicIp:
    Description: Bastion Host Public IP
    Value: !GetAtt SoaEc2Bastion.PublicIp
    Export:
      Name: !Sub ${AWS::StackName}-BastionPublicIp

  TestCommand:
    Description: Command to test the NLB using SSM Session Manager
    Value: !Sub 'aws ssm start-session --target <INSTANCE_ID> --region ${AWS::Region}'

  SsmConnectInstructions:
    Description: Instructions to connect and test
    Value: |
      1. Connect to bastion: aws ssm start-session --target <BASTION_INSTANCE_ID>
      2. Test NLB: curl http://<NLB_DNS_NAME>
      3. Connect to web instance: aws ssm start-session --target <WEB_INSTANCE_ID>

1.1 Tóm tắt các resource được tạo:

🌐 NETWORK INFRASTRUCTURE (11 resources):

  • 1 VPC: soa-vpc-main (10.7.0.0/16)
  • 4 Subnets:
    • 2 Public: 10.7.1.0/24, 10.7.2.0/24 (AZ a,b)
    • 2 Private: 10.7.3.0/24, 10.7.4.0/24 (AZ a,b)
  • 1 Internet Gateway: soa-igw-main
  • 1 NAT Gateway: soa-nat-gateway-public-01 (trong public subnet 01)
  • 1 Elastic IP: Cho NAT Gateway
  • 2 Route Tables: Public + Private với routes tương ứng
  • 4 Route Table Associations: Gắn subnets vào route tables

🔐 SECURITY & IAM (4 resources):

  • 1 IAM Role: soa-role-ec2-ssm-access (với AmazonSSMManagedInstanceCore)
  • 1 Instance Profile: soa-instance-profile-ec2-ssm-access
  • 3 Security Groups:
    • soa-sg-nlb-private: Cho NLB (allow port 80 từ VPC)
    • soa-sg-web-api: Cho Web API (allow port 80 từ NLB SG)
    • soa-sg-bastion: Cho Bastion (chỉ outbound traffic)

⚖️ LOAD BALANCING (3 resources):

  • 1 Target Group: soa-tg-web-api (TCP port 80, HTTP health check)
  • 1 Network Load Balancer: soa-nlb-private-web-api (internal, private subnets)
  • 1 Listener: Port 80 TCP → Target Group

🚀 AUTO SCALING (3 resources):

  • 1 Launch Template: soa-lt-web-api-template (AL2023, t2.micro, Apache)
  • 1 Auto Scaling Group: soa-asg-web-api (Min:1, Des:1, Max:2)
  • 1 Scaling Policy: Target tracking 50% CPU

🖥️ COMPUTE (1 resource):

  • 1 Bastion Host: soa-ec2-bastion (public subnet, SSM access)

1.2 Tạo cloudformation stack

Stack name: soa-cfn-nlb-asg-stack

KeyPairName: Chọn Key pair đã có sẵn trong Account

Review lại và Submit

Đợi cho đến khi Stack được tạo thành công

2. Test kết nối đến NLB

  • Connect đến bastion host

  • Thực hiện: curl http://<NLB_DNS_NAME>

  • Kết quả trả về nội dung trang web là OK

Tại Console API Gateway -> VPC Link -> Create

  • Name: soa-vpc-link

  • Target NLB: Chọn NLB đã tạo ở bước chạy Cloudformation stack

Có thể mất 7-10 phút để VPC Link status chuyển trạng thái sang Available (chỉ có thể đợi)

4. Tạo và config API Gateway

Tại Console API Gateway -> API -> Create API

Chọn Build REST API

API name: soa-apigw-web-api

API endpoint type: Regional

Chọn API của bạn

Chọn Create Method

  • For Method type, select GET.

  • For Integration type, select VPC link.

  • Turn on VPC proxy integration.

  • For HTTP method, select GET.

  • For VPC link, select [Use stage variable] and enter ${stageVariables.vpcLinkId} in the text box below.

  • For Endpoint URL: http://<NLB_DNS_NAME>

  • Choose Create method.

Deploy API

  • Stage name: develop

Update stage variable:

  • Stage variables

    • Name: vpcLinkId
    • Value: giá trị VPC link ID

Save và hoàn tất

Tại đây cho dù chúng ta có access đến URL của API Gateway thì kết quả sẽ là Server error

Để...

Mở Cloudshell và run lệnh sau:

aws elbv2 set-security-groups --load-balancer-arn <NLB-ARN-URL> \
  --security-groups <NLB-SG-ID> --enforce-security-group-inbound-rules-on-private-link-traffic off 
  • Thay <NLB-ARN-URL> bằng ARN của NLB
  • Thay <NLB-SG-ID> bằng Security group ID của NLB

Bên dưới là command của mình

aws elbv2 set-security-groups \
  --load-balancer-arn arn:aws:elasticloadbalancing:us-east-1:067057696393:loadbalancer/net/soa-nlb-private-web-api/11171a3019aa5282 \
  --security-groups sg-0b9495c41a2b09471 \
  --enforce-security-group-inbound-rules-on-private-link-traffic off
  • Mở Cloudshell và run

6. Test kết nối đến API Gateway

  • Lấy URL của API gateway

  • Access trên browser

  • Lưu ý có thể phải xóa cache sau khi Turn off security group evaluation for PrivateLink phía trên

Challenge (Optional)

  1. Có thể custom domain cho api gateway
  2. Demo phía trên mình dùng web apache để thể hiện server web api, bạn có thể connect đến web api để cài đặt api khác theo mục đích. Thực hiện tets nhiều phương thức post, get, put vv
  3. Có thể liên kết với Cognito để thực hiện authen cho api gateway

Troubleshooting

  1. Sau khi run command để Turn off security group evaluation for PrivateLink, nếu access url của API gateway mà kết quả vẫn ko hiển thị nội dung web: Bạn nên clear cache, hoặc tets với private browser

Clean up resources

  • Delete API Gateway: soa-apigw-web-api
  • delete VPC Link: soa-vpc-link
  • Delete Cloudformation stack: soa-cfn-nlb-asg-stack

Tài liệu tham khảo: