Create An Internal Network Load Balancer With Static Private IP Address
Hello Everyone
Welcome to CloudAffaire and this is Debjeet.
In the last blog post, we have discussed how to create an internet-facing network load balancer with static public (elastic) ip address.
In this blog post, we will discuss how to create an internal network load balancer with static private ip address and ip address as target.
Create An Internal Network Load Balancer With Static Private IP Address:
By default, AWS assigns a private IPv4 address to each load balancer node from the subnet for its Availability Zone. Alternatively, If you create an internal load balancer, you can assign a private IP address from the IPv4 range of each subnet instead of letting AWS assign one.
Internal load balancer ip assignment:
- one private address assigned by AWS to each load balancer node from the subnet for its Availability Zone.
OR
- one private address assigned by Customer to each load balancer node from the subnet for its Availability Zone.
Request Routing and IP Addresses:
If you specify targets using an instance ID, traffic is routed to instances using the primary private IP address specified in the primary network interface for the instance. The load balancer rewrites the destination IP address from the data packet before forwarding it to the target instance.
If you specify targets using IP addresses, you can route traffic to an instance using any private IP address from one or more network interfaces. This enables multiple applications on an instance to use the same port. Note that each network interface can have its own security group. The load balancer rewrites the destination IP address before forwarding it to the target.
Source IP Preservation:
If you specify targets using an instance ID, the source IP addresses of the clients are preserved and provided to your applications.
If you specify targets by IP address, the source IP addresses are the private IP addresses of the load balancer nodes. If you need the IP addresses of the clients, enable Proxy Protocol and get the client IP addresses from the Proxy Protocol header.
In this demo, we are going to create an internal network load balancer with private ip address and ip address as target.
Create An Internal Network Load Balancer With Static Private IP Address:
Step 1: Create a custom VPC for your Network Load Balancer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
############################################## ## Create An Internal Network Load Balancer ## ############################################## ## Prerequisite: AWS CLI installed and configured with proper access ## https://cloudaffaire.com/category/aws/aws-cli/ ##---------------------------------- ## Create custom vpc for your nlb ## ##---------------------------------- ## Create a directory for this demo mkdir aws_internal_nlb_demo && cd aws_internal_nlb_demo ## Create a VPC with DNS hostname enabled AWS_VPC_ID=$(aws ec2 create-vpc \ --cidr-block 10.0.0.0/16 \ --query 'Vpc.{VpcId:VpcId}' \ --output text) && aws ec2 modify-vpc-attribute \ --vpc-id $AWS_VPC_ID \ --enable-dns-hostnames "{\"Value\":true}" ## Create one public subnet and two private subnets AWS_SUBNET_PUBLIC_ONE_ID=$(aws ec2 create-subnet \ --vpc-id $AWS_VPC_ID --cidr-block 10.0.1.0/24 \ --availability-zone ap-south-1a --query 'Subnet.{SubnetId:SubnetId}' \ --output text) && AWS_SUBNET_PRIVATE_ONE_ID=$(aws ec2 create-subnet \ --vpc-id $AWS_VPC_ID --cidr-block 10.0.2.0/24 \ --availability-zone ap-south-1a --query 'Subnet.{SubnetId:SubnetId}' \ --output text) && AWS_SUBNET_PRIVATE_TWO_ID=$(aws ec2 create-subnet \ --vpc-id $AWS_VPC_ID --cidr-block 10.0.3.0/24 \ --availability-zone ap-south-1b --query 'Subnet.{SubnetId:SubnetId}' \ --output text) && aws ec2 modify-subnet-attribute \ --subnet-id $AWS_SUBNET_PUBLIC_ONE_ID \ --map-public-ip-on-launch ## Craete a Elastic IP address for NAT gateway AWS_ELASTIC_IP_ALLOCID=$(aws ec2 allocate-address \ --domain vpc \ --query 'AllocationId' \ --output text) ## Create a Nat Gateway for outbound internet access in private subnet AWS_NAT_GATEWAY_ID=$(aws ec2 create-nat-gateway \ --subnet-id $AWS_SUBNET_PUBLIC_ONE_ID \ --allocation-id $AWS_ELASTIC_IP_ALLOCID \ --query 'NatGateway.NatGatewayId' \ --output text) ## Create an Internet Gateway AWS_INTERNET_GATEWAY_ID=$(aws ec2 create-internet-gateway \ --query 'InternetGateway.{InternetGatewayId:InternetGatewayId}' \ --output text) && aws ec2 attach-internet-gateway \ --vpc-id $AWS_VPC_ID \ --internet-gateway-id $AWS_INTERNET_GATEWAY_ID ## Create a route table for public subnet AWS_CUSTOM_PUBLIC_ROUTE_TABLE_ID=$(aws ec2 create-route-table \ --vpc-id $AWS_VPC_ID \ --query 'RouteTable.{RouteTableId:RouteTableId}' \ --output text ) && aws ec2 create-route \ --route-table-id $AWS_CUSTOM_PUBLIC_ROUTE_TABLE_ID \ --destination-cidr-block 0.0.0.0/0 \ --gateway-id $AWS_INTERNET_GATEWAY_ID ## Associate the public subnet with route table AWS_ROUTE_TABLE_ASSOID_ONE=$(aws ec2 associate-route-table \ --subnet-id $AWS_SUBNET_PUBLIC_ONE_ID \ --route-table-id $AWS_CUSTOM_PUBLIC_ROUTE_TABLE_ID \ --query 'AssociationId' \ --output text) ## Create a route table for private subnets AWS_CUSTOM_PRIVATE_ROUTE_TABLE_ID=$(aws ec2 create-route-table \ --vpc-id $AWS_VPC_ID \ --query 'RouteTable.{RouteTableId:RouteTableId}' \ --output text ) && aws ec2 create-route \ --route-table-id $AWS_CUSTOM_PRIVATE_ROUTE_TABLE_ID \ --destination-cidr-block 0.0.0.0/0 \ --gateway-id $AWS_NAT_GATEWAY_ID ## Associate the private subnets with route table AWS_ROUTE_TABLE_ASSOID_TWO=$(aws ec2 associate-route-table \ --subnet-id $AWS_SUBNET_PRIVATE_ONE_ID \ --route-table-id $AWS_CUSTOM_PRIVATE_ROUTE_TABLE_ID \ --query 'AssociationId' \ --output text) && AWS_ROUTE_TABLE_ASSOID_THREE=$(aws ec2 associate-route-table \ --subnet-id $AWS_SUBNET_PRIVATE_TWO_ID \ --route-table-id $AWS_CUSTOM_PRIVATE_ROUTE_TABLE_ID \ --query 'AssociationId' \ --output text) ## Create a security group aws ec2 create-security-group \ --vpc-id $AWS_VPC_ID \ --group-name myvpc-security-group \ --description 'My VPC non default security group' ## Get security group ID's AWS_DEFAULT_SECURITY_GROUP_ID=$(aws ec2 describe-security-groups \ --filters "Name=vpc-id,Values=$AWS_VPC_ID" \ --query 'SecurityGroups[?GroupName == `default`].GroupId' \ --output text) && AWS_CUSTOM_SECURITY_GROUP_ID=$(aws ec2 describe-security-groups \ --filters "Name=vpc-id,Values=$AWS_VPC_ID" \ --query 'SecurityGroups[?GroupName == `myvpc-security-group`].GroupId' \ --output text) ## Create security group ingress rules ## For this demo, I am opening up my sg which is not recommended by AWS aws ec2 authorize-security-group-ingress \ --group-id $AWS_CUSTOM_SECURITY_GROUP_ID \ --ip-permissions '[{"IpProtocol": "-1", "FromPort": -1, "ToPort": -1, "IpRanges": [{"CidrIp": "0.0.0.0/0", "Description": "Allow All Traffic"}]}]' |
Step 2: Create three EC2 instances, two as NLB target and one to access the internal load balancer.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 |
##-------------------------------------------------------------------------------- ## Create three ec2 instances two for your nlb target group and one for testing ## ##-------------------------------------------------------------------------------- ## Get Amazon Linux 2 latest AMI ID AWS_AMI_ID=$(aws ec2 describe-images \ --owners 'amazon' \ --filters 'Name=name,Values=amzn2-ami-hvm-2.0.????????-x86_64-gp2' 'Name=state,Values=available' \ --query 'sort_by(Images, &CreationDate)[-1].[ImageId]' \ --output 'text') ## Create a key-pair aws ec2 create-key-pair \ --key-name myvpc-keypair \ --query 'KeyMaterial' \ --output text > myvpc-keypair.pem && chmod 400 myvpc-keypair.pem ## Create user data to configure LAMP stack vi myuserdataone.txt ----------------------- #!/bin/bash sudo yum install -y httpd sudo systemctl start httpd sudo usermod -a -G apache ec2-user sudo chown -R ec2-user:apache /var/www sudo chmod 2775 /var/www sudo find /var/www -type d -exec chmod 2775 {} \; sudo find /var/www -type f -exec chmod 0664 {} \; sudo echo "hello from instance one" > /var/www/html/index.html ----------------------- :wq vi myuserdatatwo.txt ----------------------- #!/bin/bash sudo yum install -y httpd sudo systemctl start httpd sudo usermod -a -G apache ec2-user sudo chown -R ec2-user:apache /var/www sudo chmod 2775 /var/www sudo find /var/www -type d -exec chmod 2775 {} \; sudo find /var/www -type f -exec chmod 0664 {} \; sudo echo "hello from instance two" > /var/www/html/index.html ----------------------- :wq ## Create two EC2 instance in two private subnets for your nlb AWS_EC2_INSTANCE_ONE_ID=$(aws ec2 run-instances \ --image-id $AWS_AMI_ID \ --instance-type t2.micro \ --key-name myvpc-keypair \ --monitoring "Enabled=false" \ --security-group-ids $AWS_CUSTOM_SECURITY_GROUP_ID \ --subnet-id $AWS_SUBNET_PRIVATE_ONE_ID \ --user-data file://myuserdataone.txt \ --private-ip-address 10.0.2.10 \ --query 'Instances[0].InstanceId' \ --output text) && AWS_EC2_INSTANCE_TWO_ID=$(aws ec2 run-instances \ --image-id $AWS_AMI_ID \ --instance-type t2.micro \ --key-name myvpc-keypair \ --monitoring "Enabled=false" \ --security-group-ids $AWS_CUSTOM_SECURITY_GROUP_ID \ --subnet-id $AWS_SUBNET_PRIVATE_TWO_ID \ --user-data file://myuserdatatwo.txt \ --private-ip-address 10.0.3.10 \ --query 'Instances[0].InstanceId' \ --output text) ## Create one EC2 instance in public subnet for testing your internal nlb AWS_EC2_INSTANCE_THREE_ID=$(aws ec2 run-instances \ --image-id $AWS_AMI_ID \ --instance-type t2.micro \ --key-name myvpc-keypair \ --monitoring "Enabled=false" \ --security-group-ids $AWS_CUSTOM_SECURITY_GROUP_ID \ --subnet-id $AWS_SUBNET_PUBLIC_ONE_ID \ --private-ip-address 10.0.1.10 \ --query 'Instances[0].InstanceId' \ --output text) ## It will take some time for the instances to get ready |
Step 3: Create an internal Network Load Balancer with static private ip.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 |
##---------------------------------------------------------------- ## Create internal network load balancer with static private ip ## ##---------------------------------------------------------------- ## Create the internal network load balancer with static private ip address ## Observe, we have assigned private ip 10.0.2.20 and 10.0.3.20 to NLB nodes AWS_NLB_ARN=$(aws elbv2 create-load-balancer \ --name my-network-load-balancer \ --subnet-mappings SubnetId=$AWS_SUBNET_PRIVATE_ONE_ID,PrivateIPv4Address=10.0.2.20 \ SubnetId=$AWS_SUBNET_PRIVATE_TWO_ID,PrivateIPv4Address=10.0.3.20 \ --type network \ --scheme internal \ --query 'LoadBalancers[0].LoadBalancerArn' \ --output text) ## Check the status of load balancer aws elbv2 describe-load-balancers \ --load-balancer-arns $AWS_NLB_ARN \ --query 'LoadBalancers[0].State.Code' \ --output text ## Create the target group for your nlb AWS_NLB_TARGET_GROUP_ARN=$(aws elbv2 create-target-group \ --name my-nlb-targets \ --protocol TCP --port 80 \ --vpc-id $AWS_VPC_ID \ --target-type ip \ --query 'TargetGroups[0].TargetGroupArn' \ --output text) ## Register both the instances ip address in the target group aws elbv2 register-targets --target-group-arn $AWS_NLB_TARGET_GROUP_ARN \ --targets Id=10.0.2.10,Port=80,AvailabilityZone=ap-south-1a && aws elbv2 register-targets --target-group-arn $AWS_NLB_TARGET_GROUP_ARN \ --targets Id=10.0.3.10,Port=80,AvailabilityZone=ap-south-1b ## Create a listener for your load balancer with a default rule that forwards requests to your target group AWS_NLB_LISTNER_ARN=$(aws elbv2 create-listener --load-balancer-arn $AWS_NLB_ARN \ --protocol TCP --port 80 \ --default-actions Type=forward,TargetGroupArn=$AWS_NLB_TARGET_GROUP_ARN \ --query 'Listeners[0].ListenerArn' \ --output text) ## Verify the health of the registered targets for your target group aws elbv2 describe-target-health --target-group-arn $AWS_NLB_TARGET_GROUP_ARN ## Get the public ip address of EC2 instance created in public subnet. aws ec2 describe-instances \ --instance-ids $AWS_EC2_INSTANCE_THREE_ID \ --query 'Reservations[*].Instances[?PrivateIpAddress == `10.0.1.10`].PublicIpAddress' \ --output text ## Get the DNS of your internal network load balancer AWS_NLB_DNS=$(aws elbv2 describe-load-balancers \ --load-balancer-arns $AWS_NLB_ARN \ --query 'LoadBalancers[0].DNSName' \ --output text) && echo $AWS_NLB_DNS ## Note the DNS name which we will curl in next step ## my-network-load-balancer-c2ad80bb05a2389f.elb.ap-south-1.amazonaws.com ## Replace the network load balancer dns name with your dns name below ## Login to the instance in public subnet ssh -i myvpc-keypair.pem ec2-user@13.232.131.59 #replace the ip from above output ## Check NLB DNS name for IP address ## Same as private ip address that you have assigned dig +short my-network-load-balancer-c2ad80bb05a2389f.elb.ap-south-1.amazonaws.com | tail -n2 ## Send request to your NLB using DNS and IP address curl 10.0.2.10 ## Responce from instance one curl 10.0.3.10 ## Responce from instance two curl 10.0.2.20 ## Responce from instance one and two curl 10.0.3.20 ## Responce from instance one and two curl my-network-load-balancer-c2ad80bb05a2389f.elb.ap-south-1.amazonaws.com ## Responce from instance one and two exit ## exit back to your system |
Step 4: Cleanup.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 |
##----------- ## Cleanup ## ##----------- ## Delete the listener and Deregister targets aws elbv2 delete-listener \ --listener-arn $AWS_NLB_LISTNER_ARN && aws elbv2 deregister-targets \ --target-group-arn $AWS_NLB_TARGET_GROUP_ARN \ --targets Id=10.0.2.10,Port=80,AvailabilityZone=ap-south-1a && aws elbv2 deregister-targets \ --target-group-arn $AWS_NLB_TARGET_GROUP_ARN \ --targets Id=10.0.3.10,Port=80,AvailabilityZone=ap-south-1b ## Delete target group and nlb aws elbv2 delete-target-group \ --target-group-arn $AWS_NLB_TARGET_GROUP_ARN && aws elbv2 delete-load-balancer \ --load-balancer-arn $AWS_NLB_ARN ## Terminate the ec2 instances aws ec2 terminate-instances \ --instance-ids $AWS_EC2_INSTANCE_ONE_ID && aws ec2 terminate-instances \ --instance-ids $AWS_EC2_INSTANCE_TWO_ID && aws ec2 terminate-instances \ --instance-ids $AWS_EC2_INSTANCE_THREE_ID ## Delete the NAT gateway aws ec2 delete-nat-gateway \ --nat-gateway-id $AWS_NAT_GATEWAY_ID ## Delete key pair aws ec2 delete-key-pair \ --key-name myvpc-keypair ## Delete custom security group (once instances are terminated) aws ec2 delete-security-group \ --group-id $AWS_CUSTOM_SECURITY_GROUP_ID ## Deallocate the Elastic IP address (give some time and retry, if any error) aws ec2 release-address \ --allocation-id $AWS_ELASTIC_IP_ALLOCID ## Delete internet gateway aws ec2 detach-internet-gateway \ --internet-gateway-id $AWS_INTERNET_GATEWAY_ID \ --vpc-id $AWS_VPC_ID && aws ec2 delete-internet-gateway \ --internet-gateway-id $AWS_INTERNET_GATEWAY_ID ## Disassociate the subnets from custom route table aws ec2 disassociate-route-table \ --association-id $AWS_ROUTE_TABLE_ASSOID_ONE && aws ec2 disassociate-route-table \ --association-id $AWS_ROUTE_TABLE_ASSOID_TWO && aws ec2 disassociate-route-table \ --association-id $AWS_ROUTE_TABLE_ASSOID_THREE ## Delete custom route table aws ec2 delete-route-table \ --route-table-id $AWS_CUSTOM_PUBLIC_ROUTE_TABLE_ID && aws ec2 delete-route-table \ --route-table-id $AWS_CUSTOM_PRIVATE_ROUTE_TABLE_ID ## Delete the subnets aws ec2 delete-subnet \ --subnet-id $AWS_SUBNET_PUBLIC_ONE_ID && aws ec2 delete-subnet \ --subnet-id $AWS_SUBNET_PRIVATE_ONE_ID && aws ec2 delete-subnet \ --subnet-id $AWS_SUBNET_PRIVATE_TWO_ID ## Delete the vpc aws ec2 delete-vpc \ --vpc-id $AWS_VPC_ID ## Delete the directory used in this demo cd .. && rm -rf aws_internal_nlb_demo |
Hope you have enjoyed this article, In the next blog post, we will discuss Classic Load Balancer.
All the public cloud providers are changing the console user interface rapidly and due to this some of the screenshots used in our previous AWS blogs are no longer relevant. Hence, we have decided that from now onwards most of the demo will be done programmatically. Let us know your feedback on this in the comment section.
To get more details on AWS ELB, please refer below AWS documentation
https://docs.aws.amazon.com/elasticloadbalancing/index.html
Thanks for the article
kindly explains why step3 there is no subnets parameter in the create-load-balancer call.
is there a default value for subnets? if yes, what is it?
## Observe, we have assigned private ip 10.0.2.20 and 10.0.3.20 to NLB nodes
AWS_NLB_ARN=$(aws elbv2 create-load-balancer \
–name my-network-load-balancer \
–subnet-mappings SubnetId=$AWS_SUBNET_PRIVATE_ONE_ID,PrivateIPv4Address=10.0.2.20 \
SubnetId=$AWS_SUBNET_PRIVATE_TWO_ID,PrivateIPv4Address=10.0.3.20 \
–type network \
–scheme internal \
–query ‘LoadBalancers[0].LoadBalancerArn’ \
–output text)