certman 0.1.0 → 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: abd249cac5771cfd40429d8123247925a65c3b55
4
- data.tar.gz: a06cea74aff79c77bc6800660f038f89f0412aa8
3
+ metadata.gz: dc3463ae829bfaef6897bb714c2489d113113465
4
+ data.tar.gz: 55623eb5f306caa72832a252a06125632344efc9
5
5
  SHA512:
6
- metadata.gz: 88589e4fb6d9b5eb7e065dc3ddc351c7b2831ea2d5b6cda1e541192e470e50a9ddcd66be775959e2ec202ac034f5be7db437627223fb8fb9dd84a7d3de9707b8
7
- data.tar.gz: e10726b02ce3acd0287f8800a8176c6f2f1816d23de210ca8152d3915a0b341173d3f2ea5ddd3f301933e50512563b218e0ccf77e9dcc1e895d715c2e6908e6c
6
+ metadata.gz: 6fab1591da092475a654d4903b9984ec71f4c35b6f85ce69ff4bdfcde40123d3b53557e10f8450d2efff75d777da892542ff424107fecc1eb2b6a81aa42b031f
7
+ data.tar.gz: 285bae5e5f326b9b6d57e9d32dcf68b01461354ce63d0b3fed8599a68c49f45e67e28ebe3a8e12c1bdb3028537646efe857a6410a17551f758eccddc00a208e0
data/.rubocop.yml CHANGED
@@ -17,7 +17,7 @@ Metrics/PerceivedComplexity:
17
17
  Max: 10
18
18
 
19
19
  Metrics/BlockLength:
20
- Max: 30
20
+ Max: 50
21
21
 
22
22
  Metrics/LineLength:
23
23
  Max: 120
data/README.md CHANGED
@@ -36,15 +36,20 @@ NOTICE! When requesting, Certman replace Active Receipt Rule Set. OK? Yes
36
36
  [✔] [Route53] Check MX Record (successfull)
37
37
  [✔] [S3] Create Bucket for SES inbound (successfull)
38
38
  [✔] [SES] Create Domain Identity (successfull)
39
- [✔] [Route53] Add TXT Record Set to verify Domain Identity (successfull)
39
+ [✔] [Route53] Create TXT Record Set to verify Domain Identity (successfull)
40
40
  [✔] [SES] Check Domain Identity Status *verified* (successfull)
41
- [✔] [Route53] Add MX Record Set (successfull)
41
+ [✔] [Route53] Create MX Record Set (successfull)
42
+ [✔] [SES] Create Receipt Rule Set (successfull)
42
43
  [✔] [SES] Create Receipt Rule (successfull)
44
+ [✔] [SES] Replace Active Receipt Rule Set (successfull)
43
45
  [✔] [ACM] Request Certificate (successfull)
44
46
  [✔] [S3] Check approval mail (will take about 30 min) (successfull)
45
- [✔] [SES] Remove Receipt rule (successfull)
46
- [✔] [Route53] Remove Record Set (successfull)
47
- [✔] [SES] Remove Verified Domain Identiry (successfull)
47
+ [✔] [SES] Revert Active Receipt Rule Set (successfull)
48
+ [✔] [SES] Delete Receipt Rule (successfull)
49
+ [✔] [SES] Delete Receipt Rule Set (successfull)
50
+ [✔] [Route53] Delete MX Record Set (successfull)
51
+ [✔] [Route53] Delete TXT Record Set (successfull)
52
+ [✔] [SES] Delete Verified Domain Identiry (successfull)
48
53
  [✔] [S3] Delete Bucket (successfull)
49
54
  Done.
50
55
 
data/lib/certman/cli.rb CHANGED
@@ -1,12 +1,19 @@
1
1
  module Certman
2
2
  class CLI < Thor
3
3
  desc 'request [DOMAIN]', 'Request ACM Certificate with only AWS managed services'
4
+ option :remain_resources, type: :boolean
4
5
  def request(domain)
5
6
  pastel = Pastel.new
6
7
  prompt = TTY::Prompt.new
