acmesmith-google-cloud-dns 0.1.1 → 0.2.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.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c7d3669d3a965183f22b88bfaf0237dd96bdddb7
|
4
|
+
data.tar.gz: d792b2845d8f1f4865141e609d17e389974db7d1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b56650c70ad3329026efeccaaebe9713878806ae3096170792afc1c11ef0f9eec1f78a1c527516b4625685c04a651f31116550d5a428d5f9af220fdec22641dc
|
7
|
+
data.tar.gz: e13876bccf6c72ac5f6d84b7ef528ac382c1ff8be210e96da039e8cc20fe64d728e078207f3707a36442dc2f64f961101b0aeaf2fc05df007c24dcd428ab4a23
|
data/README.md
CHANGED
@@ -22,7 +22,7 @@ Use `google-cloud-dns` challenge responder in your `acmesmith.yml`. General inst
|
|
22
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
23
|
|
24
24
|
```yaml
|
25
|
-
|
25
|
+
directory: https://acme-v02.api.letsencrypt.org/directory
|
26
26
|
|
27
27
|
storage:
|
28
28
|
type: filesystem
|
@@ -19,7 +19,7 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
20
20
|
spec.require_paths = ["lib"]
|
21
21
|
|
22
|
-
spec.add_dependency "acmesmith"
|
22
|
+
spec.add_dependency "acmesmith", "~> 2.0"
|
23
23
|
spec.add_dependency "google-api-client"
|
24
24
|
|
25
25
|
spec.add_development_dependency "bundler", "~> 1.10"
|
@@ -3,6 +3,7 @@ require "acmesmith/challenge_responders/base"
|
|
3
3
|
require "json"
|
4
4
|
require "google/apis/dns_v1"
|
5
5
|
require "resolv"
|
6
|
+
require "set"
|
6
7
|
|
7
8
|
module Acmesmith
|
8
9
|
module ChallengeResponders
|
@@ -11,6 +12,10 @@ module Acmesmith
|
|
11
12
|
type == 'dns-01'
|
12
13
|
end
|
13
14
|
|
15
|
+
def cap_respond_all?
|
16
|
+
true
|
17
|
+
end
|
18
|
+
|
14
19
|
def initialize(config)
|
15
20
|
@config = config
|
16
21
|
@scope = "https://www.googleapis.com/auth/ndev.clouddns.readwrite"
|
@@ -32,21 +37,44 @@ module Acmesmith
|
|
32
37
|
@project_id = @config[:project_id]
|
33
38
|
end
|
34
39
|
|
35
|
-
def
|
36
|
-
|
40
|
+
def respond_all(*domain_and_challenges)
|
41
|
+
challenges_by_zone_names = domain_and_challenges.group_by{ |domain, challenge|
|
42
|
+
domain = canonicalize(domain)
|
43
|
+
find_managed_zone(domain).name
|
44
|
+
}
|
37
45
|
|
38
|
-
|
39
|
-
|
46
|
+
challenges_by_zone_names.each do |zone_name, dcs|
|
47
|
+
change = change_for_challenges(zone_name, dcs)
|
40
48
|
|
41
|
-
|
42
|
-
|
43
|
-
change.additions = [
|
44
|
-
resource_record_set(domain, challenge)
|
45
|
-
]
|
46
|
-
resp = @api.create_change(@project_id, zone_name, change)
|
49
|
+
resp = @api.create_change(@project_id, zone_name, change)
|
50
|
+
change_id = resp.id
|
47
51
|
|
48
|
-
|
52
|
+
wait_for_sync_by_api(zone_name, change_id)
|
53
|
+
wait_for_sync_by_dns(zone_name, change)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def cleanup_all(*domain_and_challenges)
|
58
|
+
challenges_by_zone_names = domain_and_challenges.group_by{ |domain, challenge|
|
59
|
+
domain = canonicalize(domain)
|
60
|
+
find_managed_zone(domain).name
|
61
|
+
}
|
62
|
+
|
63
|
+
challenges_by_zone_names.each do |zone_name, dcs|
|
64
|
+
change = change_for_challenges(zone_name, dcs, for_cleanup: true)
|
65
|
+
|
66
|
+
resp = @api.create_change(@project_id, zone_name, change)
|
67
|
+
change_id = resp.id
|
68
|
+
|
69
|
+
wait_for_sync_by_api(zone_name, change_id)
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
|
75
|
+
def wait_for_sync_by_api(zone_name, change_id)
|
49
76
|
puts " * requested change: #{change_id}"
|
77
|
+
resp = @api.get_change(@project_id, zone_name, change_id)
|
50
78
|
|
51
79
|
while resp.status != 'done'
|
52
80
|
puts " * change #{change_id.inspect} is still #{resp.status.inspect}"
|
@@ -55,38 +83,40 @@ module Acmesmith
|
|
55
83
|
end
|
56
84
|
|
57
85
|
puts " * synced!"
|
86
|
+
end
|
58
87
|
|
88
|
+
def wait_for_sync_by_dns(zone_name, change)
|
59
89
|
puts "=> Checking DNS resource record"
|
60
90
|
nameservers = @api.get_managed_zone(@project_id, zone_name).name_servers
|
61
91
|
puts " * nameservers: #{nameservers.inspect}"
|
62
92
|
nameservers.each do |ns|
|
63
93
|
Resolv::DNS.open(:nameserver => Resolv.getaddresses(ns)) do |dns|
|
64
94
|
dns.timeouts = 5
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
95
|
+
change.additions.each do |rrset|
|
96
|
+
required_rrdatas = Set.new(rrset.rrdatas.map{|rrdata| rrdata.gsub(/(\A"|"\z)/, '') })
|
97
|
+
|
98
|
+
deletion = change.deletions.find{|_deletion| _deletion.name == rrset.name && _deletion.type == rrset.type }
|
99
|
+
if deletion
|
100
|
+
required_rrdatas -= Set.new(deletion.rrdatas)
|
101
|
+
end
|
102
|
+
|
103
|
+
loop do
|
104
|
+
resources = dns.getresources(rrset.name, Resolv::DNS::Resource::IN::TXT)
|
105
|
+
actual_rrdatas = resources.map(&:data)
|
106
|
+
if required_rrdatas.subset?(Set.new(actual_rrdatas))
|
107
|
+
puts " * [#{ns} -> #{rrset.name}] success. (actual=#{actual_rrdatas.inspect})"
|
108
|
+
sleep 1
|
109
|
+
break
|
110
|
+
else
|
111
|
+
puts " * [#{ns} -> #{rrset.name}] failed. (required=#{required_rrdatas.to_a.inspect}, but actual=#{actual_rrdatas.inspect})"
|
112
|
+
sleep 5
|
113
|
+
end
|
114
|
+
end
|
71
115
|
end
|
72
|
-
puts " * [#{ns}] success: ttl=#{ret.ttl.inspect}, data=#{ret.data.inspect}"
|
73
|
-
sleep 1
|
74
116
|
end
|
75
117
|
end
|
76
118
|
end
|
77
119
|
|
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
120
|
def load_json_key(filepath)
|
91
121
|
obj = JSON.parse(File.read(filepath))
|
92
122
|
{
|
@@ -109,13 +139,55 @@ module Acmesmith
|
|
109
139
|
managed_zone
|
110
140
|
end
|
111
141
|
|
112
|
-
def
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
142
|
+
def change_for_challenges(zone_name, domain_and_challenges, for_cleanup: false)
|
143
|
+
current_rrsets = @api.fetch_all(items: :rrsets) do |token|
|
144
|
+
@api.list_resource_record_sets(@project_id, zone_name, page_token: token)
|
145
|
+
end
|
146
|
+
|
147
|
+
change = Google::Apis::DnsV1::Change.new
|
148
|
+
|
149
|
+
change.deletions = domain_and_challenges.map{ |domain, challenge|
|
150
|
+
domain = canonicalize(domain)
|
151
|
+
name = [challenge.record_name, domain].join('.')
|
152
|
+
type = challenge.record_type
|
153
|
+
|
154
|
+
current_rrsets.find{ |rrset| rrset.type == type && rrset.name == name }
|
155
|
+
}.uniq.compact
|
156
|
+
|
157
|
+
change.additions = domain_and_challenges.map{ |domain, challenge|
|
158
|
+
domain = canonicalize(domain)
|
159
|
+
name = [challenge.record_name, domain].join('.')
|
160
|
+
type = challenge.record_type
|
161
|
+
data = "\"#{challenge.record_content}\""
|
162
|
+
|
163
|
+
{
|
164
|
+
name: name,
|
165
|
+
type: type,
|
166
|
+
rrdatas: [data],
|
167
|
+
}
|
168
|
+
}.group_by{ |rrset_param|
|
169
|
+
[ rrset_param[:name], rrset_param[:type] ]
|
170
|
+
}.map{ |(name, type), rrset_params|
|
171
|
+
current_rrset = current_rrsets.find{ |rrset| rrset.type == type && rrset.name == name }
|
172
|
+
|
173
|
+
new_rrset = Google::Apis::DnsV1::ResourceRecordSet.new(
|
174
|
+
name: name,
|
175
|
+
type: type,
|
176
|
+
rrdatas: current_rrset ? current_rrset.rrdatas : [],
|
177
|
+
ttl: @config[:ttl] || 5,
|
178
|
+
)
|
179
|
+
|
180
|
+
if for_cleanup
|
181
|
+
new_rrset.rrdatas -= rrset_params.map{|rrset| rrset[:rrdatas] }.flatten
|
182
|
+
else
|
183
|
+
new_rrset.rrdatas += rrset_params.map{|rrset| rrset[:rrdatas] }.flatten
|
184
|
+
end
|
185
|
+
new_rrset
|
186
|
+
}.select{ |rrset|
|
187
|
+
rrset.rrdatas != []
|
188
|
+
}
|
189
|
+
|
190
|
+
change
|
119
191
|
end
|
120
192
|
end
|
121
193
|
end
|
metadata
CHANGED
@@ -1,29 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: acmesmith-google-cloud-dns
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Chikanaga Tomoyuki
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-11-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: acmesmith
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - "
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '2.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - "
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
26
|
+
version: '2.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: google-api-client
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -119,7 +119,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
119
|
version: '0'
|
120
120
|
requirements: []
|
121
121
|
rubyforge_project:
|
122
|
-
rubygems_version: 2.6.
|
122
|
+
rubygems_version: 2.6.14.1
|
123
123
|
signing_key:
|
124
124
|
specification_version: 4
|
125
125
|
summary: acmesmith plugin implementing dns-01 using Google Cloud DNS
|