Skip to content

add heritage txt record support #14

Merged
merged 2 commits into from
Feb 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,3 +33,7 @@
* 0.0.22 -- 2022-02-22
- code 0.0.13
- fix typo

* 0.0.23 -- 2022-02-22
- code 0.1.0
- add heritage TXT record support
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ No modules.
| <a name="input_component_tags"></a> [component\_tags](#input\_component\_tags) | Additional tags for Components (s3, kms, ddb) | `map(map(string))` | <pre>{<br> "ddb": {},<br> "kms": {},<br> "s3": {}<br>}</pre> | no |
| <a name="input_create"></a> [create](#input\_create) | Flag to indicate whether to create the resources or not (default: true) | `bool` | `true` | no |
| <a name="input_dynamodb_table_name"></a> [dynamodb\_table\_name](#input\_dynamodb\_table\_name) | Different DynamoDB table name to override default of var.name) | `string` | `null` | no |
| <a name="input_lambda_environment_variables"></a> [lambda\_environment\_variables](#input\_lambda\_environment\_variables) | Map of lambda environment variables and values | `map(string)` | <pre>{<br> "DNS_RR_TimeToLive": 60,<br> "DynamoDBName": null,<br> "SleepTime": 60,<br> "TagKeyCname": "boc:dns:cname",<br> "TagKeyHostName": "boc:dns:name",<br> "TagKeyZone": "boc:dns:zone"<br>}</pre> | no |
| <a name="input_lambda_environment_variables"></a> [lambda\_environment\_variables](#input\_lambda\_environment\_variables) | Map of lambda environment variables and values | `map(string)` | <pre>{<br> "DNS_RR_TimeToLive": 60,<br> "DynamoDBName": null,<br> "HeritageIdentifier": "dynr53",<br> "HeritageTXTRecordPrefix": "_txt",<br> "SleepTime": 60,<br> "TagKeyCname": "boc:dns:cname",<br> "TagKeyHostName": "boc:dns:name",<br> "TagKeyZone": "boc:dns:zone"<br>}</pre> | no |
| <a name="input_lambda_name"></a> [lambda\_name](#input\_lambda\_name) | Different Lambda name to override default of var.name) | `string` | `null` | no |
| <a name="input_name"></a> [name](#input\_name) | Name to use within all the created resources (default: inf-dynamic-route53) | `string` | `"inf-dynamic-route53"` | no |
| <a name="input_override_prefixes"></a> [override\_prefixes](#input\_override\_prefixes) | Override built-in prefixes by component. This should be used primarily for common infrastructure things | `map(string)` | `{}` | no |
Expand Down
180 changes: 162 additions & 18 deletions code/ddns-lambda.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@
LOGGER = logging.getLogger()
ACCOUNT = None
REGION = None
VERSION = '0.0.13'
VERSION = '0.1.0'

# Adjust the logging level [logging.INFO, logging.DEBUG, logging.WARNING, etc]
LOGGER.setLevel(logging.DEBUG)
Expand All @@ -86,6 +86,9 @@
DNS_RR_TTL = int(os.environ.get('DNS_RR_TimeToLive', '60'))
DNS_RR_TTL = 60 if DNS_RR_TTL == 0 else DNS_RR_TTL
TF_MODULE_VERSION = os.environ.get('tf_module_version', '(unknown)')
# for CNAMEs
TXT_RR_PREFIX = os.environ.get('HeritageTXTRecordPrefix', '_txt')
HERITAGE_TAG = os.environ.get('HeritageIdentifier', 'dynr53')

print('Loading function v{} tf_module_version {}: {}'.format(
VERSION, TF_MODULE_VERSION, datetime.datetime.now().time().isoformat()))
Expand Down Expand Up @@ -132,12 +135,25 @@ def get_dynamodb_client():
print("Unexpected error: %s" % err)


def get_caller_account_id():
"""
Get AWS Account ID from STS
:return str: AWS Account ID
"""
try:
return boto3.client('sts').get_caller_identity()['Account'])
except ClientError as err:
print("Unexpected error: %s" % err)


def lambda_handler(
event,
context,
dynamodb_client=get_dynamodb_client(),
compute=get_ec2_client(),
route53=get_route53_client()
dynamodb_client = get_dynamodb_client(),
compute = get_ec2_client(),
route53 = get_route53_client()


):
"""
Check to see whether a DynamoDB table already exists. If not, create it.
Expand All @@ -155,9 +171,9 @@ def lambda_handler(
LOGGER.info("event: %s", str(event) + lineno())
LOGGER.info("context: %s", str(context) + lineno())

caller_response = []
caller_response=[]
# Checking to make sure there is a dynamodb table named in the Env Variable
tables = list_tables(dynamodb_client)
tables=list_tables(dynamodb_client)

LOGGER.info("tables: %s", str(tables))
if DDBNAME in tables['TableNames']:
Expand All @@ -168,34 +184,36 @@ def lambda_handler(

# Set variables
# Get the state from the Event stream
state = event['detail']['state']
state=event['detail']['state']
LOGGER.debug("instance state: %s", str(state) + lineno())

# Get the instance id, region, and tag collection
instance_id = event['detail']['instance-id']
instance_id=event['detail']['instance-id']
LOGGER.debug("instance id: %s", str(instance_id) + lineno())
region = event['region']
region=event['region']
LOGGER.debug("region: %s", str(region) + lineno())
account_id=get_caller_account_id()
LOGGER.debug("account_id: %s", str(account_id) + lineno())

# Only doing something if the state is running
if state == 'running':
LOGGER.debug("sleeping for maximum {} seconds {}".format(SLEEPTIME, lineno()))

# wait increment and wait until maximum sleeptime
i = 1
i=1
while i < SLEEPTIME:
LOGGER.debug("waiting count: %s", str(i) + lineno())
time.sleep(1)
i += 1

try:
# Get instance information
instance = get_instances(compute, instance_id)
instance=get_instances(compute, instance_id)

t_private_ip = instance['Reservations'][0]['Instances'][0]['PrivateIpAddress']
t_private_dns_name = instance['Reservations'][0]['Instances'][0]['PrivateDnsName']
t_subnet_id = instance['Reservations'][0]['Instances'][0]['SubnetId']
t_vpc_id = instance['Reservations'][0]['Instances'][0]['VpcId']
t_private_ip=instance['Reservations'][0]['Instances'][0]['PrivateIpAddress']
t_private_dns_name=instance['Reservations'][0]['Instances'][0]['PrivateDnsName']
t_subnet_id=instance['Reservations'][0]['Instances'][0]['SubnetId']
t_vpc_id=instance['Reservations'][0]['Instances'][0]['VpcId']

# if key attributes are found, then break out of the loop
if all([t_private_ip, t_private_dns_name, t_subnet_id, t_vpc_id]):
Expand All @@ -211,9 +229,9 @@ def lambda_handler(
# Remove null values from the response. You cannot save a dict/JSON
# document in DynamoDB if it contains null values
LOGGER.debug("instance: %s", str(instance) + lineno())
instance = remove_empty_from_dict(instance)
instance_dump = json.dumps(instance, default=json_serial)
instance_attributes = json.loads(instance_dump)
instance=remove_empty_from_dict(instance)
instance_dump=json.dumps(instance, default = json_serial)
instance_attributes=json.loads(instance_dump)
LOGGER.debug("instance_attributes: %s", str(instance_attributes) + lineno())
LOGGER.debug("trying to put instance information in "
"dynamo table %s", str(instance_attributes) + lineno())
Expand Down Expand Up @@ -586,6 +604,17 @@ def lambda_handler(
LOGGER.debug("valid_dns_zones:"
" %s", str(valid_dns_zones) + lineno())

# create the TXT heritage record
heritage = initialize_heritage(HERITAGE_TAG,VERSION,
{
'instance_id': instance_id,
'account_id': account_id,
'region': region
} )
add_heritage_item_timestamp(heritage,'create_time')
heritage_value = format_heritage(heritage)
# txt=format_heritage(h)

# Create OR Delete the A / PTR Record
if state == 'running':
# create the records
Expand All @@ -608,6 +637,25 @@ def lambda_handler(
' with value: ' +
str(private_ip))

if len(heritage)>0:
LOGGER.debug("Creating heritage TXT resource records %s", lineno())
create_resource_record(
route53,
final_hosted_zone_id,
final_private_hostname,
final_hosted_zone_name,
'TXT',
heritage_value
)

caller_response.append('Created TXT record in zone id: ' +
str(final_hosted_zone_id) +
' for hosted zone ' +
str(final_private_hostname) + '.' +
str(final_hosted_zone_name) +
' with value: ' +
str(heritage_value))

if reverse_zone_associated:
create_resource_record(
route53,
Expand All @@ -625,6 +673,24 @@ def lambda_handler(
'in-addr.arpa with value: ' +
str(final_private_dns_name))

if len(heritage)>0:
create_resource_record(
route53,
reverse_lookup_zone_id,
reversed_ip_address,
'in-addr.arpa',
'TXT',
heritage_value
)

caller_response.append('Created TXT reverse record in zone id: ' +
str(reverse_lookup_zone_id) +
' for hosted zone ' +
str(reversed_ip_address) +
'in-addr.arpa with value: ' +
str(heritage_value))


except BaseException as err:
LOGGER.info("unexpected error. %s\n", str(err) + lineno())

Expand All @@ -650,6 +716,26 @@ def lambda_handler(
' with value: ' +
str(private_ip))

if len(heritage)>0:
# pause 1 before deleting to avoid API limit
time.sleep(1)
delete_resource_record(
route53,
final_hosted_zone_id,
final_private_hostname,
final_hosted_zone_name,
'TXT',
heritage_value
)

caller_response.append('Deleted TXT record in zone id: ' +
str(final_hosted_zone_id) +
' for hosted zone ' +
str(final_private_hostname) + '.' +
str(final_hosted_zone_name) +
' with value: ' +
str(heritage_value))

# pause 1 before deleting to avoid API limit
time.sleep(1)
delete_resource_record(
Expand All @@ -669,6 +755,26 @@ def lambda_handler(
' with value: ' +
str(final_private_dns_name))

if len(heritage)>0:
# pause 1 before deleting to avoid API limit
time.sleep(1)
delete_resource_record(
route53,
reverse_lookup_zone_id,
reversed_ip_address,
'in-addr.arpa',
'TXT',
heritage_value
)

caller_response.append('Deleted PTR record in zone id: ' +
str(reverse_lookup_zone_id) +
' for hosted zone ' +
str(reversed_ip_address) +
str(private_dns_name) +
' with value: ' +
str(heritage_value))

except BaseException as err:
LOGGER.debug("%s", str(err) + lineno())

Expand Down Expand Up @@ -708,6 +814,25 @@ def lambda_handler(
' with value: ' +
str(final_private_dns_name))

if len(heritage)>0:
create_resource_record(
route53,
cname_domain_suffix_id,
TXT_RR_PREFIX + '.' + cname_host_name,
cname_domain_suffix,
'TXT',
heritage_value
)

caller_response.append('Created TXT for CNAME record in zone id: ' +
str(cname_domain_suffix_id) +
' for hosted zone ' +
str(TXT_RR_PREFIX) + '.' +
str(cname_host_name) + '.' +
str(cname_domain_suffix) +
' with value: ' +
str(heritage_value))

except BaseException as err:
LOGGER.debug("%s", str(err) + lineno())
else:
Expand All @@ -733,6 +858,25 @@ def lambda_handler(
' with value: ' +
str(final_private_dns_name))

if len(heritage)>0:
delete_resource_record(
route53,
cname_domain_suffix_id,
TXT_RR_PREFIX + '.' + cname_host_name,
cname_domain_suffix,
'TXT',
heritage_value
)

caller_response.append('Deleted TXT for CNAME record in zone id: ' +
str(cname_domain_suffix_id) +
' for hosted zone ' +
str(TXT_RR_PREFIX) + '.' +
str(cname_host_name) + '.' +
str(cname_domain_suffix) +
' with value: ' +
str(heritage_value))

except BaseException as err:
LOGGER.debug("%s", str(err) + lineno())

Expand Down
Binary file modified code/ddns-lambda.zip
Binary file not shown.
14 changes: 8 additions & 6 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ variable "lambda_environment_variables" {
description = "Map of lambda environment variables and values"
type = map(string)
default = {
SleepTime = 60
DynamoDBName = null
TagKeyCname = "boc:dns:cname"
TagKeyZone = "boc:dns:zone"
TagKeyHostName = "boc:dns:name"
DNS_RR_TimeToLive = 60
SleepTime = 60
DynamoDBName = null
TagKeyCname = "boc:dns:cname"
TagKeyZone = "boc:dns:zone"
TagKeyHostName = "boc:dns:name"
DNS_RR_TimeToLive = 60
HeritageTXTRecordPrefix = "_txt"
HeritageIdentifier = "dynr53"
}
}
2 changes: 1 addition & 1 deletion version.tf
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
locals {
_module_version = "0.0.22"
_module_version = "0.0.23"
}