certman 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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: