Skip to content

Commit

Permalink
upgrade docs
Browse files Browse the repository at this point in the history
  • Loading branch information
badra001 committed Apr 29, 2023
1 parent 1c1f422 commit a2adb62
Show file tree
Hide file tree
Showing 3 changed files with 240 additions and 114 deletions.
73 changes: 17 additions & 56 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,52 +1,9 @@
<!-- BEGIN_TF_DOCS -->
# About :: aws-dynamic-route53

This module sets up all the things one needs to enable the dynamic creation and removal of Route53 records. It requires
the VPC to have the following:

* DHCP option for DNS enabled
* DHCP option for DNS domain name
* Route53 zone for the DNS domain name in the DHCP option
* Route53 zone for all of the PTR subnets for the VPC (x.y.z.in-addr.arpa)

This module creates these resources:

* DyanmoDB Table for tracking the instances
* CloudWatch Log
* Lambda Function
* IAM role and policy for Lambda
* SNS topic (if `enable_sns=true`)

# Deployment

This should be deployed per account in each region where the automated Route53 is desired. DNS entries are created on EC2 instance
startup (when running) and removed on shutdown or termination. The instance IDs are tracked in the DynamoDB Table. Here's how
DNS entries are handled:

1. If the `Name` tags exists, it will take the host part of the name (up to the first dot) and create an A and PTR records for the
hostname with the DHCP options domain.
1. If there is no `Name` tag, it will use the _IP Address Format_ (ip-x-x-x-x where the private IP is x.x.x.) with the domain from the DHCP options.
1. If the tag `boc:dns:name` exists on the EC2 instance, it will use this name to enter into DNS. This assumes the domain part of the name exists and is
associated to the VPC. Using this tag, you can create a completely different name from the `Name` tag.
1. If the tag `boc:dns:zone` exits on the EC2 instance, it will take the hostname part of the `Name` tag, and add the zone, and use this name
in DNS. This assumes the domain part of the name exists and is associated to the VPC. If there is no `Name` tag, it will use the _IP Address Format_ (ip-x-x-x-x where the private IP is x.x.x.).
Using this tag, you can create the host in a completely different zone from that of the DHCP options.
1. If the tag `boc:dns:cname` exists, that name will be entered in DNS in the zone indicated by the tag as a CNAME to the main name (as determined above),
assuming the domain part of the name exists and is associated to the VPC.

We also add what is called a _heritage_ TXT record, associated with the instance. It looks like this:

```script
"heritage=dynr53,dynr53/version=0.2.1,dynr53/account_id=252999262699,dynr53/region=us-gov-west-1,dynr53/instance_id=i-0e836a68e01f8b1c3,dynr53/create_time=1648143761"
```

This is createed as a TXT record on

* the hostname, however it is determined from the above rules
* on the associated PTR resource record (RR), that is, `x.x.x.x.in-addr.arpa IN TXT ...`
* and with a default prefix of \_txt with the CNAME if using the `boc:dns:cname` tag, because, you cannot have more than one RR when using a CNAME
This module sets up all the things one needs to enable the dynamic creation and removal of Route53 records.

If SNS is enabled, any errors will cause a message to be published to the SNS topic.
We have moved the details of using the flags on instances into [USAGE](USAGE.md).

# Usage

