Skip to content

Instantly share code, notes, and snippets.

@oveaurs
Forked from joshgarnett/lets-encrypt-route53.rb
Last active June 24, 2019 14:34
Show Gist options
  • Save oveaurs/68c32500c0f5a2a4507f051adf439673 to your computer and use it in GitHub Desktop.
Save oveaurs/68c32500c0f5a2a4507f051adf439673 to your computer and use it in GitHub Desktop.
Ruby script to use as a hook for the letsencrypt.sh client
#!/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.rindex { |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)
resp = route53.test_dns_answer({
hosted_zone_id: hosted_zone.id,
record_name: "_acme-challenge.#{domain}.",
record_type: "TXT"
})
records = []
resp.record_data.each do |val|
records << {
value: val
}
end
records << {
value: "\"#{txt_challenge}\""
}
changes = []
changes << {
action: 'UPSERT',
resource_record_set: {
name: "_acme-challenge.#{domain}.",
type: 'TXT',
ttl: 60,
resource_records: records.uniq
}
}
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)
resp = route53.test_dns_answer({
hosted_zone_id: hosted_zone.id,
record_name: "_acme-challenge.#{domain}.",
record_type: "TXT"
})
records = []
method = "DELETE"
if resp.record_data.count > 1
method = "UPSERT"
resp.record_data.delete("\"#{txt_challenge}\"")
resp.record_data.each do |val|
records << {
value: val
}
end
else
records << {
value: "\"#{txt_challenge}\""
}
end
changes = []
changes << {
action: method,
resource_record_set: {
name: "_acme-challenge.#{domain}.",
type: 'TXT',
ttl: 60,
resource_records: records.uniq
}
}
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]
if hook_stage == 'deploy_challenge'
puts "stage: #{hook_stage} domain: #{domain} txt_challenge: #{txt_challenge}"
setup_dns(domain, txt_challenge)
elsif hook_stage == 'clean_challenge'
puts "stage: #{hook_stage} domain: #{domain} txt_challenge: #{txt_challenge}"
delete_dns(domain, txt_challenge)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment