IT. SECURITY. OPEN SOURCE.

Category: AWS

dnssec

Configuring DNSSEC With Terraform and AWS Route 53

Why Enable DNSSEC?

The Domain Name Service (or DNS) has been apart of the internet since the 1980’s by combinging names to IP addresses together. Though there have been a few blog posts about DNS, we never discussed how to provide authentication to the responses you receive. Providing DNS services without authentication could lead someone to a rogue or spoofed internet site. This is where DNSSEC comes in.

A common attack vector against DNS servers is known as DNS Cache Poisoning. This happens when an attacker is allowed to send updates to zone files which do not belong to them. For instance, if I were allowed to send updates to a DNS server that belongs to Google, I could then point destination traffic to a host in my possession. I would then be able to set up sites which look identical to those of Google and steal your username and password, or capture what you look up online.

What DNSSEC Is Not

The activation of DNSSEC on your domain provides authenticity of the zone records, it does not provide confidentiality. DNSSEC does not encrypt your DNS traffic to and from the resolver. To provide encryption you must use the DNS over HTTPS (DOH), or DNS over TLS (DOT) protocol. These protocols protect your online privacy by encrypting DNS traffic to the resolver. This prevents Internet Service Providers (ISP) from sniffing your traffic.

You can also combine DOH/DOT and DNSSEC which will provide privacy and authenticity of the resolver. This is a new concept and only a few DNS providers are performing this type of service.

Getting Started

First you need to check if your Top Level Domain (TLD) supports DNSSEC.

If you own a .com domain, you are able to activate DNSSEC. For other TLD’s, please check the ICANN website.

Creating the KMS Key and Policy

The following is a template which can be used to create the KMS key and JSON policy. This will create an ECDSA P256 asymmetric key with sign and verify capabilities. Remember, DNSSEC does not provide privacy so all we need is to sign and verify the domain.

resource "aws_kms_key" "domaindnssec" {
  customer_master_key_spec = "ECC_NIST_P256"
  deletion_window_in_days  = 7
  key_usage                = "SIGN_VERIFY"
  policy = jsonencode({
    Statement = [
      {
        Action = [
          "kms:DescribeKey",
          "kms:GetPublicKey",
          "kms:Sign",
        ],
        Effect = "Allow"
        Principal = {
          Service = "dnssec-route53.amazonaws.com"
        }
        Sid      = "Allow Route 53 DNSSEC Service",
        Resource = "*"
      },
      {
        Action = "kms:CreateGrant",
        Effect = "Allow"
        Principal = {
          Service = "dnssec-route53.amazonaws.com"
        }
        Sid      = "Allow Route 53 DNSSEC Service to CreateGrant",
        Resource = "*"
        Condition = {
          Bool = {
            "kms:GrantIsForAWSResource" = "true"
          }
        }
      },
      {
        Action = "kms:*"
        Effect = "Allow"
        Principal = {
          AWS = "*"
        }
        Resource = "*"
        Sid      = "IAM User Permissions"
      },
    ]
    Version = "2012-10-17"
  })
}

Next, we define the zone and tie the keys to the zone for signature and verification.

data "aws_route53_zone" "example" {
  name = "example.com"
}

resource "aws_route53_key_signing_key" "dnssecksk" {
  name = "example.com"
  hosted_zone_id = data.aws_route53_zone.example.id
  key_management_service_arn = aws_kms_key.dnssecksk.arn
}

resource "aws_route53_hosted_zone_dnssec" "example" {
  depends_on = [
    aws_route53_key_signing_key.dnssecksk
  ]
  hosted_zone_id = aws_route53_key_signing_key.dnssecksk.hosted_zone_id
}

Verify That DNSSEC Is Working

Use dig to verify that DNSSEC is working on the domain. To get started use the following command:

dig +short +dnssec example.com

Note that the resolver being used must be capable of providing DNSSEC look ups. To verify, run the dig command against a known DNSSEC service provider like Cloudflare.

$ dig +short +dnssec cloudflare.com. @1.1.1.1
104.16.133.229
104.16.132.229
A 13 2 300 20220104184526 20220102164526 34505 cloudflare.com. T+hHkJPzWpqYHlh9qkTz9/YUzdOdOlmj5WhDytndJTEqqd9v3KJDz+Qx L1iV2ZhgvSUnV/YhPC4ccIJitS2y8A==

Now commit your code and you are all set.

Restrict AWS Console Access Based On Source IP Address

Zero trust, or risk-based authentication, can be hard to achieve (You can read more about it here). Organizations must trust the identity being used and the location from where the user is authenticating. Many cloud-based services, like AWS, have functionality built in to help protect your account. This is a must in preventing account takeover (ATO) while protecting the confidentiality, integrity, and availability of your AWS systems.

AWS’ built-in tools help protect your account which is easy to use. It is an automated process to validate that your Root account has multifactor authentication turned on, the Root account does not have programmatic access, etc. One function that is missing from the GUI is protecting accounts from untrusted networks. To do this, go to IAM and click on Policies. Create a new policy and use the JSON editor to paste the following:

{
  "Version": "2012-10-17",
  "Statement": {
    "Effect": "Deny",
    "Action": "*",
    "Resource": "*",
    "Condition": {"NotIpAddress": 
    {"aws:SourceIp": [
      "Source IP Address"
    ]}}
  }
}

Replace “Source IP Address” with your source IP address(es) of your corporate network.

Once the policy has been created, attach the policy to either a user account or a group that users are apart of. Now when someone tries to log in, from outside the network, the person will receive an “Access Denied” while trying to access any AWS resources.

For the latest on this policy, or other AWS policies, please check out the GitHub Repo.

Powered by WordPress & Theme by Anders Norén