diff --git a/CHANGELOG.md b/CHANGELOG.md index 1d4585e..5987854 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -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 diff --git a/README.md b/README.md index 8c069fc..1e3c14d 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ No modules. | [component\_tags](#input\_component\_tags) | Additional tags for Components (s3, kms, ddb) | `map(map(string))` |
{
"ddb": {},
"kms": {},
"s3": {}
}
| no | | [create](#input\_create) | Flag to indicate whether to create the resources or not (default: true) | `bool` | `true` | no | | [dynamodb\_table\_name](#input\_dynamodb\_table\_name) | Different DynamoDB table name to override default of var.name) | `string` | `null` | no | -| [lambda\_environment\_variables](#input\_lambda\_environment\_variables) | Map of lambda environment variables and values | `map(string)` |
{
"DNS_RR_TimeToLive": 60,
"DynamoDBName": null,
"SleepTime": 60,
"TagKeyCname": "boc:dns:cname",
"TagKeyHostName": "boc:dns:name",
"TagKeyZone": "boc:dns:zone"
}
| no | +| [lambda\_environment\_variables](#input\_lambda\_environment\_variables) | Map of lambda environment variables and values | `map(string)` |
{
"DNS_RR_TimeToLive": 60,
"DynamoDBName": null,
"HeritageIdentifier": "dynr53",
"HeritageTXTRecordPrefix": "_txt",
"SleepTime": 60,
"TagKeyCname": "boc:dns:cname",
"TagKeyHostName": "boc:dns:name",
"TagKeyZone": "boc:dns:zone"
}
| no | | [lambda\_name](#input\_lambda\_name) | Different Lambda name to override default of var.name) | `string` | `null` | no | | [name](#input\_name) | Name to use within all the created resources (default: inf-dynamic-route53) | `string` | `"inf-dynamic-route53"` | no | | [override\_prefixes](#input\_override\_prefixes) | Override built-in prefixes by component. This should be used primarily for common infrastructure things | `map(string)` | `{}` | no | diff --git a/code/ddns-lambda.py b/code/ddns-lambda.py index 309f630..76c7559 100755 --- a/code/ddns-lambda.py +++ b/code/ddns-lambda.py @@ -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) @@ -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())) @@ -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. @@ -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']: @@ -168,21 +184,23 @@ 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) @@ -190,12 +208,12 @@ def lambda_handler( 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]): @@ -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()) @@ -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 @@ -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, @@ -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()) @@ -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( @@ -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()) @@ -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: @@ -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()) diff --git a/code/ddns-lambda.zip b/code/ddns-lambda.zip index ba3ca7c..157de09 100644 Binary files a/code/ddns-lambda.zip and b/code/ddns-lambda.zip differ diff --git a/variables.tf b/variables.tf index afb4945..060eafb 100644 --- a/variables.tf +++ b/variables.tf @@ -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" } } diff --git a/version.tf b/version.tf index ac63989..4c5fed3 100644 --- a/version.tf +++ b/version.tf @@ -1,3 +1,3 @@ locals { - _module_version = "0.0.22" + _module_version = "0.0.23" }