7
8
  return unless prompt.yes?(pastel.red('NOTICE! Certman support *us-east-1* only, now. OK?'))
8
9
  return unless prompt.yes?(pastel.red('NOTICE! When requesting, Certman replace Active Receipt Rule Set. OK?'))
9
- cert_arn = Certman::Client.new(domain).request_certificate
10
+ client = Certman::Client.new(domain)
11
+ Signal.trap(:INT) do
12
+ puts ''
13
+ puts pastel.red('Rollback start.')
14
+ client.rollback
15
+ end
16
+ cert_arn = client.request(options[:remain_resources])
10
17
  puts 'Done.'
11
18
  puts ''
12
19
  puts "certificate_arn: #{pastel.cyan(cert_arn)}"
@@ -15,7 +22,7 @@ module Certman
15
22
 
16
23
  desc 'delete [DOMAIN]', 'Delete ACM Certificate'
17
24
  def delete(domain)
18
- Certman::Client.new(domain).delete_certificate
25
+ Certman::Client.new(domain).delete
19
26
  puts 'Done.'
20
27
  puts ''
21
28
  end
@@ -1,350 +1,157 @@
1
1
  module Certman
2
2
  class Client
3
- attr_reader :domain
3
+ include Certman::Resource::STS
4
+ include Certman::Resource::S3
5
+ include Certman::Resource::SES
6
+ include Certman::Resource::Route53
7
+ include Certman::Resource::ACM
4
8
 
5
9
  def initialize(domain)
10
+ @do_rollback = false
6
11
  @domain = domain
12
+ @cert_arn = nil
13
+ @savepoint = []
7
14
  end
8
15
 
9
- def request_certificate
16
+ def request(remain_resources = false)
10
17
  check_resource
11
18
 
12
- # Get Account ID
13
- account_id = sts.get_caller_identity.account
14
-
15
- # Create S3 for SES inbound
16
- s = spinner('[S3] Create Bucket for SES inbound')
17
- bucket_policy = <<-"EOF"
18
- {
19
- "Version": "2008-10-17",
20
- "Statement": [
21
- {
22
- "Sid": "GiveSESPermissionToWriteEmail",
23
- "Effect": "Allow",
24
- "Principal": {
25
- "Service": [
26
- "ses.amazonaws.com"
27
- ]
28
- },
29
- "Action": [
30
- "s3:PutObject"
31
- ],
32
- "Resource": "arn:aws:s3:::#{bucket_name}/*",
33
- "Condition": {
34
- "StringEquals": {
35
- "aws:Referer": "#{account_id}"
36
- }
37
- }
38
- }
39
- ]
40
- }
41
- EOF
42
- s3.create_bucket(
43
- acl: 'private',
44
- bucket: bucket_name
45
- )
46
- s3.put_bucket_policy(
47
- bucket: bucket_name,
48
- policy: bucket_policy,
49
- use_accelerate_endpoint: false
50
- )
51
- s.success
52
-
53
- # Create Domain Identity
54
- s = spinner('[SES] Create Domain Identity')
55
- res = ses.verify_domain_identity(domain: domain)
56
- token = res.verification_token
57
- s.success
58
-
59
- # Add TXT Record Set with Route53
60
- s = spinner('[Route53] Add TXT Record Set to verify Domain Identity')
61
- root_domain = PublicSuffix.domain(domain)
62
- hosted_zone = route53.list_hosted_zones.hosted_zones.find do |zone|
63
- PublicSuffix.domain(zone.name) == root_domain
19
+ step('[S3] Create Bucket for SES inbound', :s3_bucket) do
20
+ create_bucket
64
21
  end
65
- route53.change_resource_record_sets(
66
- change_batch: {
67
- changes: [
68
- {
69
- action: 'CREATE',
70
- resource_record_set: {
71
- name: "_amazonses.#{domain}",
72
- resource_records: [
73
- {
74
- value: '"' + token + '"'
75
- }
76
- ],
77
- ttl: 60,
78
- type: 'TXT'
79
- }
80
- }
81
- ],
82
- comment: 'Generate by certman'
83
- },
84
- hosted_zone_id: hosted_zone.id
85
- )
86
- s.success
87
22
 
