acmesmith-google-cloud-dns 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: a46d6d5a3f556dcb149e5708306c1b111a9c5006
4
+ data.tar.gz: 4eb78bbe978413c07707404445ddf1fe9faabb11
5
+ SHA512:
6
+ metadata.gz: baf9ce852a5e74ba05547593d76dfff9183f14104772ece7ed691701fcbaa79f57f7b9504a5f28e350523683e5eb2e367fc90cde0b5f041331276e853a531132
7
+ data.tar.gz: 30e8fa2c3bd938b1fe4da69ae9241963eeae8fcf87801e0d68ec4522a55d34c3f820c644dbbe0c5d350ee8f7ce6bc0d0d7c0436b741ec72361bab67d180be436
@@ -0,0 +1,12 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ /vendor/bundle
11
+ /acmesmith.yml
12
+ /storage
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
@@ -0,0 +1,4 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.2.4
4
+ before_install: gem install bundler -v 1.10.6
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in acmesmith-cloud-dns.gemspec
4
+ gemspec
@@ -0,0 +1,41 @@
1
+ # acmesmith-google-cloud-dns
2
+
3
+ This gem is a plugin for [Acmesmith](https://github.com/sorah/acmesmith) and implements an automated `dns-01` challenge responder using Google Cloud DNS.
4
+
5
+ With this plugin and Acmesmith, you can automate to authorize your domain hosted on [Google Cloud DNS](https://cloud.google.com/dns/) and request TLS certificates for the domains against [Let's Encrypt](https://letsencrypt.org/) and other CAs supporting the ACME protocol.
6
+
7
+ ## Usage
8
+ ### Prerequisites
9
+ - You need to have control of your domain name to change its authoritative nameservers.
10
+ - You need to have service account of Google Cloud Platform to operate Google Cloud DNS via API.
11
+
12
+ ### Preparation
13
+ - Ask your DNSaaS provider to host a zone for your domain name. They will tell you the DNS content servers that host the zone.
14
+ - Ask your domain registrar to set the authoritative nameservers of your domain to the content servers provided by the DNSaaS.
15
+
16
+ ### Installation
17
+ Install `acmesith-google-cloud-dns` gem along with `acmesmith`. You can just do `gem install acmesith-google-cloud-dns` or use Bundler if you want.
18
+
19
+ ### Configuration
20
+ Use `google-cloud-dns` challenge responder in your `acmesmith.yml`. General instructions about `acmesmith.yml` is available in the manual of Acmesmith.
21
+
22
+ Write your `tenant_name`, `username`, `password` and `auth_url` in `acmesmith.yml`, or if you don't want to write them down into the file, export these values as the corresponding environment variables `OS_TENANT_NAME`, `OS_USERNAME`, `OS_PASSWORD` and `OS_AUTH_URL`.
23
+
24
+ ```yaml
25
+ endpoint: https://acme-v01.api.letsencrypt.org/
26
+
27
+ storage:
28
+ type: filesystem
29
+ path: /path/to/key/storage
30
+
31
+ challenge_responders:
32
+ - google_cloud_dns:
33
+ project_id: my-project-id # GCP Project ID. Be careful it's different from Project Name.
34
+ compute_engine_service_account: true # (pick-one): You can use GCE VM instance scope
35
+ private_key_json_file: /path/to/credential.json # (pick-one) Only JSON key file is supported
36
+ ttl: 5 # (optional) long TTL hinders re-authorization, but a DNSaaS provider may restrict short TTL
37
+ ```
38
+
39
+ ## License
40
+
41
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
@@ -0,0 +1,28 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'acmesmith-google-cloud-dns/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "acmesmith-google-cloud-dns"
8
+ spec.version = AcmesmithGoogleCloudDns::VERSION
9
+ spec.authors = ["Chikanaga Tomoyuki"]
10
+ spec.email = ["nagachika@ruby-lang.org"]
11
+
12
+ spec.summary = %q{acmesmith plugin implementing dns-01 using Google Cloud DNS}
13
+ spec.description = %q{This gem is a plugin for acmesmith and implements an automated dns-01 challenge responder using Google Cloud DNS}
14
+ spec.homepage = "https://github.com/nagachika/acmetmith-google-cloud-dns"
15
+ spec.license = "MIT"
16
+
17
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
18
+ spec.bindir = "exe"
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ["lib"]
21
+
22
+ spec.add_dependency "acmesmith"
23
+ spec.add_dependency "google-api-client", "~> 0.9.1"
24
+
25
+ spec.add_development_dependency "bundler", "~> 1.10"
26
+ spec.add_development_dependency "rake", "~> 10.0"
27
+ spec.add_development_dependency 'rspec', '~> 3.0'
28
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "acmesmith/challenge_responders/google_cloud_dns"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,3 @@
1
+ module AcmesmithGoogleCloudDns
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,122 @@
1
+ require "acmesmith/challenge_responders/base"
2
+
3
+ require "json"
4
+ require "google/apis/dns_v1"
5
+ require "resolv"
6
+
7
+ module Acmesmith
8
+ module ChallengeResponders
9
+ class GoogleCloudDns < Base
10
+ def support?(type)
11
+ type == 'dns-01'
12
+ end
13
+
14
+ def initialize(config)
15
+ @config = config
16
+ @scope = "https://www.googleapis.com/auth/ndev.clouddns.readwrite"
17
+ @api = Google::Apis::DnsV1::DnsService.new
18
+ if @config[:compute_engine_service_account]
19
+ @api.authorization = Google::Auth.get_application_default(@scope)
20
+ elsif @config[:private_key_json_file]
21
+ credential = load_json_key(@config[:private_key_json_file])
22
+ @api.authorization = Signet::OAuth2::Client.new(
23
+ token_credential_uri: "https://accounts.google.com/o/oauth2/token",
24
+ audience: "https://accounts.google.com/o/oauth2/token",
25
+ scope: @scope,
26
+ issuer: credential[:email_address],
27
+ signing_key: credential[:private_key])
28
+ else
29
+ raise "You need to specify authentication options (compute_engine_service_account or private_key_json_file)"
30
+ end
31
+ @api.authorization.fetch_access_token!
32
+ @project_id = @config[:project_id]
33
+ end
34
+
35
+ def respond(domain, challenge)
36
+ puts "=> Responding challenge dns-01 for #{domain} in #{self.class.name}"
37
+
38
+ domain = canonicalize(domain)
39
+ zone_name = find_managed_zone(domain).name
40
+
41
+ puts " * create_change: #{challenge.record_type} #{[challenge.record_name, domain].join('.').inspect}, #{challenge.record_content.inspect}"
42
+ change = Google::Apis::DnsV1::Change.new
43
+ change.additions = [
44
+ resource_record_set(domain, challenge)
45
+ ]
46
+ resp = @api.create_change(@project_id, zone_name, change)
47
+
48
+ change_id = resp.id
49
+ puts " * requested change: #{change_id}"
50
+
51
+ while resp.status != 'done'
52
+ puts " * change #{change_id.inspect} is still #{resp.status.inspect}"
53
+ sleep 5
54
+ resp = @api.get_change(@project_id, zone_name, change_id)
55
+ end
56
+
57
+ puts " * synced!"
58
+
59
+ puts "=> Checking DNS resource record"
60
+ nameservers = @api.get_managed_zone(@project_id, zone_name).name_servers
61
+ puts " * nameservers: #{nameservers.inspect}"
62
+ nameservers.each do |ns|
63
+ Resolv::DNS.open(:nameserver => Resolv.getaddresses(ns)) do |dns|
64
+ dns.timeouts = 5
65
+ begin
66
+ ret = dns.getresource([challenge.record_name, domain].join('.'), Resolv::DNS::Resource::IN::TXT)
67
+ rescue Resolv::ResolvError => e
68
+ puts " * [#{ns}] failed: #{e.to_s}"
69
+ sleep 5
70
+ retry
71
+ end
72
+ puts " * [#{ns}] success: ttl=#{ret.ttl.inspect}, data=#{ret.data.inspect}"
73
+ sleep 1
74
+ end
75
+ end
76
+ end
77
+
78
+ def cleanup(domain, challenge)
79
+ domain = canonicalize(domain)
80
+ zone_name = find_managed_zone(domain).name
81
+ change = Google::Apis::DnsV1::Change.new
82
+ change.deletions = [
83
+ resource_record_set(domain, challenge)
84
+ ]
85
+ @api.create_change(@project_id, zone_name, change)
86
+ end
87
+
88
+ private
89
+
90
+ def load_json_key(filepath)
91
+ obj = JSON.parse(File.read(filepath))
92
+ {
93
+ email_address: obj["client_email"],
94
+ private_key: OpenSSL::PKey.read(obj["private_key"]),
95
+ }
96
+ end
97
+
98
+ def canonicalize(domain)
99
+ "#{domain}.".gsub(/\.{2,}/, '.')
100
+ end
101
+
102
+ def find_managed_zone(domain)
103
+ managed_zone = @api.list_managed_zones(@project_id).managed_zones.select do |zone|
104
+ /(?:\A|\.)#{Regexp.escape(zone.dns_name)}\z/ =~ domain
105
+ end.max_by{|z| z.dns_name.size }
106
+ if managed_zone.nil?
107
+ raise "Domain #{domain} is not managed in Google Cloud DNS [project_id=#{@project_id}]"
108
+ end
109
+ managed_zone
110
+ end
111
+
112
+ def resource_record_set(domain, challenge)
113
+ Google::Apis::DnsV1::ResourceRecordSet.new(
114
+ name: [challenge.record_name, domain].join("."),
115
+ type: challenge.record_type,
116
+ rrdatas: [challenge.record_content],
117
+ ttl: @config[:ttl] || 5
118
+ )
119
+ end
120
+ end
121
+ end
122
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: acmesmith-google-cloud-dns
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Chikanaga Tomoyuki
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2016-03-28 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: acmesmith
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: google-api-client
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.9.1
41
+ - !ruby/object:Gem::Dependency
42
+ name: bundler
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '1.10'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '1.10'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '10.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '10.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rspec
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '3.0'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '3.0'
83
+ description: This gem is a plugin for acmesmith and implements an automated dns-01
84
+ challenge responder using Google Cloud DNS
85
+ email:
86
+ - nagachika@ruby-lang.org
87
+ executables: []
88
+ extensions: []
89
+ extra_rdoc_files: []
90
+ files:
91
+ - ".gitignore"
92
+ - ".rspec"
93
+ - ".travis.yml"
94
+ - Gemfile
95
+ - README.md
96
+ - Rakefile
97
+ - acmesmith-google-cloud-dns.gemspec
98
+ - bin/console
99
+ - bin/setup
100
+ - lib/acmesmith-google-cloud-dns/version.rb
101
+ - lib/acmesmith/challenge_responders/google_cloud_dns.rb
102
+ homepage: https://github.com/nagachika/acmetmith-google-cloud-dns
103
+ licenses:
104
+ - MIT
105
+ metadata: {}
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 2.4.5.1
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: acmesmith plugin implementing dns-01 using Google Cloud DNS
126
+ test_files: []