Thursday, February 02, 2023

How to find Private Network Load Balancer (NLB) ALBv2 IP4 addresses for adding to security group to allow health checks to pass

 Use case:

My Target Groups attached to my Load Balancer route to a private internal port that is not on the security group white listing.   Due to Network Load Balancer's use of the EC2 connected Security Group. I don't want to whitelist the private internal port to the internet for possible bypass.

This can be done manually in the aws console by finding the ENI by looking up the ELB (type)/(name)/(random string) getting the private ip4 and then adding them manually to the security group.


But this defeats the purpose of having a cloudformation script that automatically stands up everything to work.

in this example we want to get the private ip4 address of a ELBv2 (network). Full working example: https://github.com/qld-gov-au/quickstart-atlassian-bitbucket/blob/d6ebe59b5ccdd204a7edc72ab6f0f89d575ac6f8/templates/quickstart-bitbucket-dc.template.yaml 



(non-gist version below)

#Network Load Balancer health checks, need internal ip to approve connectivity

InternalNLBIp4List:
  DependsOn: NetworkLoadBalancerELB2
  Type: Custom::InternalNLBIp4ListCollector
  Version: 1.0
  Properties:
    ServiceToken: !GetAtt InternalNLBIp4ListCollector.Arn
    ELBv2Arn: !Ref NetworkLoadBalancerELB2
    StackName: !Ref 'AWS::StackName'
InternalNLBIp4ListCollector:
  Type: "AWS::Lambda::Function"
Properties:
    Handler: index.lambda_handler
    Role: !GetAtt InternalNLBIp4ListCollectorExecutionRole.Arn
    Runtime: python3.7
    Timeout: 120
    Code:
      ZipFile: |
        import cfnresponse
        import boto3

        def lambda_handler(event, context):
          elbv2 = boto3.client('elbv2')
          ec2 = boto3.client('ec2')
          elb2arn = event['ResourceProperties']['ELBv2Arn']
          response = elbv2.describe_load_balancers(LoadBalancerArns=[elb2arn])
          name = response['LoadBalancers'][0]['LoadBalancerName']
          elbtype = response['LoadBalancers'][0]['Type']
          filters = [{'Name': 'description', 'Values': ['ELB '+ elbtype[0:3] + '/' + name + '*']}]
          eni_response = ec2.describe_network_interfaces(Filters=filters)
          ip_addresses = [eni['PrivateIpAddress'] for eni in eni_response['NetworkInterfaces']]
          ip_addresses_cidr = [eni['PrivateIpAddress'] + '/32' for eni in eni_response['NetworkInterfaces']]
          print (ip_addresses)
          responseData = {}
          responseData['PrivateIpAddresses'] = ip_addresses
          responseData['PrivateIpCidrAddresses'] = ip_addresses_cidr
          cfnresponse.send(event, context, cfnresponse.SUCCESS, responseData)

InternalNLBIp4ListCollectorExecutionRole:
  Type: "AWS::IAM::Role"
Properties:
    AssumeRolePolicyDocument:
      Version: '2012-10-17'
Statement:
        - Effect: Allow
          Principal:
            Service:
              - lambda.amazonaws.com
          Action:
            - sts:AssumeRole
    Path: "/"
Policies:
      - PolicyName: root
        PolicyDocument:
          Version: '2012-10-17'
Statement:
            - Effect: Allow
              Action:
                - logs:CreateLogGroup
                - logs:CreateLogStream
                - logs:PutLogEvents
              Resource: !Sub "arn:${AWS::Partition}:logs:*:${AWS::AccountId}:log-group:/aws/lambda/*InternalNLBIp4ListCollector*"
- Effect: Allow
              Action:
                - "elasticloadbalancing:DescribeLoadBalancers"
- "ec2:DescribeNetworkInterfaces"
Resource: "*"
#NLB ip's need to be whitelisted to allow health checks to pass
SecurityGroupIngressNLB:
  DependsOn:
    - InternalNLBIp4List
    - SecurityGroup
  Type: AWS::EC2::SecurityGroupIngress
  Properties:
    GroupId: !Ref SecurityGroup
    IpProtocol: "-1"
FromPort: -1
    ToPort: -1
    CidrIp: !Select [ 0, !GetAtt InternalNLBIp4List.PrivateIpCidrAddresses ]

SecurityGroupIngressNLB2: #ELB in 2 subnets, will have 2 ip's
DependsOn:
    - InternalNLBIp4List
    - SecurityGroup
  Type: AWS::EC2::SecurityGroupIngress
  Properties:
    GroupId: !Ref SecurityGroup
    IpProtocol: "-1"
FromPort: -1
    ToPort: -1
    CidrIp: !Select [ 1, !GetAtt InternalNLBIp4List.PrivateIpCidrAddresses ]

No comments: