Skip to content

Commit

Permalink
feat(route53-targets): route53 record target (#14820)
Browse files Browse the repository at this point in the history
Add an alias target for a Route53 record.

Closes #14800


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
jogold authored Jun 7, 2021
1 parent f0c9726 commit b22da80
Show file tree
Hide file tree
Showing 17 changed files with 147 additions and 13 deletions.
9 changes: 9 additions & 0 deletions packages/@aws-cdk/aws-route53-targets/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,4 +120,13 @@ See [the Developer Guide](https://docs.aws.amazon.com/Route53/latest/DeveloperGu
});
```

* Route 53 record

```ts
new route53.ARecord(this, 'AliasRecord', {
zone,
target: route53.RecordTarget.fromAlias(new targets.Route53RecordTarget(record)),
});
```

See the documentation of `@aws-cdk/aws-route53` for more information.
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import * as route53 from '@aws-cdk/aws-route53';
export class ApiGatewayDomain implements route53.IAliasRecordTarget {
constructor(private readonly domainName: apig.IDomainName) { }

public bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig {
public bind(_record: route53.IRecordSet, _zone?: route53.IHostedZone): route53.AliasRecordTargetConfig {
return {
dnsName: this.domainName.domainNameAliasDomainName,
hostedZoneId: this.domainName.domainNameAliasHostedZoneId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ export class ApiGatewayv2DomainProperties implements route53.IAliasRecordTarget
*/
constructor(private readonly regionalDomainName: string, private readonly regionalHostedZoneId: string) { }

public bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig {
public bind(_record: route53.IRecordSet, _zone?: route53.IHostedZone): route53.AliasRecordTargetConfig {
return {
dnsName: this.regionalDomainName,
hostedZoneId: this.regionalHostedZoneId,
};
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ export class BucketWebsiteTarget implements route53.IAliasRecordTarget {
constructor(private readonly bucket: s3.IBucket) {
}

public bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig {
public bind(_record: route53.IRecordSet, _zone?: route53.IHostedZone): route53.AliasRecordTargetConfig {
const { region } = Stack.of(this.bucket.stack);

if (Token.isUnresolved(region)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class ClassicLoadBalancerTarget implements route53.IAliasRecordTarget {
constructor(private readonly loadBalancer: elb.LoadBalancer) {
}

public bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig {
public bind(_record: route53.IRecordSet, _zone?: route53.IHostedZone): route53.AliasRecordTargetConfig {
return {
hostedZoneId: this.loadBalancer.loadBalancerCanonicalHostedZoneNameId,
dnsName: `dualstack.${this.loadBalancer.loadBalancerDnsName}`,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ export class CloudFrontTarget implements route53.IAliasRecordTarget {
constructor(private readonly distribution: cloudfront.IDistribution) {
}

public bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig {
public bind(_record: route53.IRecordSet, _zone?: route53.IHostedZone): route53.AliasRecordTargetConfig {
return {
hostedZoneId: CloudFrontTarget.getHostedZoneId(this.distribution),
dnsName: this.distribution.distributionDomainName,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export class GlobalAcceleratorDomainTarget implements route53.IAliasRecordTarget
constructor(private readonly acceleratorDomainName: string) {
}

bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig {
bind(_record: route53.IRecordSet, _zone?: route53.IHostedZone): route53.AliasRecordTargetConfig {
return {
hostedZoneId: GlobalAcceleratorTarget.GLOBAL_ACCELERATOR_ZONE_ID,
dnsName: this.acceleratorDomainName,
Expand Down
1 change: 1 addition & 0 deletions packages/@aws-cdk/aws-route53-targets/lib/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,4 @@ export * from './load-balancer-target';
export * from './interface-vpc-endpoint-target';
export * from './userpool-domain';
export * from './global-accelerator-target';
export * from './route53-record';
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ export class InterfaceVpcEndpointTarget implements route53.IAliasRecordTarget {
this.cfnVpcEndpoint = this.vpcEndpoint.node.findChild('Resource') as ec2.CfnVPCEndpoint;
}

public bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig {
public bind(_record: route53.IRecordSet, _zone?: route53.IHostedZone): route53.AliasRecordTargetConfig {
return {
dnsName: cdk.Fn.select(1, cdk.Fn.split(':', cdk.Fn.select(0, this.cfnVpcEndpoint.attrDnsEntries))),
hostedZoneId: cdk.Fn.select(0, cdk.Fn.split(':', cdk.Fn.select(0, this.cfnVpcEndpoint.attrDnsEntries))),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ export class LoadBalancerTarget implements route53.IAliasRecordTarget {
constructor(private readonly loadBalancer: elbv2.ILoadBalancerV2) {
}

public bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig {
public bind(_record: route53.IRecordSet, _zone?: route53.IHostedZone): route53.AliasRecordTargetConfig {
return {
hostedZoneId: this.loadBalancer.loadBalancerCanonicalHostedZoneId,
dnsName: `dualstack.${this.loadBalancer.loadBalancerDnsName}`,
Expand Down
19 changes: 19 additions & 0 deletions packages/@aws-cdk/aws-route53-targets/lib/route53-record.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import * as route53 from '@aws-cdk/aws-route53';

/**
* Use another Route 53 record as an alias record target
*/
export class Route53RecordTarget implements route53.IAliasRecordTarget {
constructor(private readonly record: route53.IRecordSet) {
}

public bind(_record: route53.IRecordSet, zone?: route53.IHostedZone): route53.AliasRecordTargetConfig {
if (!zone) { // zone introduced as optional to avoid a breaking change
throw new Error('Cannot bind to record without a zone');
}
return {
dnsName: this.record.domainName,
hostedZoneId: zone.hostedZoneId,
};
}
}
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-route53-targets/lib/userpool-domain.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { UserPoolDomain } from '@aws-cdk/aws-cognito';
import { AliasRecordTargetConfig, IAliasRecordTarget, IRecordSet } from '@aws-cdk/aws-route53';
import { AliasRecordTargetConfig, IAliasRecordTarget, IHostedZone, IRecordSet } from '@aws-cdk/aws-route53';
import { CloudFrontTarget } from './cloudfront-target';

/**
Expand All @@ -9,7 +9,7 @@ export class UserPoolDomainTarget implements IAliasRecordTarget {
constructor(private readonly domain: UserPoolDomain) {
}

public bind(_record: IRecordSet): AliasRecordTargetConfig {
public bind(_record: IRecordSet, _zone?: IHostedZone): AliasRecordTargetConfig {
return {
dnsName: this.domain.cloudFrontDomainName,
hostedZoneId: CloudFrontTarget.getHostedZoneId(this.domain),
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
{
"Resources": {
"HostedZoneDB99F866": {
"Type": "AWS::Route53::HostedZone",
"Properties": {
"Name": "cdk-integ.com."
}
},
"WWW9F8609DA": {
"Type": "AWS::Route53::RecordSet",
"Properties": {
"Name": "www.cdk-integ.com.",
"Type": "A",
"HostedZoneId": {
"Ref": "HostedZoneDB99F866"
},
"ResourceRecords": [
"1.2.3.4"
],
"TTL": "1800"
}
},
"Alias325C5727": {
"Type": "AWS::Route53::RecordSet",
"Properties": {
"Name": "cdk-integ.com.",
"Type": "A",
"AliasTarget": {
"DNSName": {
"Ref": "WWW9F8609DA"
},
"HostedZoneId": {
"Ref": "HostedZoneDB99F866"
}
},
"HostedZoneId": {
"Ref": "HostedZoneDB99F866"
}
}
}
}
}
30 changes: 30 additions & 0 deletions packages/@aws-cdk/aws-route53-targets/test/integ.route53-record.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
#!/usr/bin/env node
import * as route53 from '@aws-cdk/aws-route53';
import { App, Stack } from '@aws-cdk/core';
import { Construct } from 'constructs';
import * as targets from '../lib';

class TestStack extends Stack {
constructor(scope: Construct, id: string) {
super(scope, id);

const zone = new route53.PublicHostedZone(this, 'HostedZone', {
zoneName: 'cdk-integ.com',
});

const www = new route53.ARecord(this, 'WWW', {
zone,
recordName: 'www.cdk-integ.com',
target: route53.RecordTarget.fromIpAddresses('1.2.3.4'),
});

new route53.ARecord(this, 'Alias', {
zone,
target: route53.RecordTarget.fromAlias(new targets.Route53RecordTarget(www)),
});
}
}

const app = new App();
new TestStack(app, 'aws-cdk-r53-record-alias-target-integ');
app.synth();
32 changes: 32 additions & 0 deletions packages/@aws-cdk/aws-route53-targets/test/route53-record.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import '@aws-cdk/assert-internal/jest';
import { ARecord, PublicHostedZone, RecordTarget } from '@aws-cdk/aws-route53';
import { Stack } from '@aws-cdk/core';
import { Route53RecordTarget } from '../lib';

test('use another route 53 record as record target', () => {
// GIVEN
const stack = new Stack();
const zone = new PublicHostedZone(stack, 'HostedZone', { zoneName: 'test.public' });
const record = new ARecord(zone, 'Record', {
zone,
target: RecordTarget.fromIpAddresses('1.2.3.4'),
});

// WHEN
new ARecord(zone, 'Alias', {
zone,
target: RecordTarget.fromAlias(new Route53RecordTarget(record)),
});

// THEN
expect(stack).toHaveResource('AWS::Route53::RecordSet', {
AliasTarget: {
DNSName: {
Ref: 'HostedZoneRecordB6AB510D',
},
HostedZoneId: {
Ref: 'HostedZoneDB99F866',
},
},
});
});
3 changes: 2 additions & 1 deletion packages/@aws-cdk/aws-route53/lib/alias-record-target.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { IHostedZone } from './hosted-zone-ref';
import { IRecordSet } from './record-set';

/**
Expand All @@ -8,7 +9,7 @@ export interface IAliasRecordTarget {
/**
* Return hosted zone ID and DNS name, usable for Route53 alias targets
*/
bind(record: IRecordSet): AliasRecordTargetConfig;
bind(record: IRecordSet, zone?: IHostedZone): AliasRecordTargetConfig;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-route53/lib/record-set.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,7 +226,7 @@ export class RecordSet extends Resource implements IRecordSet {
name: determineFullyQualifiedDomainName(props.recordName || props.zone.zoneName, props.zone),
type: props.recordType,
resourceRecords: props.target.values,
aliasTarget: props.target.aliasTarget && props.target.aliasTarget.bind(this),
aliasTarget: props.target.aliasTarget && props.target.aliasTarget.bind(this, props.zone),
ttl,
comment: props.comment,
});
Expand Down

0 comments on commit b22da80

Please sign in to comment.