88
- # Checking verify
89
- s = spinner('[SES] Check Domain Identity Status *verified*')
90
- is_break = false
91
- 100.times do
92
- res = ses.get_identity_verification_attributes(
93
- identities: [
94
- domain
95
- ]
96
- )
97
- if res.verification_attributes[domain].verification_status == 'Success'
98
- is_break = true
99
- s.success
100
- break
101
- end
102
- sleep 5
23
+ step('[SES] Create Domain Identity', :ses_domain_identity) do
24
+ create_domain_identity
103
25
  end
104
- s.error unless is_break
105
26
 
106
- # Add MX Record Set
107
- s = spinner('[Route53] Add MX Record Set')
108
- route53.change_resource_record_sets(
109
- change_batch: {
110
- changes: [
111
- {
112
- action: 'CREATE',
113
- resource_record_set: {
114
- name: domain,
115
- resource_records: [
116
- {
117
- value: '10 inbound-smtp.us-east-1.amazonaws.com'
118
- }
119
- ],
120
- ttl: 60,
121
- type: 'MX'
122
- }
123
- }
124
- ],
125
- comment: 'Generate by certman'
126
- },
127
- hosted_zone_id: hosted_zone.id
128
- )
129
- s.success
27
+ step('[Route53] Create TXT Record Set to verify Domain Identity', :route53_txt) do
28
+ create_txt_rset
29
+ end
130
30
 
131
- # Create Receipt rule
132
- s = spinner('[SES] Create Receipt Rule')
133
- rule_name = "S3RuleGeneratedByCertman_#{domain}"
134
- rule_set_name = "RuleSetGeneratedByCertman_#{domain}"
135
- ses.create_receipt_rule_set(rule_set_name: rule_set_name)
136
- ses.create_receipt_rule(
137
- rule: {
138
- recipients: ["admin@#{domain}"],
139
- actions: [
140
- {
141
- s3_action: {
142
- bucket_name: bucket_name
143
- }
144
- }
145
- ],
146
- enabled: true,
147
- name: rule_name,
148
- scan_enabled: true,
149
- tls_policy: 'Optional'
150
- },
151
- rule_set_name: rule_set_name
152
- )
153
- current_rule_set_name = nil
154
- res = ses.describe_active_receipt_rule_set
155
- current_rule_set_name = res.metadata.name if res.metadata
156
- ses.set_active_receipt_rule_set(rule_set_name: rule_set_name)
157
- s.success
31
+ step('[SES] Check Domain Identity Status *verified*', nil) do
32
+ check_domain_identity_verified
33
+ end
158
34
 
159
- # Request Certificate
160
- s = spinner('[ACM] Request Certificate')
161
- res = acm.request_certificate(
162
- domain_name: domain,
163
- subject_alternative_names: [domain],
164
- domain_validation_options: [
165
- {
166
- domain_name: domain,
167
- validation_domain: domain
168
- }
169
- ]
170
- )
171
- cert_arn = res.certificate_arn
172
- s.success
35
+ step('[Route53] Create MX Record Set', :route53_mx) do
36
+ create_mx_rset
37
+ end
173
38
 
