Created
January 30, 2021 19:59
-
-
Save jerm/dbd2ea7f28beb73bf4723aa7700802a9 to your computer and use it in GitHub Desktop.
Sync Tailscale hosts to route53
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python | |
# | |
# Sync your tailscale hosts to a route53 hosted zone. | |
# | |
import json | |
import platform | |
import subprocess | |
import boto3 | |
import click | |
ZONE_ID = "" | |
DOMAIN = "" | |
if platform.system() == "Darwin": | |
TSCMD = "/Applications/Tailscale.app/Contents/MacOS/Tailscale" | |
else: | |
TSCMD = "tailscale" | |
def get_ts_hosts(): | |
"""Get hosts list from taillscale. Slight gotcha that this is | |
divided into "Self" and "Peers", so we grab both.""" | |
tshosts = {} | |
tsjson = json.loads( | |
subprocess.run( | |
["{} status --json".format(TSCMD)], shell=True, capture_output=True | |
).stdout | |
) | |
for key, value in tsjson.items(): | |
if key == "Self": | |
tshosts[value.get("HostName").lower()] = value.get("TailAddr") | |
elif key == "Peer": | |
for _, peerdict in value.items(): | |
tshosts[peerdict.get("HostName").lower()] = peerdict.get("TailAddr") | |
return tshosts | |
def get_r53_hosts(zone_id): | |
""" in which we get a list of A records in our zone """ | |
client = boto3.client("route53") | |
rrsets = client.list_resource_record_sets(HostedZoneId=zone_id) | |
r53_records = {} | |
for rrset in rrsets["ResourceRecordSets"]: | |
if rrset["Type"] == "A": | |
r53_records[rrset["Name"]] = rrset["ResourceRecords"][0]["Value"] | |
return r53_records | |
@click.command() | |
@click.option("--domain", type=str, default=DOMAIN) | |
@click.option("--zone-id", type=str, default=ZONE_ID) | |
def main(domain, zone_id): | |
""" main logic """ | |
client = boto3.client("route53") | |
changes = [] | |
tshosts = get_ts_hosts() | |
r53_records = get_r53_hosts(zone_id) | |
for host, ip in tshosts.items(): | |
hostname = "{}.{}.".format(host, domain) | |
if hostname in r53_records: | |
if not ip == r53_records[hostname]: | |
print( | |
"{} exists, but ips don't match r53 {} vs ts {}".format( | |
hostname, r53_records[hostname], ip | |
) | |
) | |
changes.append( | |
{ | |
"Action": "UPSERT", | |
"ResourceRecordSet": { | |
"Name": hostname, | |
"Type": "A", | |
"TTL": 300, | |
"ResourceRecords": [ | |
{"Value": ip}, | |
], | |
}, | |
} | |
) | |
else: | |
print(hostname, "is correct") | |
else: | |
print("Need to add", hostname) | |
changes.append( | |
{ | |
"Action": "CREATE", | |
"ResourceRecordSet": { | |
"Name": hostname, | |
"Type": "A", | |
"TTL": 300, | |
"ResourceRecords": [ | |
{"Value": ip}, | |
], | |
}, | |
} | |
) | |
if changes: | |
_ = client.change_resource_record_sets( | |
HostedZoneId=zone_id, ChangeBatch={"Comment": "string", "Changes": changes} | |
) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment