# Enable DNSSEC signing in Amazon Route 53 using AWS CDK

[DNSSEC (Domain Security Extensions)](https://www.icann.org/resources/pages/dnssec-what-is-it-why-important-2019-03-05-en) adds security features to the DNS protocol so that DNS resolvers can verify that the data came from the specific zone and validate that it has not been tampered with in transit. In this post I will explain how to [enable DNSSEC signing in Amazon Route 53](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-configuring-dnssec.html), not via the Console, but using AWS CDK.

## Preparation

Consider the preparation steps mentioned under [Step 1 in this developer guide](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-configuring-dnssec-enable-signing.html).

## Customer Managed Key

First, you will need to create a stack that creates a Customer Managed Key in AWS KMS (Key Management Service). It is important that this stack and the key is created in N.Virginia region (`us-east-1`).

These are the imports needed (this is for CDK V1, make the necessary changes for CDK V2)

```typescript
import * as cdk from '@aws-cdk/core';
import * as iam from '@aws-cdk/aws-iam';
import * as kms from '@aws-cdk/aws-kms';
```

Create the key with the right cryptographic configuration (`ECC_NIST_P256`) and the correct cryptographic operations for which the key can be used (`SIGN_VERIFY`).

```typescript
const dnssecKeyAlias = 'example-com-dnssec-key';

const dnssecKey = new kms.Key(this, 'dnssec-key', {
  enableKeyRotation: false,
  removalPolicy: cdk.RemovalPolicy.DESTROY,
  alias: dnssecKeyAlias,
  keySpec: kms.KeySpec.ECC_NIST_P256,
  keyUsage: kms.KeyUsage.SIGN_VERIFY,
});
```

Give Route 53 DNSSEC Service the necessary permissions in order to use the key.

```typescript
dnssecKey.addToResourcePolicy(new iam.PolicyStatement({
  sid: "Allow Route 53 DNSSEC Service",
  effect: iam.Effect.ALLOW,
  principals: [
    new iam.ServicePrincipal("dnssec-route53.amazonaws.com")
  ],
  actions: [
    "kms:DescribeKey",
    "kms:GetPublicKey",
    "kms:Sign"
  ],
  resources: ["*"],
  conditions: {
    "StringEquals": {
      "aws:SourceAccount": cdk.Aws.ACCOUNT_ID
    }
  }
}));

dnssecKey.addToResourcePolicy(new iam.PolicyStatement({
  sid: "Allow Route 53 DNSSEC to CreateGrant",
  effect: iam.Effect.ALLOW,
  principals: [
    new iam.ServicePrincipal("dnssec-route53.amazonaws.com")
  ],
  actions: [
    "kms:CreateGrant"
  ],
  resources: ["*"],
  conditions: {
    "StringEquals": {
      "aws:SourceAccount": cdk.Aws.ACCOUNT_ID
    },
    "Bool": {
      "kms:GrantIsForAWSResource": true
    }
  }
}));
```

## Enable DNSSEC signing

Now we go back to the stack where you have defined your hosted zone. This can be the same or a different stack, and it does not need to be deployed in N.Virginia. The imports needed are

```typescript
import * as cdk from '@aws-cdk/core';
import * as route53 from '@aws-cdk/aws-route53';
```

In my case, the two stacks are in two different regions, so I have hard-coded the key alias. You can use other ways of sharing the key ARN between stacks, for example, if they are in the same region you can [export and then import the ARN](https://docs.aws.amazon.com/cdk/api/v1/docs/@aws-cdk_core.CfnOutput.html#exportname).

```typescript
const dnssecKeyAlias = 'example-com-dnssec-key';

const zone = new route53.PublicHostedZone(this, 'zone-example-com', {
  zoneName: 'example.com'
});
```

Create a [Key Signing Key (KSK)](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/dns-configuring-dnssec-ksk.html)

```typescript
const keySigningKey = new route53.CfnKeySigningKey(this, 'route-53-key-signing-key', {
  hostedZoneId: zone.hostedZoneId,
  keyManagementServiceArn: `arn:aws:kms:us-east-1:${cdk.Aws.ACCOUNT_ID}:alias/${dnssecKeyAlias}`,
  name: 'ExampleComKeySigningKey',
  status: 'ACTIVE',
});
```

and then associate the KSK with the hosted zone.

```typescript
const dnssec = new route53.CfnDNSSEC(this, 'zone-example-com-dnssec', {
  hostedZoneId: zone.hostedZoneId
});
dnssec.node.addDependency(keySigningKey);
```

Verify in the console that DNSSEC Signing has been enabled for your hosted zone.

![aws-console-verify-dnssec-enabled.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1654583451527/hVg1gcaQM.png align="left")

## Establish a chain of trust

This is the only manual step and will vary depending on your domain registrar or whether you own the parent domain.

In the console, in the screen shown above, click `View Information to create DS record` and follow the instructions to `Establish a chain of trust`. On this page, you can find the public key, the key type (flags field), the signing algorithm and the DS record.

If Route 53 is your registrar, in a new tab go to Registered Domains, open your domain page, and under `DNSSEC status` click `Manage Keys`. Select the correct algorithm (shown on the information page) and copy and paste your public key.

If you own the parent domain, then you should create a DS (Delegation Signer) record in the parent zone that you control.

```typescript
const parentZone = route53.HostedZone.fromLookup(this, 'parent-zone', {
  domainName: 'example.com'
});

new route53.DsRecord(this, 'my-subdomain-delegation-signer', {
  zone: parentZone,
  recordName: 'my-subdomain',
  values: [
    '<DS record copied from the console>'
  ],
  ttl: cdk.Duration.seconds(3600)
});
```

## Verify that DNSSEC is enabled

Finally, you can verify that DNSSEC is enabled with the command line tool `dig`.

Find your name servers

```bash
dig codiply.com. NS
```

and then query one of them with `+dnssec` (prepend `@` before the name server address)

```bash
dig codiply.com.  +dnssec @ns-477.awsdns-59.com.
```

If DNSSEC is enabled, in the first few lines of the response you should see `ad` among the flags listed.

```bash
;; flags: qr aa rd ad;
```

Congratulations, DNSSEC is enabled for your domain!
