Skip to main content

The Rhythmic Blog

Route 53 Resolvers: Simplifying DNS in Hybrid Environments with Terraform and RAM

February 18, 2019       Cris Daniluk       , ,         Comments  0

Check out Route 53 Resolvers, Revisited, with updates for Terraform and Resource Access Manager.

To minimal fanfare, AWS released Route 53 inbound/outbound resolvers at re:Invent 2018. That’s unfortunate because if you’re one of the [all of us] running a hybrid infrastructure or using centralized authentication of some kind (e.g., ActiveDirectory, FreeIPA) in the cloud, this is a game changer.

In the past when you had complex DNS requirements, the solutions of choice were to edit your hosts file everywhere (uggh) or set a custom DHCP Option Set for your VPC (slightly less uggh). Both have undesirable qualities and neither is particularly scalable, particularly across accounts and VPCs. It’s the sort of thing you forget is there while troubleshooting a complicated DNS issue.

Route 53 Resolvers give you two modes of operation–inbound and outbound, each useful for different use cases. Inbound resolvers allow you to resolve your private Route 53 zones from off-premise. Outbound resolvers allow you to forward requests to your name servers of choice for things like AD resolution.

These are common sense things that a managed DNS service that you have no choice but to use would offer. But, they weren’t easy for AWS to implement. So they get a pass.

Route 53 Inbound Resolvers

Inbound resolvers let you make your Route 53 private zones accessible to other AWS accounts and resources that live outside of AWS entirely, over either VPN or DirectConnect.

The following CloudFormation snippet creates an inbound resolver capable of resolving queries for any private zone in your account:

InboundEndpoint:
     Type: "AWS::Route53Resolver::ResolverEndpoint"
     Properties:
       Direction: 'inbound'
       IpAddresses:
         - SubnetId: !Ref InboundSubnet1
         - SubnetId: !Ref InboundSubnet2
       Name: !Sub '$${AWS::StackName}-Inbound-Resolver'
       SecurityGroupIds:
         - !Ref InboundSecurityGroup

Note that at least two subnets (or IP addresses using the IP property) must be specified. Each subnet/IP requires an ENI, so using more than 2 will only get you a bigger bill. Also note the security group that the endpoint expects. You’ll want to allow the IP address ranges in your data centers, other accounts, etc that should be able to resolve within this account. Keep in mind that the account itself already has full access to resolve all private zones, so it only makes sense to specify CIDRs in your security group.

Route 53 Outbound Resolvers

Outbound resolvers allow you to conditionally forward domains to the name servers of your choice. Using outbound resolvers requires three separate resources:

  • An endpoint, similar to the inbound resolver with two or more IP addresses and a security group–this time restricting access to only your designated target resolvers. Be sure your network ACLs and routing tables are ready for this. Check your data center firewalls, too.
  • A rule, which specifies the domain you wish to conditionally forward to your nameservers.
  • An association, which links the rule to one or more VPCs.

The following example combines all 3:

  OutboundEndpoint:
    Type: "AWS::Route53Resolver::ResolverEndpoint"
    Properties:
      Direction: 'outbound'
      IpAddresses:
        - SubnetId: !Ref OutboundSubnet1
        - SubnetId: !Ref OutboundSubnet2
      Name: !Sub '$${AWS::StackName}-Outbound-Resolver'
      SecurityGroupIds:
        - !Ref OutboundSecurityGroup

  OutboundEndpointCustomDomainResolverRule:
    Type: "AWS::Route53Resolver::ResolverRule"
    Properties:
      DomainName: 'ad.domain.com'
      Name: !Sub '$${AWS::StackName}-Resolver-ad-domain-com'
      ResolverEndpointId: !Ref OutboundEndpoint
      RuleType: 'FORWARD'
      TargetIps:
        - Ip: LocalResolverIP
          Port: 53

  OutboundEndpointCustomDomainResolverRuleAssoc:
    Type: "AWS::Route53Resolver::ResolverRuleAssociation"
    Properties:
      ResolverRuleId: !Ref OutboundEndpointCustomDomainResolverRule
      VPCId: !Ref VpcId

ENIs, Oh My

Each endpoint IP you specify requires an ENI. In Route 53, they’re billed at $.125/hr, or $3/day. So, using both inbound and outbound across 2 subnets will set you back $12/day, or $360/month. That’s steep. The good news is that you can share your endpoints across many accounts using Resource Access Manager–something we’ll cover in a future post. Suffice to say, $360/month can get you by for many accounts, but it’s also the minimum you can get by with for one account.

Terraform On The Way

Terraform has an open PR to add this functionality. For now, you can create your security groups in Terraform and incorporate in a CloudFormation template for your inbound/outbound resolvers. This will translate easily to a Terraform native solution once the PR merges, provided you don’t mind a brief outage while you tear down your stack and recreate in Terraform.

Leave a Reply