aws-route53-targets: LoadBalancerTarget always appends the `dualstack` prefix even when not a valid option
What is the problem?
When fixing https://github.com/aws/aws-cdk/issues/6271 with https://github.com/aws/aws-cdk/pull/8747, you enforced that all load balancer targets start with the dualstack prefix. Network Load Balancers (NLBs) have 2 IP Address types you can configure, IPv4 or dualstack (this was launched late last year). The default for the property is IPv4, and the CDK definition doesn't even allow for the option to be set. When NLB is set to IPv4, it does not have a dualstack prefix you can route to. This means the generated ARecords don't work; they target a non-existent DNS record.
Reproduction Steps
I'm going to leave the class instantiation out, but you can assume this is within a construct.
this.hostedZone = new route53.HostedZone(this, "ExampleHostedZone", {
zoneName: props.hostedZoneName,
});
this.vpc = new ec2.Vpc(this, "ExampleVPC");
this.loadBalancer = new elasticloadbalancingv2.NetworkLoadBalancer(this, "ExampleNLB", {
vpc: this.vpc,
});
new aws-route53.ARecord(this,
"LoadBalancerAlias",
{
zone: this.hostedZone,
target: aws-route53.RecordTarget.fromAlias(
new aws-route53-targets.LoadBalancerTarget(this.loadBalancer)
),
comment: "A-Record to route traffic to the service Load Balancer",
}
);
What did you expect to happen?
I expected a valid Alias ARecord to my NLB.
What actually happened?
The CDK incorrectly prefixed dualstack to my NLB DNS name, causing the service to be unreachable.
CDK CLI Version
1.125.0
Framework Version
No response
Node.js Version
12
OS
AmazonLinux 2
Language
Typescript
Language Version
No response
Other information
The NLB IPAddressType is a configurable property of the Cfn definition https://docs.aws.amazon.com/AWSCloudFormation/latest/UserGuide/aws-resource-elasticloadbalancingv2-loadbalancer.html#cfn-elasticloadbalancingv2-loadbalancer-ipaddresstype
I'm also running into this issue. @epalace510 did you figure out a workaround?
In my case I'm creating an NLB-specific version of https://github.com/aws/aws-cdk/blob/v1.134.0/packages/@aws-cdk/aws-route53-targets/lib/load-balancer-target.ts
Same issue also with CDK v2.
@larryboymi I wrote a class to do what I needed. It's not my preferred solution, but it unblocked me.
import { AliasRecordTargetConfig, IAliasRecordTarget, IHostedZone, IRecordSet } from "monocdk/aws-route53";
import { NetworkLoadBalancer } from "monocdk/aws-elasticloadbalancingv2";
/**
* Use an ELB Network Load Balancer as an alias record target.
* This NLB specific target was written because CDK will always prepend
* `dualstack` to the DNS name which is not always valid for NLBs.
* https://github.com/aws/aws-cdk/issues/16987
*/
export class NetworkLoadBalancerTarget implements IAliasRecordTarget {
private readonly loadBalancer: NetworkLoadBalancer;
constructor(loadBalancer: NetworkLoadBalancer) {
this.loadBalancer = loadBalancer;
}
/**
* Return hosted zone ID and DNS name, usable for Route53 alias targets.
*/
bind(_record: IRecordSet, _zone?: IHostedZone): AliasRecordTargetConfig {
return {
hostedZoneId: this.loadBalancer.loadBalancerCanonicalHostedZoneId,
dnsName: this.loadBalancer.loadBalancerDnsName,
};
}
}
@epalace510 yep that's exactly what my class looked like
I'm facing exactly the same issue.
This issue has not received any attention in 1 year. If you want to keep this issue open, please leave a comment below and auto-close will be canceled.
Possible Solution
-
First, we need to modify the
ILoadBalancerV2interface to expose the IP address type. We'll need to check the NetworkLoadBalancer implementation to see how to access this property. -
Then, we'll update the
LoadBalancerTargetclass to check the IP address type before adding the dualstack prefix.
Here's what the implementation will look like:
// In aws-elasticloadbalancingv2/lib/shared/load-balancer.ts
export interface ILoadBalancerV2 extends IResource {
// ... existing properties ...
/**
* The IP address type of the load balancer
* @default - IPv4
*/
readonly ipAddressType?: LoadBalancerIpAddressType;
}
export enum LoadBalancerIpAddressType {
IPV4 = 'ipv4',
DUALSTACK = 'dualstack'
}
// In aws-route53-targets/lib/load-balancer-target.ts
export class LoadBalancerTarget implements route53.IAliasRecordTarget {
constructor(private readonly loadBalancer: elbv2.ILoadBalancerV2, private readonly props?: IAliasRecordTargetProps) {}
public bind(_record: route53.IRecordSet, _zone?: route53.IHostedZone): route53.AliasRecordTargetConfig {
const dnsName = this.loadBalancer.ipAddressType === elbv2.LoadBalancerIpAddressType.DUALSTACK
? `dualstack.${this.loadBalancer.loadBalancerDnsName}`
: this.loadBalancer.loadBalancerDnsName;
return {
hostedZoneId: this.loadBalancer.loadBalancerCanonicalHostedZoneId,
dnsName,
evaluateTargetHealth: this.props?.evaluateTargetHealth,
};
}
}
-
We'll also need to update the NetworkLoadBalancer class to properly set the ipAddressType property based on its configuration.
-
Finally, we'll add tests to verify the behavior:
test('creates correct DNS name for IPv4 NLB', () => {
// Test setup with IPv4 NLB
// Verify DNS name doesn't have dualstack prefix
});
test('creates correct DNS name for dualstack NLB', () => {
// Test setup with dualstack NLB
// Verify DNS name has dualstack prefix
});
I will dive into this today and see if this solution is working.