Skip to content

Commit

Permalink
feat(route53): improve constructs for basic records (#2741)
Browse files Browse the repository at this point in the history
Constructs for records (CNAME, TXT, etc.) now extend the `RecordSet` construct and
offer better typed properties interfaces.

Add constructs for A, AAAA, CAA, MX and SRV records.

Add support for multiple values in basic records.

Make `recordName` optional with default to zone root.

Add a "security" `CaaAmazonRecord` construct to easily restrict certificate authorities
allowed to issue certificates for a domain to Amazon only.

BREAKING CHANGE: `recordValue: string` prop in `route53.TxtRecord` changed to `values: string[]`
* `recordValue` prop in `route53.CnameRecord` renamed to `domainName`
* `route53.AliasRecord` has been removed, use `route53.ARecord` or `route53.AaaaRecord` with the `target` prop.
  • Loading branch information
jogold authored and rix0rrr committed Jun 7, 2019
1 parent 6d83cb9 commit 696f53f
Show file tree
Hide file tree
Showing 27 changed files with 1,087 additions and 820 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import ecs = require('@aws-cdk/aws-ecs');
import { AliasRecord, IHostedZone } from '@aws-cdk/aws-route53';
import { AddressRecordTarget, ARecord, IHostedZone } from '@aws-cdk/aws-route53';
import targets = require('@aws-cdk/aws-route53-targets');
import cdk = require('@aws-cdk/cdk');
import { LoadBalancedServiceBase, LoadBalancedServiceBaseProps } from '../base/load-balanced-service-base';
Expand Down Expand Up @@ -120,10 +120,10 @@ export class LoadBalancedFargateService extends LoadBalancedServiceBase {
throw new Error('A Route53 hosted domain zone name is required to configure the specified domain name');
}

new AliasRecord(this, "DNS", {
new ARecord(this, "DNS", {
zone: props.domainZone,
recordName: props.domainName,
target: new targets.LoadBalancerTarget(this.loadBalancer),
target: AddressRecordTarget.fromAlias(new targets.LoadBalancerTarget(this.loadBalancer)),
});
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ export class CloudFrontTarget implements route53.IAliasRecordTarget {
constructor(private readonly distribution: cloudfront.CloudFrontWebDistribution) {
}

public bind(_record: route53.IAliasRecord): route53.AliasRecordTargetConfig {
public bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig {
return {
hostedZoneId: CLOUDFRONT_ZONE_ID,
dnsName: this.distribution.domainName
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.IAliasRecord): route53.AliasRecordTargetConfig {
public bind(_record: route53.IRecordSet): route53.AliasRecordTargetConfig {
return {
hostedZoneId: this.loadBalancer.loadBalancerCanonicalHostedZoneId,
dnsName: this.loadBalancer.loadBalancerDnsName
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,10 @@ test('use CloudFront as record target', () => {

// WHEN
const zone = new route53.PublicHostedZone(stack, 'HostedZone', { zoneName: 'test.public' });
new route53.AliasRecord(zone, 'Alias', {
new route53.ARecord(zone, 'Alias', {
zone,
recordName: '_foo',
target: new targets.CloudFrontTarget(distribution)
target: route53.AddressRecordTarget.fromAlias(new targets.CloudFrontTarget(distribution))
});

// THEN
Expand All @@ -37,4 +37,4 @@ test('use CloudFront as record target', () => {
HostedZoneId: "Z2FDTNDATAQYW2"
},
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ const lb = new elbv2.ApplicationLoadBalancer(stack, 'LB', {

const zone = new route53.PublicHostedZone(stack, 'HostedZone', { zoneName: 'test.public' });

new route53.AliasRecord(zone, 'Alias', {
new route53.ARecord(zone, 'Alias', {
zone,
recordName: '_foo',
target: new targets.LoadBalancerTarget(lb)
target: route53.AddressRecordTarget.fromAlias(new targets.LoadBalancerTarget(lb))
});

app.synth();
Original file line number Diff line number Diff line change
Expand Up @@ -25,10 +25,10 @@ const distribution = new cloudfront.CloudFrontWebDistribution(stack, 'MyDistribu
]
});

new route53.AliasRecord(zone, 'Alias', {
new route53.ARecord(zone, 'Alias', {
zone,
recordName: '_foo',
target: new targets.CloudFrontTarget(distribution)
target: route53.AddressRecordTarget.fromAlias(new targets.CloudFrontTarget(distribution))
});

app.synth();
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ test('use ALB as record target', () => {
const zone = new route53.PublicHostedZone(stack, 'HostedZone', { zoneName: 'test.public' });

// WHEN
new route53.AliasRecord(zone, 'Alias', {
new route53.ARecord(zone, 'Alias', {
zone,
recordName: '_foo',
target: new targets.LoadBalancerTarget(lb)
target: route53.AddressRecordTarget.fromAlias(new targets.LoadBalancerTarget(lb))
});

// THEN
Expand Down
54 changes: 42 additions & 12 deletions packages/@aws-cdk/aws-route53/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ To add a public hosted zone:
import route53 = require('@aws-cdk/aws-route53');

new route53.PublicHostedZone(this, 'HostedZone', {
zoneName: 'fully.qualified.domain.com'
zoneName: 'fully.qualified.domain.com'
});
```

Expand All @@ -33,8 +33,8 @@ import route53 = require('@aws-cdk/aws-route53');
const vpc = new ec2.VpcNetwork(this, 'VPC');

const zone = new route53.PrivateHostedZone(this, 'HostedZone', {
zoneName: 'fully.qualified.domain.com',
vpc // At least one VPC has to be added to a Private Hosted Zone.
zoneName: 'fully.qualified.domain.com',
vpc // At least one VPC has to be added to a Private Hosted Zone.
});
```

Expand All @@ -46,24 +46,54 @@ To add a TXT record to your zone:
```ts
import route53 = require('@aws-cdk/aws-route53');

new route53.TxtRecord(zone, 'TXTRecord', {
recordName: '_foo', // If the name ends with a ".", it will be used as-is;
// if it ends with a "." followed by the zone name, a trailing "." will be added automatically;
// otherwise, a ".", the zone name, and a trailing "." will be added automatically.
recordValue: 'Bar!', // Will be quoted for you, and " will be escaped automatically.
ttl: 90, // Optional - default is 1800
new route53.TxtRecord(this, 'TXTRecord', {
zone: myZone,
recordName: '_foo', // If the name ends with a ".", it will be used as-is;
// if it ends with a "." followed by the zone name, a trailing "." will be added automatically;
// otherwise, a ".", the zone name, and a trailing "." will be added automatically.
// Defaults to zone root if not specified.
values: [ // Will be quoted for you, and " will be escaped automatically.
'Bar!',
'Baz?'
],
ttl: 90, // Optional - default is 1800
});
```

To add a A record to your zone:
```ts
import route53 = require('@aws-cdk/aws-route53');

new route53.ARecord(this, 'ARecord', {
zone: myZone,
target: route53.AddressRecordTarget.fromIpAddresses('1.2.3.4', '5.6.7.8')
})
```

To add a AAAA record pointing to a CloudFront distribution:
```ts
import route53 = require('@aws-cdk/aws-route53');
import targets = require('@aws-cdk/aws-route53-targets');

new route53.AaaaRecord(this, 'Alias', {
zone: myZone,
target: route53.AddressRecordTarget.fromAlias(new targets.CloudFrontTarget(distribution))
})
```

Constructs are available for A, AAAA, CAA, CNAME, MX, NS, SRV and TXT records.

Use the `CaaAmazonRecord` construct to easily restrict certificate authorities
allowed to issue certificates for a domain to Amazon only.

### Adding records to existing hosted zones

If you know the ID and Name of a Hosted Zone, you can import it directly:

```ts
const zone = HostedZone.import(this, 'MyZone', {
zoneName: 'example.com',
hostedZoneId: 'ZOJJZC49E0EPZ',
zoneName: 'example.com',
hostedZoneId: 'ZOJJZC49E0EPZ',
});
```

Expand All @@ -72,6 +102,6 @@ to discover and import it:

```ts
const zone = new HostedZoneProvider(this, {
domainName: 'example.com'
domainName: 'example.com'
}).findAndImport(this, 'MyZone');
```
4 changes: 2 additions & 2 deletions packages/@aws-cdk/aws-route53/lib/alias-record-target.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IAliasRecord } from "./records/alias";
import { IRecordSet } from "./record-set";

/**
* Classes that are valid alias record targets, like CloudFront distributions and load
Expand All @@ -8,7 +8,7 @@ export interface IAliasRecordTarget {
/**
* Return hosted zone ID and DNS name, usable for Route53 alias targets
*/
bind(record: IAliasRecord): AliasRecordTargetConfig;
bind(record: IRecordSet): AliasRecordTargetConfig;
}

/**
Expand Down
24 changes: 21 additions & 3 deletions packages/@aws-cdk/aws-route53/lib/hosted-zone.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import ec2 = require('@aws-cdk/aws-ec2');
import { Construct, Resource, Token } from '@aws-cdk/cdk';
import { HostedZoneAttributes, IHostedZone } from './hosted-zone-ref';
import { ZoneDelegationRecord } from './records';
import { CaaAmazonRecord, ZoneDelegationRecord } from './record-set';
import { CfnHostedZone } from './route53.generated';
import { validateZoneName } from './util';

Expand Down Expand Up @@ -107,7 +107,19 @@ export class HostedZone extends Resource implements IHostedZone {
}
}

export interface PublicHostedZoneProps extends CommonHostedZoneProps { }
/**
* Construction properties for a PublicHostedZone.
*/
export interface PublicHostedZoneProps extends CommonHostedZoneProps {
/**
* Whether to create a CAA record to restrict certificate authorities allowed
* to issue certificates for this domain to Amazon only.
*
* @default false
*/
readonly caaAmazon?: boolean;
}

export interface IPublicHostedZone extends IHostedZone { }

/**
Expand All @@ -127,6 +139,12 @@ export class PublicHostedZone extends HostedZone implements IPublicHostedZone {

constructor(scope: Construct, id: string, props: PublicHostedZoneProps) {
super(scope, id, props);

if (props.caaAmazon) {
new CaaAmazonRecord(this, 'CaaAmazon', {
zone: this
});
}
}

public addVpc(_vpc: ec2.IVpc) {
Expand All @@ -142,7 +160,7 @@ export class PublicHostedZone extends HostedZone implements IPublicHostedZone {
public addDelegation(delegate: IPublicHostedZone, opts: ZoneDelegationOptions = {}): void {
new ZoneDelegationRecord(this, `${this.zoneName} -> ${delegate.zoneName}`, {
zone: this,
delegatedZoneName: delegate.zoneName,
recordName: delegate.zoneName,
nameServers: delegate.hostedZoneNameServers!, // PublicHostedZones always have name servers!
comment: opts.comment,
ttl: opts.ttl,
Expand Down
2 changes: 1 addition & 1 deletion packages/@aws-cdk/aws-route53/lib/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
export * from './hosted-zone';
export * from './hosted-zone-provider';
export * from './hosted-zone-ref';
export * from './records';
export * from './record-set';
export * from './alias-record-target';

// AWS::Route53 CloudFormation Resources:
Expand Down
Loading

0 comments on commit 696f53f

Please sign in to comment.