All files / lib dns.ts

95.83% Statements 23/24
62.5% Branches 5/8
100% Functions 4/4
95.83% Lines 23/24

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 1172x 2x 2x 2x   2x                                               2x       1x 1x   1x 3x 3x       3x 3x 3x                         1x       1x                         3x 3x                 3x         3x                   3x               3x       1x          
import * as cdk from "@aws-cdk/core";
import * as iam from "@aws-cdk/aws-iam";
import * as route53 from "@aws-cdk/aws-route53";
import { RecordTarget } from "@aws-cdk/aws-route53";
import {Account} from './account';
import * as utils from './dns/delegation-record-handler/utils';
 
/**
 * Properties for RootDns
 */
export interface RootDnsProps {
  /**
   * The stages Accounts taht will need their subzone delegation
   */
  readonly stagesAccounts: Account[];
  /**
   * The top level domain name
   */
  readonly rootHostedZoneDNSName: string;
 
  /**
   * A boolean indicating if Domain name has already been registered to a third party or if you want this contruct to create it (the latter is not yet supported)
   */
  readonly thirdPartyProviderDNSUsed?: boolean;
}
 
/**
 * A class creating the main hosted zone and a role assumable by stages account to be able to set sub domain delegation
 */
export class RootDns extends cdk.Construct {
  rootHostedZone: route53.IHostedZone;
 
  constructor(scope: cdk.Construct, id: string, props: RootDnsProps) {
    super(scope, id);
    this.rootHostedZone = this.createRootHostedZone(props);
 
    for (const accountIndex in props.stagesAccounts) {
      const account = props.stagesAccounts[accountIndex];
      const stageSubZone = this.createStageSubZone(
        account,
        props.rootHostedZoneDNSName
      );
      this.createDNSAutoUpdateRole(account, stageSubZone);
      Eif (stageSubZone.hostedZoneNameServers) {
        new route53.RecordSet(
          this,
          `${account.accountName}SubZoneDelegationNSRecord`,
          {
            recordType: route53.RecordType.NS,
            target: RecordTarget.fromValues(...stageSubZone.hostedZoneNameServers?stageSubZone.hostedZoneNameServers:''),
            recordName: stageSubZone.zoneName,
            zone: this.rootHostedZone,
          }
        );
      }
    }
 
    Eif (
      props.thirdPartyProviderDNSUsed &&
      this.rootHostedZone.hostedZoneNameServers
    ) {
      new cdk.CfnOutput(this, `NS records`, {
        value: cdk.Fn.join(",", this.rootHostedZone.hostedZoneNameServers),
      });
    } else {
      throw new Error("Creation of DNS domain is not yet supported");
      // TODO: implement call to https://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/Route53Domains.html#registerDomain-property
    }
  }
 
  createStageSubZone(
    account: Account,
    rootHostedZoneDNSName: string
  ): route53.HostedZone {
    const subDomainPrefix = utils.getSubdomainPrefix(account.accountName, account.accountStageName);
    return new route53.HostedZone(this, `${subDomainPrefix}StageSubZone`, {
      zoneName: `${subDomainPrefix}.${rootHostedZoneDNSName}`,
    });
  }
 
  createDNSAutoUpdateRole(
    account: Account,
    stageSubZone: route53.HostedZone
  ) {
    const dnsAutoUpdateRole = new iam.Role(this, stageSubZone.zoneName, {
      assumedBy: new iam.AccountPrincipal(account.accountId),
      roleName: utils.getDNSUpdateRoleNameFromSubZoneName(stageSubZone.zoneName)
    });
 
    dnsAutoUpdateRole.addToPolicy(
      new iam.PolicyStatement({
        resources: [stageSubZone.hostedZoneArn],
        actions: [
          "route53:GetHostedZone",
          "route53:ChangeResourceRecordSets",
          "route53:TestDNSAnswer",
        ],
      })
    );
    dnsAutoUpdateRole.addToPolicy(
      new iam.PolicyStatement({
        resources: ['*'],
        actions: [
          "route53:ListHostedZonesByName"
        ],
      })
    );
    return dnsAutoUpdateRole;
  }
 
  createRootHostedZone(props: RootDnsProps) {
    return new route53.HostedZone(this, "RootHostedZone", {
      zoneName: props.rootHostedZoneDNSName,
    });
  }
}