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 ]