Expand All @@ -68,22 +25,26 @@ module "dynamic-route53" {
The folowing defualts are applied to the Lambda function. There is ordinarily no need to change
these.

```hcl
```hcl
{
DebugLevel = "INFO"
SleepTime = 60
DynamoDBName = null
TagKeyCname = "boc:dns:cname"
TagKeyZone = "boc:dns:zone"
TagKeyHostName = "boc:dns:name"
DebugLogLevel = "INFO"
DNS_RR_TimeToLive = 60
DynamoDBName = null
HeritageIdentifier = "dynr53"
HeritageTXTRecordPrefix = "_txt"
MaxApiRetry = 10
SnsTopicArn = ""
SleepTime = 60
SnsEnable = false
HeritageTXTRecordPrefix = "_txt"
HeritageIdentifier = "dynr53"
SnsTopicArn = ""
RemoteRoleArnFormat = "arn:%s:iam::%s:role/r-inf-dynamic-route53-actions"
EMRTagPrefix = "aws"
TagKeyCname = "boc:dns:cname"
TagKeyHostName = "boc:dns:name"
TagKeyZone = "boc:dns:zone"
TagKeyPtrname = "boc:dns:ptrname"
TagKeyFlags = "boc:dns:flags"
}
```
```

## Requirements

Expand Down
204 changes: 204 additions & 0 deletions USAGE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,204 @@
# About :: aws-dynamic-route53

This describes the new capabilities of the 2.0 version of the Dyanmic Route53 module.
It sets up all the things one needs to enable the dynamic creation and removal of Route53 records. It requires the VPC to have the following:

* DHCP option for DNS enabled
* DHCP option for DNS domain name
* Route53 zone for the DNS domain name in the DHCP option
* Route53 zone for all of the PTR subnets for the VPC (x.y.z.in-addr.arpa)
* Route53 zone assocations for the VPC to all associated zones

This module creates these resources:

* DyanmoDB Table for tracking the instances
* CloudWatch Log
* Lambda Function
* IAM role and policy for Lambda
* SNS topic (if `enable_sns=true`)

# Deployment

This should be deployed per account in each region where the automated Route53 is desired.

# Usage

DNS entries are created **ONLY** on
EC2 instance start (when running) and removed on stop or terminate. If you change the tags which affect the naming, you must _stop_ and _start_
the instance. Do not reboot, because that is not an EC2 action. You can stop and start from the CLI like this (sleep 60 is to give the instance
time to be properly shut down).

```script
aws --profile PROFILE ec2 stop-instances --instance-ids i-xxxxxxxx
sleep 60
aws --profile PROFILE ec2 start-instances --instance-ids i-xxxxxxxx
```
The instance IDs and DNS records created are tracked in a DynamoDB Table.

## Tags

Here are the tags which affect the DNS name:

### `Name`

This should be a fully qualified valid DNS name. The domain (components after the first dot, typically) must exist and must be associated
the VPC where the instance resides.

Do not use invalid DNS characters (no underscores, no spaces, no special other than dash). Legal characters: a-z 0-9 dash (-).

It is possible, but not recommended, where this can a short non-FQDN name, that is, just a hostname. In this case, the DHCP options domain will be used,
if it exists, or a different zone will be used based on the `boc:dns:zone` flag.

If the `Name` tag is missing, the IP address wil be used to construct the name in the form of `ip-X-X-X-X`.

Examples:
* Name = cio-001-web.dev.csp1.census.gov
yields DNS of: cio-001-web.dev.csp1.census.gov
* Name = myhost
yields DNS of: myhost.{dhcp_domain_name} (if such a zone exists, or what was specified in `boc:dns:zone`)
* Name =
yields DNS of: ip-X-X-X-X.{dhcp_domain_name}

### `boc:dns:name`

It is possible to use a completely different name in DNS from the Name tag, if desired. Like the `Name` tag, this should be an FQDN, but a short
domain-less name will use the default DHCP options domain or the `boc:dns:zone` tag.

Examples:
* boc:dns:name = myhost.qa.csp1.census.gov
yields DNS of: myhost.qa.csp1.census.gov,
* boc:dns:name = somotherhost
yields DNS of: someotherhost.{dhcp_domain_name} (if such a zone exists, or what was specified in `boc:dns:zone`)

### `boc:dns:zone`

If you want to use a zone other than what is defined in the DHCP options, or that zone in the DHCP options is not availble (as in the case
of `compute.csp1.census.gov`, which exist in BIND on a cloud DNS server), you can use the `boc:dns:zone` option. Setting this value
will cause the domains for foward entries (A), and reverse (PTR) to use the short hostname and the provided domain from `boc:dns:zone`.

Examples:
* boc:dns:zone = uat.csp1.census.gov
yields DNS of: {hostname}.uat.csp1.census.gov, using the hostname part from the `Name` tag following the rules above for the A and PTR recors

### `boc:dns:cname`

If you need to set a second name for an instance, you can use an Alias/CNAME. This is another entry created in Route53, which points at the main
host FQDN. A CNAME cannot point to a CNAME. This may be an FQDN or a shortname. If an FQDN and the zone exist in Route53, it will add it.
If a shortname, it will append the default DHCP options domain or the value from the `boc:dns:zone` tag.

Examples:
* Name = cio-014-app.stage.csp1.census.gov
* boc:dns:cname = myothername.stage.csp1.census.gov
yields DNS of: myothername.stage.csp1.census.gov pointing to cio-014-app.stage.csp1.census.gov

### `boc:dns:ptrname`

Sometimes, we need to set a different name from the `Name` tag on the PTR record. This is the record that lets you lookup an IP and get a name, by
taking the IP and reversing the dotted quad and adding `.in-addr.arpa`. An IP of 10.193.14.78 would have a PTR name of
78.14.193.10.in-addr.arpa. Normally, you set the value of this to the same name as the registered hostname, `Name` or `boc:dns:name`, as many security
checks are performed to make sure the host resolves _"forward and backward"_.

However, in the case of a Windows host, we cannot use the `Name` or `boc:dns:name` tag, because the Active Directory (AD) domain name is not capable
of running on Route53. Windows adds hosts dynamically on registration to the domain to the Forest or child AD domain. The windows server cannot
make the corresponding PTR entry, because Route53 does not speak the DDNS protocol.

We can solve this using the `boc:dns:ptrname` tag and using one of the _flag_ settings. For a Windows host, you will want to set
the `boc:dns:ptrname` to the Windows FQDN. For example, `cio003web.ead.census.gov`. The domain of this host is not checked to be present in the
VPC, because we are not writing to that omain.

YOu will also want to use the `boc:dns:flags=noforward` with this option, as registering a differname in some zone defined in Route53 causes
confusion. As AD will update the forward name, you do not need Route53 to set the forward name.

### `boc:dns:flags`

We do need to control the settings a bit more than we do with the tags above. Fortunately, we have some flags available. This tag `boc:dns:flags` may
be set to one or more (as a CSV list, no spaces) of the following values:

* noforward
This does **NOT** create the A (and AAAA, when IPv6 is available) and associated heritage record (see [below](#additional-heritage-txt-records)) in
the zone (DHCP options or from `boc:dns:zone`) or the name from `boc:dns:name`. This is most often used with the `boc:dns:ptrname` and Windows hosts.

* noptrname
This does **NOT** create the PTR and associated heritage record (see [below](#additional-heritage-txt-records)) in the
PTR zone (x.x.x.in-addr.arpa). We are not sure why you would do this.

* nocname
This does **NOT** create the CNAME, if defined with `boc:dns:cname` and associated heritage record (see [below](#additional-heritage-txt-records)) in the
the zone (DHCP options or from `boc:dns:zone`) or the name from `boc:dns:name`. It is easier to simply not set the tag `boc:dns:cname`, but there could be
a reason somewhere out there.

* noheritage
This will not create any of the heritage records, which are TXT records in the same zone as their respective record. You can look this name up with
a `txt` query, like:

```script
# A record
host -t txt myhost.dev.csp1.census.gov
# PTR record
host -t txt 14.107.193.10.in-addr.arpa
# CNAME record
host -t txt _txt.myalias.services.csp1.census.gov
```

Note that for aliases (CNAMES), we can not add a TXT record because a CNAME references the defined name for EVERY record type. Looking up the TXT
on a CNAME is the same as looking up the TXT on the pointed-to name.

## Additional Heritage TXT records

We also add what is called a _heritage_ TXT record, associated with the instance. It looks like this:

```script
"heritage=dynr53,dynr53/version=2.0.1,dynr53/account_id=252999262699,dynr53/region=us-gov-west-1,dynr53/instance_id=i-0e836a68e01f8b1c3,dynr53/create_time=1648143761"
```

This is createed as a TXT record on

* the hostname, however it is determined from the above rules
* on the associated PTR resource record (RR), that is, `x.x.x.x.in-addr.arpa IN TXT ...`
* and with a default prefix of `_txt` with the CNAME if using the `boc:dns:cname` tag, because, you cannot have more than one RR when using a CNAME

## Additional Features

This release also includes _EMR detection_. What that means if an instance is created as part of an EMR cluster, a special tag will be added
by EMR to indicate this. That tag is

`aws:elasticmapreduce:job-flow-id = j-xxxxxxxx`

where the vallue of this is the EMR cluster id.

A second tag is added if the instance happens to be the master node:

`aws:elasticmapreduce:group-instance-role = MASTER`

This is ONLY on the master node.

EMR does not allow you to tag individual instances. You can create a tag for EMR, but it gets added to every instance in the cluster. Since we can detect
an EMR clsuter, and specifically the master node, we can couple that with the `boc:dns:cname` tag to create an alias to the master node, to simplify use.

It is **imperitive** that the cluster master alias you create be unique, as if some other name already exists in the zone, the creation will fail.

Here is how you can use this capability:

1. create a tag `boc:dns:cname=mynewcluster.master`
- This will create a CNAME mynewclsuter.master.{dhpc_domain_name} to the FQDN of the master instance
1. launch the cluster
- non-master noes will have only the _job-flow-id_ tag
- the master node will have the _MASTER_ role
1. if the instance is an EMR cluster, and the instance is labelled as MASTER, and the CNAME tag is defined, the CNAME will be set. It may fail
if it already exist.


# Notes

To register a name in a zone, the VPC where the instance runs must be associated to the zone, whever the zone is created, whether it is the
same account as the instance, or some other account.

If the zone is created in another account, the Lambda will execute an assume role `r-inf-dynamic-route53-actions` to gain the permissions to create,
modify and delete the records in the zone. This, and a Terraform-supporting role, is created in the `aws-vpc-setup` submoduiels:

* terraform-modules/aws-vpc-setup/route53-zone-association/lambda-role
* terraform-modules/aws-vpc-setup/route53-zone-association/terraform-role

and are instantiated with a `dynroute53-role.tf` and `terraform-role.tf` (to be wrapped up into an INF script soon).

These must be created in the target account if the zone is in a different account.
77 changes: 19 additions & 58 deletions main.tf
Original file line number Diff line number Diff line change
@@ -1,53 +1,10 @@
/*
* # About :: aws-dynamic-route53
*
* This module sets up all the things one needs to enable the dynamic creation and removal of Route53 records.
*
* This module sets up all the things one needs to enable the dynamic creation and removal of Route53 records. It requires
* the VPC to have the following:
*
* * DHCP option for DNS enabled
* * DHCP option for DNS domain name
* * Route53 zone for the DNS domain name in the DHCP option
* * Route53 zone for all of the PTR subnets for the VPC (x.y.z.in-addr.arpa)
*
* This module creates these resources:
*
* * DyanmoDB Table for tracking the instances
* * CloudWatch Log
* * Lambda Function
* * IAM role and policy for Lambda
* * SNS topic (if `enable_sns=true`)
*
* # Deployment
*
* This should be deployed per account in each region where the automated Route53 is desired. DNS entries are created on EC2 instance
* startup (when running) and removed on shutdown or termination. The instance IDs are tracked in the DynamoDB Table. Here's how
* DNS entries are handled:
*
* 1. If the `Name` tags exists, it will take the host part of the name (up to the first dot) and create an A and PTR records for the
* hostname with the DHCP options domain.
* 1. If there is no `Name` tag, it will use the _IP Address Format_ (ip-x-x-x-x where the private IP is x.x.x.) with the domain from the DHCP options.
* 1. If the tag `boc:dns:name` exists on the EC2 instance, it will use this name to enter into DNS. This assumes the domain part of the name exists and is
* associated to the VPC. Using this tag, you can create a completely different name from the `Name` tag.
* 1. If the tag `boc:dns:zone` exits on the EC2 instance, it will take the hostname part of the `Name` tag, and add the zone, and use this name
* in DNS. This assumes the domain part of the name exists and is associated to the VPC. If there is no `Name` tag, it will use the _IP Address Format_ (ip-x-x-x-x where the private IP is x.x.x.).
* Using this tag, you can create the host in a completely different zone from that of the DHCP options.
* 1. If the tag `boc:dns:cname` exists, that name will be entered in DNS in the zone indicated by the tag as a CNAME to the main name (as determined above),
* assuming the domain part of the name exists and is associated to the VPC.
*
* We also add what is called a _heritage_ TXT record, associated with the instance. It looks like this:
*
* ```script
* "heritage=dynr53,dynr53/version=0.2.1,dynr53/account_id=252999262699,dynr53/region=us-gov-west-1,dynr53/instance_id=i-0e836a68e01f8b1c3,dynr53/create_time=1648143761"
* ```
*
* This is createed as a TXT record on
*
* * the hostname, however it is determined from the above rules
* * on the associated PTR resource record (RR), that is, `x.x.x.x.in-addr.arpa IN TXT ...`
* * and with a default prefix of _txt with the CNAME if using the `boc:dns:cname` tag, because, you cannot have more than one RR when using a CNAME
*
* If SNS is enabled, any errors will cause a message to be published to the SNS topic.
*
* We have moved the details of using the flags on instances into [USAGE](USAGE.md).
*
* # Usage
*
* This is a simmple call. With no arguments, it will setup everything besides the SNS topic.
Expand All @@ -68,20 +25,24 @@
* The folowing defualts are applied to the Lambda function. There is ordinarily no need to change
* these.
*
* ```hcl
* ```hcl
* {
* DebugLevel = "INFO"
* SleepTime = 60
* DynamoDBName = null
* TagKeyCname = "boc:dns:cname"
* TagKeyZone = "boc:dns:zone"
* TagKeyHostName = "boc:dns:name"
* DebugLogLevel = "INFO"
* DNS_RR_TimeToLive = 60
* DynamoDBName = null
* HeritageIdentifier = "dynr53"
* HeritageTXTRecordPrefix = "_txt"
* MaxApiRetry = 10
* SnsTopicArn = ""
* SleepTime = 60
* SnsEnable = false
* HeritageTXTRecordPrefix = "_txt"
* HeritageIdentifier = "dynr53"
* SnsTopicArn = ""
* RemoteRoleArnFormat = "arn:%s:iam::%s:role/r-inf-dynamic-route53-actions"
* EMRTagPrefix = "aws"
* TagKeyCname = "boc:dns:cname"
* TagKeyHostName = "boc:dns:name"
* TagKeyZone = "boc:dns:zone"
* TagKeyPtrname = "boc:dns:ptrname"
* TagKeyFlags = "boc:dns:flags"
* }
* ```
* ```
*/

0 comments on commit a2adb62

Please sign in to comment.