174
- # Check Mail and Approve
175
- s = spinner('[S3] Check approval mail (will take about 30 min)')
176
- is_break = false
177
- 60.times do
178
- s3.list_objects(bucket: bucket_name).contents.map do |object|
179
- res = s3.get_object(bucket: bucket_name, key: object.key)
180
- res.body.read.match(%r{https://certificates\.amazon\.com/approvals[^\s]+}) do |md|
181
- cert_uri = md[0]
182
- handle = open(cert_uri)
183
- document = Oga.parse_html(handle)
184
- data = {}
185
- document.css('form input').each do |input|
186
- data[input.get('name')] = input.get('value')
187
- end
188
- res = Net::HTTP.post_form(URI.parse('https://certificates.amazon.com/approvals'), data)
189
- if res.body =~ /Success/
190
- s.success
191
- else
192
- s.error
193
- end
194
- is_break = true
195
- break
196
- end
197
- end
198
- break if is_break
199
- sleep 30
39
+ step('[SES] Create Receipt Rule Set', :ses_rule_set) do
40
+ create_rule_set
200
41
  end
201
- s.error unless is_break
202
42
 
203
- # Remove Receipt Rule
204
- s = spinner('[SES] Remove Receipt Rule')
205
- ses.set_active_receipt_rule_set(rule_set_name: current_rule_set_name)
206
- ses.delete_receipt_rule(
207
- rule_name: rule_name,
208
- rule_set_name: rule_set_name
209
- )
210
- ses.delete_receipt_rule_set(rule_set_name: rule_set_name)
211
- s.success
43
+ step('[SES] Create Receipt Rule', :ses_rule) do
44
+ create_rule
45
+ end
212
46
 
213
- # Remove Record Set
214
- s = spinner('[Route53] Remove Record Set')
215
- route53.change_resource_record_sets(
216
- change_batch: {
217
- changes: [
218
- {
219
- action: 'DELETE',
220
- resource_record_set: {
221
- name: "_amazonses.#{domain}",
222
- resource_records: [
223
- {
224
- value: '"' + token + '"'
225
- }
226
- ],
227
- ttl: 60,
228
- type: 'TXT'
229
- }
230
- },
231
- {
232
- action: 'DELETE',
233
- resource_record_set: {
234
- name: domain,
235
- resource_records: [
236
- {
237
- value: '10 inbound-smtp.us-east-1.amazonaws.com'
238
- }
239
- ],
240
- ttl: 60,
241
- type: 'MX'
242
- }
243
- }
244
- ],
245
- comment: 'Generate by certman'
246
- },
247
- hosted_zone_id: hosted_zone.id
248
- )
249
- s.success
47
+ step('[SES] Replace Active Receipt Rule Set', :ses_replace_active_rule_set) do
48
+ replace_active_rule_set
49
+ end
250
50
 
251
- # Remove Verified Domain Identiry
252
- s = spinner('[SES] Remove Verified Domain Identiry')
253
- ses.delete_identity(identity: domain)
254
- s.success
51
+ step('[ACM] Request Certificate', :acm_certificate) do
52
+ request_certificate
53
+ end
255
54
 
256
- # Delete S3 for SES inbound
257
- s = spinner('[S3] Delete Bucket')
258
- objects = s3.list_objects(bucket: bucket_name).contents.map do |object|
259
- { key: object.key }
55
+ step('[S3] Check approval mail (will take about 30 min)', nil) do
56
+ check_approval_mail
260
57
  end
261
- s3.delete_objects(
262
- bucket: bucket_name,
263
- delete: {
264
- objects: objects
265
- }
266
- )
267
- s3.delete_bucket(bucket: bucket_name)
268
- s.success
269
58
 
270
- cert_arn
59
+ cleanup_resources if !remain_resources || @do_rollback
60
+
61
+ @cert_arn
271
62
  end
272
63
 
273
- def delete_certificate
64
+ def delete
274
65
  s = spinner('[ACM] Delete Certificate')
275
- current_cert = acm.list_certificates.certificate_summary_list.find do |cert|
276
- cert.domain_name == domain
277
- end
278
- raise 'Certificate does not exist' unless current_cert
279
- acm.delete_certificate(certificate_arn: current_cert.certificate_arn)
66
+ delete_certificate
280
67
  s.success
281
68
  end
282
69
 
283
70
  def check_resource
284
71
  s = spinner('[ACM] Check Certificate')
285
- current_cert = acm.list_certificates.certificate_summary_list.find do |cert|
286
- cert.domain_name == domain
287
- end
288
- raise 'Certificate already exist' if current_cert
72
+ check_certificate
289
73
  s.success
290
74
 
291
75
  s = spinner('[Route53] Check Hosted Zone')
292
- root_domain = PublicSuffix.domain(domain)
293
- hosted_zone_id = nil
294
- hosted_zone = route53.list_hosted_zones.hosted_zones.find do |zone|
295
- if PublicSuffix.domain(zone.name) == root_domain
296
- hosted_zone_id = zone.id
297
- next true
298
- end
299
- end
300
- raise "Hosted Zone #{root_domain} does not exist" unless hosted_zone
76
+ check_hosted_zone
301
77
  s.success
302
78
 
303
79
  s = spinner('[Route53] Check TXT Record')
304
- res = route53.list_resource_record_sets(
305
- hosted_zone_id: hosted_zone_id,
306
- start_record_name: "_amazonses.#{domain}.",
307
- start_record_type: 'TXT'
308
- )
309
- raise "_amazonses.#{domain} TXT already exist" unless res.resource_record_sets.empty?
80
+ check_txt_rset
310
81
  s.success
311
82
 
312
83
  s = spinner('[Route53] Check MX Record')
313
- res = route53.list_resource_record_sets(
314
- hosted_zone_id: hosted_zone_id,
315
- start_record_name: "#{domain}.",
316
- start_record_type: 'MX'
317
- )
318
- raise "#{domain} MX already exist" unless res.resource_record_sets.empty?
84
+ check_mx_rset
319
85
  s.success
320
86
 
321
87
  true
322
88
  end
323
89
 
324
- private
325
-
326
- def sts
327
- @sts ||= Aws::STS::Client.new
90
+ def rollback
91
+ @do_rollback = true
328
92
  end
329
93
 
330
- def s3
331
- @s3 ||= Aws::S3::Client.new
94
+ private
95
+
96
+ def step(message, save)
97
+ return if @do_rollback
98
+ s = spinner(message)
99
+ begin
100
+ yield
101
+ @savepoint.push(save)
102
+ s.success
103
+ rescue
104
+ puts "Error: #{$ERROR_INFO}"
105
+ @do_rollback = true
106
+ s.error
107
+ end
332
108
  end
333
109
 
334
- def ses
335
- @ses ||= Aws::SES::Client.new
110
+ def cleanup_resources
111
+ @savepoint.reverse.each do |state|
112
+ case state
113
+ when :s3_bucket
114
+ s = spinner('[S3] Delete Bucket')
115
+ delete_bucket
116
+ s.success
117
+ when :ses_domain_identity
118
+ s = spinner('[SES] Delete Verified Domain Identiry')
119
+ delete_domain_identity
120
+ s.success
121
+ when :route53_txt
122
+ s = spinner('[Route53] Delete TXT Record Set')
123
+ delete_txt_rset
124
+ s.success
125
+ when :route53_mx
126
+ s = spinner('[Route53] Delete MX Record Set')
127
+ delete_mx_rset
128
+ s.success
129
+ when :ses_rule_set
130
+ s = spinner('[SES] Delete Receipt Rule Set')
131
+ delete_rule_set
132
+ s.success
133
+ when :ses_rule
134
+ s = spinner('[SES] Delete Receipt Rule')
135
+ delete_rule
136
+ s.success
137
+ when :ses_replace_active_rule_set
138
+ s = spinner('[SES] Revert Active Receipt Rule Set')
139
+ revert_active_rue_set
140
+ s.success
141
+ end
142
+ end
336
143
  end
337
144
 
338
- def route53
339
- @route53 ||= Aws::Route53::Client.new
145
+ def bucket_name
146
+ @bucket_name ||= "#{@domain}-generated-by-certman-for-ses-inbound-"
340
147
  end
341
148
 
342
- def acm
343
- @acm ||= Aws::ACM::Client.new
149
+ def rule_name
150
+ @rule_name ||= "S3RuleGeneratedByCertman_#{@domain}"
344
151
  end
345
152
 
346
- def bucket_name
347
- @bucket_name ||= "#{domain}-generated-by-certman-for-ses-inbound-"
153
+ def rule_set_name
154
+ @rule_set_name ||= "RuleSetGeneratedByCertman_#{@domain}"
348
155
  end
349
156
 
350
157
  def spinner(message)
@@ -0,0 +1,38 @@
1
+ module Certman
2
+ module Resource
3
+ module ACM
4
+ def request_certificate
5
+ res = acm.request_certificate(
6
+ domain_name: @domain,
7
+ subject_alternative_names: [@domain],
8
+ domain_validation_options: [
9
+ {
10
+ domain_name: @domain,
11
+ validation_domain: @domain
12
+ }
13
+ ]
14
+ )
15
+ @cert_arn = res.certificate_arn
16
+ end
17
+
18
+ def delete_certificate
19
+ current_cert = acm.list_certificates.certificate_summary_list.find do |cert|
20
+ cert.domain_name == @domain
21
+ end
22
+ raise 'Certificate does not exist' unless current_cert
23
+ acm.delete_certificate(certificate_arn: current_cert.certificate_arn)
24
+ end
25
+
26
+ def check_certificate
27
+ current_cert = acm.list_certificates.certificate_summary_list.find do |cert|
28
+ cert.domain_name == @domain
29
+ end
30
+ raise 'Certificate already exist' if current_cert
31
+ end
32
+
33
+ def acm
34
+ @acm ||= Aws::ACM::Client.new
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,140 @@
1
+ module Certman
2
+ module Resource
3
+ # rubocop:disable Metrics/ModuleLength
4
+ module Route53
5
+ def create_txt_rset
6
+ root_domain = PublicSuffix.domain(@domain)
7
+ @hosted_zone = route53.list_hosted_zones.hosted_zones.find do |zone|
8
+ PublicSuffix.domain(zone.name) == root_domain
9
+ end
10
+ route53.change_resource_record_sets(
11
+ change_batch: {
12
+ changes: [
13
+ {
14
+ action: 'CREATE',
15
+ resource_record_set: {
16
+ name: "_amazonses.#{@domain}",
17
+ resource_records: [
18
+ {
19
+ value: '"' + @token + '"'
20
+ }
21
+ ],
22
+ ttl: 60,
23
+ type: 'TXT'
24
+ }
25
+ }
26
+ ],
27
+ comment: 'Generate by certman'
28
+ },
29
+ hosted_zone_id: @hosted_zone.id
30
+ )
31
+ end
32
+
33
+ def create_mx_rset
34
+ route53.change_resource_record_sets(
35
+ change_batch: {
36
+ changes: [
37
+ {
38
+ action: 'CREATE',
39
+ resource_record_set: {
40
+ name: @domain,
41
+ resource_records: [
42
+ {
43
+ value: '10 inbound-smtp.us-east-1.amazonaws.com'
44
+ }
45
+ ],
46
+ ttl: 60,
47
+ type: 'MX'
48
+ }
49
+ }
50
+ ],
51
+ comment: 'Generate by certman'
52
+ },
53
+ hosted_zone_id: @hosted_zone.id
54
+ )
55
+ end
56
+
57
+ def delete_txt_rset
58
+ route53.change_resource_record_sets(
59
+ change_batch: {
60
+ changes: [
61
+ {
62
+ action: 'DELETE',
63
+ resource_record_set: {
64
+ name: "_amazonses.#{@domain}",
65
+ resource_records: [
66
+ {
67
+ value: '"' + @token + '"'
68
+ }
69
+ ],
70
+ ttl: 60,
71
+ type: 'TXT'
72
+ }
73
+ }
74
+ ],
75
+ comment: 'Generate by certman'
76
+ },
77
+ hosted_zone_id: @hosted_zone.id
78
+ )
79
+ end
80
+
81
+ def delete_mx_rset
82
+ route53.change_resource_record_sets(
83
+ change_batch: {
84
+ changes: [
85
+ {
86
+ action: 'DELETE',
87
+ resource_record_set: {
88
+ name: @domain,
89
+ resource_records: [
90
+ {
91
+ value: '10 inbound-smtp.us-east-1.amazonaws.com'
92
+ }
93
+ ],
94
+ ttl: 60,
95
+ type: 'MX'
96
+ }
97
+ }
98
+ ],
99
+ comment: 'Generate by certman'
100
+ },
101
+ hosted_zone_id: @hosted_zone.id
102
+ )
103
+ end
104
+
105
+ def check_hosted_zone
106
+ root_domain = PublicSuffix.domain(@domain)
107
+ @hosted_zone_id = nil
108
+ hosted_zone = route53.list_hosted_zones.hosted_zones.find do |zone|
109
+ if PublicSuffix.domain(zone.name) == root_domain
110
+ @hosted_zone_id = zone.id
111
+ next true
112
+ end
113
+ end
114
+ raise "Hosted Zone #{root_domain} does not exist" unless hosted_zone
115
+ end
116
+
117
+ def check_txt_rset
118
+ res = route53.list_resource_record_sets(
119
+ hosted_zone_id: @hosted_zone_id,
120
+ start_record_name: "_amazonses.#{@domain}.",
121
+ start_record_type: 'TXT'
122
+ )
123
+ raise "_amazonses.#{@domain} TXT already exist" unless res.resource_record_sets.empty?
124
+ end
125
+
126
+ def check_mx_rset
127
+ res = route53.list_resource_record_sets(
128
+ hosted_zone_id: @hosted_zone_id,
129
+ start_record_name: "#{@domain}.",
130
+ start_record_type: 'MX'
131
+ )
132
+ raise "#{@domain} MX already exist" unless res.resource_record_sets.empty?
133
+ end
134
+
135
+ def route53
136
+ @route53 ||= Aws::Route53::Client.new
137
+ end
138
+ end
139
+ end
140
+ end
@@ -0,0 +1,89 @@
1
+ module Certman
2
+ module Resource
3
+ module S3
4
+ def create_bucket
5
+ account_id = sts.get_caller_identity.account
6
+ bucket_policy = <<-"EOF"
7
+ {
8
+ "Version": "2008-10-17",
9
+ "Statement": [
10
+ {
11
+ "Sid": "GiveSESPermissionToWriteEmail",
12
+ "Effect": "Allow",
13
+ "Principal": {
14
+ "Service": [
15
+ "ses.amazonaws.com"
16
+ ]
17
+ },
18
+ "Action": [
19
+ "s3:PutObject"
20
+ ],
21
+ "Resource": "arn:aws:s3:::#{bucket_name}/*",
22
+ "Condition": {
23
+ "StringEquals": {
24
+ "aws:Referer": "#{account_id}"
25
+ }
26
+ }
27
+ }
28
+ ]
29
+ }
30
+ EOF
31
+ s3.create_bucket(
32
+ acl: 'private',
33
+ bucket: bucket_name
34
+ )
35
+ s3.put_bucket_policy(
36
+ bucket: bucket_name,
37
+ policy: bucket_policy,
38
+ use_accelerate_endpoint: false
39
+ )
40
+ end
41
+
42
+ def check_approval_mail
43
+ is_break = false
44
+ 60.times do
45
+ s3.list_objects(bucket: bucket_name).contents.map do |object|
46
+ res = s3.get_object(bucket: bucket_name, key: object.key)
47
+ res.body.read.match(%r{https://certificates\.amazon\.com/approvals[^\s]+}) do |md|
48
+ cert_uri = md[0]
49
+ handle = open(cert_uri)
50
+ document = Oga.parse_html(handle)
51
+ data = {}
52
+ document.css('form input').each do |input|
53
+ data[input.get('name')] = input.get('value')
54
+ end
55
+ res = Net::HTTP.post_form(URI.parse('https://certificates.amazon.com/approvals'), data)
56
+ raise 'Can not approve' unless res.body =~ /Success/
57
+ # success
58
+ is_break = true
59
+ break
60
+ end
61
+ end
62
+ break if is_break
63
+ break if @do_rollback
64
+ sleep 30
65
+ end
66
+ raise 'Can not approve' unless is_break
67
+ end
68
+
69
+ def delete_bucket
70
+ objects = s3.list_objects(bucket: bucket_name).contents.map do |object|
71
+ { key: object.key }
72
+ end
73
+ unless objects.empty?
74
+ s3.delete_objects(
75
+ bucket: bucket_name,
76
+ delete: {
77
+ objects: objects
78
+ }
79
+ )
80
+ end
81
+ s3.delete_bucket(bucket: bucket_name)
82
+ end
83
+
84
+ def s3
85
+ @s3 ||= Aws::S3::Client.new
86
+ end
87
+ end
88
+ end
89
+ end
@@ -0,0 +1,83 @@
1
+ module Certman
2
+ module Resource
3
+ module SES
4
+ def create_domain_identity
5
+ res = ses.verify_domain_identity(domain: @domain)
6
+ @token = res.verification_token
7
+ end
8
+
9
+ def check_domain_identity_verified
10
+ is_break = false
11
+ 100.times do
12
+ res = ses.get_identity_verification_attributes(
13
+ identities: [
14
+ @domain
15
+ ]
16
+ )
17
+ if res.verification_attributes[@domain].verification_status == 'Success'
18
+ # success
19
+ is_break = true
20
+ break
21
+ end
22
+ break if @do_rollback
23
+ sleep 5
24
+ end
25
+ raise 'Can not check verified' unless is_break
26
+ end
27
+
28
+ def delete_domain_identity
29
+ ses.delete_identity(identity: @domain)
30
+ end
31
+
32
+ def create_rule_set
33
+ ses.create_receipt_rule_set(rule_set_name: rule_set_name)
34
+ end
35
+
36
+ def create_rule
37
+ ses.create_receipt_rule(
38
+ rule: {
39
+ recipients: ["admin@#{@domain}"],
40
+ actions: [
41
+ {
42
+ s3_action: {
43
+ bucket_name: bucket_name
44
+ }
45
+ }
46
+ ],
47
+ enabled: true,
48
+ name: rule_name,
49
+ scan_enabled: true,
50
+ tls_policy: 'Optional'
51
+ },
52
+ rule_set_name: rule_set_name
53
+ )
54
+ end
55
+
56
+ def replace_active_rule_set
57
+ @current_rule_set_name = nil
58
+ res = ses.describe_active_receipt_rule_set
59
+ @current_rule_set_name = res.metadata.name if res.metadata
60
+ ses.set_active_receipt_rule_set(rule_set_name: rule_set_name)
61
+ end
62
+
63
+ def delete_rule_set
64
+ ses.delete_receipt_rule_set(rule_set_name: rule_set_name)
65
+ end
66
+
67
+ def delete_rule
68
+ ses.delete_receipt_rule(
69
+ rule_name: rule_name,
70
+ rule_set_name: rule_set_name
71
+ )
72
+ end
73
+
74
+ def revert_active_rue_set
75
+ ses.set_active_receipt_rule_set(rule_set_name: @current_rule_set_name)
76
+ end
77
+
78
+ def ses
79
+ @ses ||= Aws::SES::Client.new
80
+ end
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,9 @@
1
+ module Certman
2
+ module Resource
3
+ module STS
4
+ def sts
5
+ @sts ||= Aws::STS::Client.new
6
+ end
7
+ end
8
+ end
9
+ end
@@ -1,3 +1,3 @@
1
1
  module Certman
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
data/lib/certman.rb CHANGED
@@ -8,6 +8,11 @@ require 'open-uri'
8
8
  require 'tty-prompt'
9
9
  require 'tty-spinner'
10
10
  require 'pastel'
11
+ require 'certman/resource/sts'
12
+ require 'certman/resource/s3'
13
+ require 'certman/resource/ses'
14
+ require 'certman/resource/route53'
15
+ require 'certman/resource/acm'
11
16
  require 'certman/client'
12
17
  require 'certman/cli'
13
18
  require 'certman/log'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: certman
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - k1LoW
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-03-23 00:00:00.000000000 Z
11
+ date: 2017-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: aws-sdk
@@ -230,6 +230,11 @@ files:
230
230
  - lib/certman/cli.rb
231
231
  - lib/certman/client.rb
232
232
  - lib/certman/log.rb
233
+ - lib/certman/resource/acm.rb
234
+ - lib/certman/resource/route53.rb
235
+ - lib/certman/resource/s3.rb
236
+ - lib/certman/resource/ses.rb
237
+ - lib/certman/resource/sts.rb
233
238
  - lib/certman/version.rb
234
239
  homepage: https://github.com/k1LoW/certman
235
240
  licenses: