-
-
Save joshgarnett/02920846fea35f738d3370fd991bb0e0 to your computer and use it in GitHub Desktop.
| #!/usr/bin/env ruby | |
| require 'aws-sdk' | |
| # | |
| # This script requires you to have the following environment variables set: | |
| # AWS_REGION="us-west-2" | |
| # AWS_ACCESS_KEY_ID="<YOUR_KEY>" | |
| # AWS_SECRET_ACCESS_KEY="<YOUR_SECRET_KEY>" | |
| # | |
| # Based on https://gist.github.com/asimihsan/d8d8f0f10bdc85fc6f8a | |
| # | |
| def find_hosted_zone(route53, domain) | |
| route53 = Aws::Route53::Client.new | |
| hosted_zones = route53.list_hosted_zones_by_name.hosted_zones | |
| index = hosted_zones.index { |zone| domain.end_with?(zone.name.chop) } | |
| if index.nil? | |
| puts 'Unable to find matching zone.' | |
| exit 1 | |
| end | |
| hosted_zones[index] | |
| end | |
| def wait_for_change(route53, change_id) | |
| status = '' | |
| until status == 'INSYNC' | |
| resp = route53.get_change(id: change_id) | |
| status = resp.change_info.status | |
| if status != 'INSYNC' | |
| puts 'Waiting for dns change to complete' | |
| sleep 5 | |
| end | |
| end | |
| end | |
| def setup_dns(domain, txt_challenge) | |
| route53 = Aws::Route53::Client.new | |
| hosted_zone = find_hosted_zone(route53, domain) | |
| changes = [] | |
| changes << { | |
| action: 'UPSERT', | |
| resource_record_set: { | |
| name: "_acme-challenge.#{domain}.", | |
| type: 'TXT', | |
| ttl: 60, | |
| resource_records: [ | |
| value: "\"#{txt_challenge}\"" | |
| ] | |
| } | |
| } | |
| resp = route53.change_resource_record_sets( | |
| hosted_zone_id: hosted_zone.id, | |
| change_batch: { | |
| changes: changes | |
| } | |
| ) | |
| wait_for_change(route53, resp.change_info.id) | |
| end | |
| def delete_dns(domain, txt_challenge) | |
| route53 = Aws::Route53::Client.new | |
| hosted_zone = find_hosted_zone(route53, domain) | |
| changes = [] | |
| changes << { | |
| action: 'DELETE', | |
| resource_record_set: { | |
| name: "_acme-challenge.#{domain}.", | |
| type: 'TXT', | |
| ttl: 60, | |
| resource_records: [ | |
| value: "\"#{txt_challenge}\"" | |
| ] | |
| } | |
| } | |
| resp = route53.change_resource_record_sets( | |
| hosted_zone_id: hosted_zone.id, | |
| change_batch: { | |
| changes: changes | |
| } | |
| ) | |
| wait_for_change(route53, resp.change_info.id) | |
| end | |
| if __FILE__ == $PROGRAM_NAME | |
| hook_stage = ARGV[0] | |
| domain = ARGV[1] | |
| txt_challenge = ARGV[3] | |
| puts "stage: #{hook_stage} domain: #{domain} txt_challenge: #{txt_challenge}" | |
| if hook_stage == 'deploy_challenge' | |
| setup_dns(domain, txt_challenge) | |
| elsif hook_stage == 'clean_challenge' | |
| delete_dns(domain, txt_challenge) | |
| end | |
| end |
I found that this script has problems when you have sub domain zones in AWS. Eg.
- example.com
- sub.example.com
index = hosted_zones.index { |zone| domain.end_with?(zone.name.chop) }
This will cause the script to create the challenge TXT record in the example.com zone but a DNS query will try to find it in the subdomain zone. To work around this I changed the comparison to the other way around. Instead of checking if the domain ends with the zone name I check if the zone name ends with the domain latter part:
index = hosted_zones.index { |zone| zone.name.chop.end_with?(domain.split(".",2)[1]) }
Something to consider!
@reinhard-brandstaedter what I did to fix the same issue:
index = hosted_zones.rindex { |zone| domain.end_with?(zone.name.chop) }
It will then use the "earliest match"
@cbergmann have a look at my fork: https://gist.github.com/oveaurs/68c32500c0f5a2a4507f051adf439673