knife-openvpn 0.0.1 → 0.0.2

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: 8dd1f7ab9cad0728ed9c378d00f4572308435bad
4
- data.tar.gz: 7426c914244fad2bfd8a9ae0d11b858369d20586
3
+ metadata.gz: 88392df23f3aa58d807022146707b08fead539ea
4
+ data.tar.gz: 18252c75306991cb22f8101ae2071c0503632e7f
5
5
  SHA512:
6
- metadata.gz: 95308e27b0a782af5a32f28687b6d3c53bd1a05778b44bec4177ae14e780b898b70caaae04cea30af14f075cb214b136cf904be272c7249bdf11cac8e221f36f
7
- data.tar.gz: 74f43c6fead9c46d76edb409ba435e4aece085be7841f1ec6fd6f5892cc43f05a4326b0323c1f5ebdd57dd3cc8cbca58bb7a3acf0ce3194584a5fcbe8f8d0cee
6
+ metadata.gz: d9e1e4dff1b795dafd80e1b5ffad74ccc412e819d9fe28c693314fc86a20b00ae041e000de7aa6d726754b898f16ac0a5b3591bfb948b7448fc0a2471ea57fd5
7
+ data.tar.gz: 724635b4ad05598b6ce0f96cfa8388eb51737f6bca1345a83868a09d623a3d3845dcb7c5dd1aca929c34505f0710e3b6e6bf8b6f8dd91f1350b5843f17b0ca17
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ *~
2
+ *#
3
+ .#*
4
+ \#*#
5
+ .*.sw[a-z]
6
+ *.un~
7
+
8
+ # Bundler
9
+ Gemfile.lock
10
+ bin/*
11
+ .bundle/*
12
+
13
+ # Gem
14
+ *.gem
data/.rubocop.yml ADDED
@@ -0,0 +1,14 @@
1
+ Metrics/AbcSize:
2
+ Enabled: false
3
+ Style/GuardClause:
4
+ Enabled: false
5
+ Style/Documentation:
6
+ Enabled: false
7
+ Metrics/LineLength:
8
+ Enabled: false
9
+ Metrics/MethodLength:
10
+ Enabled: false
11
+ Metrics/ClassLength:
12
+ Max: 150
13
+ Metrics/ParameterLists:
14
+ Enabled: false
data/.travis.yml ADDED
@@ -0,0 +1,7 @@
1
+ language: ruby
2
+ rvm:
3
+ - 2.1.5
4
+ script:
5
+ - bundle exec rubocop
6
+ notifications:
7
+ flowdock: d4fbb65de6c9c868a2dfc4b38fbd34c1
data/Gemfile ADDED
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ group :lint do
4
+ gem 'rubocop'
5
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2015 Express 42
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
6
+ this software and associated documentation files (the "Software"), to deal in
7
+ the Software without restriction, including without limitation the rights to
8
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9
+ the Software, and to permit persons to whom the Software is furnished to do so,
10
+ subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md CHANGED
@@ -1,2 +1,36 @@
1
+ [![Build Status](https://travis-ci.org/express42/knife-openvpn.svg)](https://travis-ci.org/express42/knife-openvpn)
2
+
1
3
  # knife-openvpn
2
- A knife plugin for Express 42 openvpn cookbook
4
+ ## Description
5
+ A knife plugin for [Express 42 OpenVPN cookbook].
6
+
7
+ ## Installation
8
+ This plugin is distributed as a Ruby Gem. To install it, run:
9
+
10
+ `gem install knife-openvpn`
11
+
12
+ ## Basic Examples
13
+
14
+ Create server ca, server cert, server key and dh params:
15
+
16
+ `knife openvpn server create office`
17
+
18
+ Add openvpn client:
19
+
20
+ `knife openvpn user create office john`
21
+
22
+ Export client data (.ovpn config, server ca, client cert and key):
23
+
24
+ `knife openvpn user export office john`
25
+
26
+ Revoke access:
27
+
28
+ `knife openvpn user revoke office john`
29
+
30
+ ## License and Maintainer
31
+
32
+ Maintainer:: LLC Express 42 (<cookbooks@express42.com>)
33
+
34
+ License:: MIT
35
+
36
+ [Express 42 OpenVPN cookbook]: https://github.com/express42-cookbooks/openvpn
@@ -1,9 +1,9 @@
1
1
  # -*- encoding: utf-8 -*-
2
- $:.push File.expand_path('../lib', __FILE__)
2
+ $LOAD_PATH.push File.expand_path('../lib', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
5
  gem.name = 'knife-openvpn'
6
- gem.version = '0.0.1'
6
+ gem.version = '0.0.2'
7
7
  gem.summary = 'A knife plugin for Express 42 openvpn cookbook'
8
8
  gem.description = gem.summary
9
9
  gem.authors = ['LLC Express 42']
@@ -37,7 +37,7 @@ module OpenvpnPlugin
37
37
  end
38
38
 
39
39
  def check_databag_secret
40
- databag_secret_file = File.join(Dir.pwd, '.chef/encrypted_data_bag_secret')
40
+ databag_secret_file = File.join(Dir.pwd, config[:databag_secret_file]) || Chef::Config[:knife][:secret_file]
41
41
  unless File.exist? databag_secret_file
42
42
  fail_with "Can't find encrypted databag secret file at #{databag_secret_file}."
43
43
  end
@@ -68,8 +68,8 @@ module OpenvpnPlugin
68
68
  name
69
69
  end
70
70
 
71
- def get_databag_secret
72
- databag_secret_file = File.join(Dir.pwd, '.chef/encrypted_data_bag_secret')
71
+ def load_databag_secret
72
+ databag_secret_file = File.join(Dir.pwd, config[:databag_secret_file]) || Chef::Config[:knife][:secret_file]
73
73
  secret = Chef::EncryptedDataBagItem.load_secret(databag_secret_file)
74
74
  secret
75
75
  end
@@ -89,13 +89,14 @@ module OpenvpnPlugin
89
89
  ca_cert.add_extension(ef.create_extension('authorityKeyIdentifier', 'keyid:always', false))
90
90
  end
91
91
 
92
- def add_endentity_extensions(entity_cert, ca_cert)
92
+ def add_endentity_extensions(entity_cert, ca_cert, is_user = false)
93
93
  ef = get_extensions_factory entity_cert, ca_cert
94
94
  entity_cert.add_extension(ef.create_extension('keyUsage', 'digitalSignature', true))
95
95
  entity_cert.add_extension(ef.create_extension('subjectKeyIdentifier', 'hash', false))
96
+ entity_cert.add_extension(ef.create_extension('nsCertType', 'server')) unless is_user
96
97
  end
97
98
 
98
- def generate_cert_and_key(subject, cert_config, selfsigned = false, ca_cert = nil, ca_key = nil)
99
+ def generate_cert_and_key(subject, cert_config, selfsigned = false, ca_cert = nil, ca_key = nil, is_user = false)
99
100
  key = OpenSSL::PKey::RSA.generate(cert_config['rsa_keysize'])
100
101
  cert = OpenSSL::X509::Certificate.new
101
102
  cert.version = 2
@@ -109,15 +110,24 @@ module OpenvpnPlugin
109
110
  cert.subject = subject
110
111
  cert.issuer = subject
111
112
  add_ca_extensions(cert)
112
- cert.sign(key, OpenSSL::Digest::SHA1.new)
113
+ cert.sign(key, OpenSSL::Digest::SHA256.new)
113
114
  else
114
115
  if ca_cert.nil? || ca_key.nil?
115
116
  fail_with "CA key or cert isn't specified"
116
117
  end
117
118
  cert.subject = subject
118
119
  cert.issuer = ca_cert.subject
119
- add_endentity_extensions(cert, ca_cert)
120
- cert.sign(ca_key, OpenSSL::Digest::SHA1.new)
120
+ add_endentity_extensions(cert, ca_cert, is_user)
121
+ cert.sign(ca_key, OpenSSL::Digest::SHA256.new)
122
+ end
123
+
124
+ if is_user
125
+ require 'highline/import'
126
+ passphrase = ask('Enter a passphrase [blank for passphraseless]: ') { |q| q.echo = false }
127
+ unless passphrase == ''
128
+ cipher = OpenSSL::Cipher.new('AES-256-CBC')
129
+ key = key.export(cipher, passphrase)
130
+ end
121
131
  end
122
132
 
123
133
  [cert, key]
@@ -171,18 +181,17 @@ module OpenvpnPlugin
171
181
  databag_path = get_databag_path server_name
172
182
  item_hash['id'] = id
173
183
  item_path = File.join(databag_path, "#{id}.json")
174
- secret = get_databag_secret
184
+ secret = load_databag_secret
175
185
  encrypted_data = Chef::EncryptedDataBagItem.encrypt_data_bag_item(item_hash, secret)
176
- unless File.exist? item_path
177
- File.write item_path, JSON.pretty_generate(encrypted_data)
178
- else
186
+ if File.exist? item_path
179
187
  fail_with "#{item_path} already exists"
188
+ else
189
+ File.write item_path, JSON.pretty_generate(encrypted_data)
180
190
  end
181
191
  end
182
192
 
183
193
  def load_databag_item(databag_name, item_id)
184
- secret = get_databag_secret
185
- # puts "Loading [#{databag_name}:#{item_id}]"
194
+ secret = load_databag_secret
186
195
  item = Chef::EncryptedDataBagItem.load(databag_name, item_id, secret)
187
196
  item
188
197
  end
@@ -190,10 +199,16 @@ module OpenvpnPlugin
190
199
 
191
200
  class OpenvpnServerCreate < Openvpn
192
201
  banner 'knife openvpn server create NAME (options)'
202
+
193
203
  deps do
194
204
  require 'readline'
195
205
  end
196
206
 
207
+ option :databag_secret_file,
208
+ long: '--secret-file PATH',
209
+ description: 'Specifies path to encrypred data bag secret file.',
210
+ default: '.chef/encrypted_data_bag_secret'
211
+
197
212
  def run
198
213
  check_arguments
199
214
  vpn_server_name = name_args.first
@@ -210,7 +225,7 @@ module OpenvpnPlugin
210
225
  server_subject = make_name vpn_server_name, cert_config
211
226
  server_cert, server_key = generate_cert_and_key server_subject, cert_config, false, ca_cert, ca_key
212
227
  dh_params = make_dh_params cert_config
213
- crl = issue_crl([], 1, now, now + 3600, [], ca_cert, ca_key, OpenSSL::Digest::SHA1.new)
228
+ crl = issue_crl([], 1, now, now + 3600, [], ca_cert, ca_key, OpenSSL::Digest::SHA256.new)
214
229
  databag_path = get_databag_path vpn_server_name
215
230
  ui.info "Creating data bag directory at #{databag_path}"
216
231
  create_databag_dir vpn_server_name
@@ -223,9 +238,7 @@ module OpenvpnPlugin
223
238
  end
224
239
 
225
240
  def check_arguments
226
- unless name_args.size == 1
227
- fail_with 'Specify NAME of new openvpn server!'
228
- end
241
+ fail_with 'Specify NAME of new openvpn server!' unless name_args.size == 1
229
242
  end
230
243
 
231
244
  def create_databag_dir(server_name)
@@ -278,6 +291,11 @@ module OpenvpnPlugin
278
291
  class OpenvpnUserCreate < Openvpn
279
292
  banner 'knife openvpn user create SERVERNAME USERNAME (options)'
280
293
 
294
+ option :databag_secret_file,
295
+ long: '--secret-file PATH',
296
+ description: 'Specifies path to encrypred data bag secret file.',
297
+ default: '.chef/encrypted_data_bag_secret'
298
+
281
299
  def run
282
300
  check_arguments
283
301
  server_name = name_args[0]
@@ -294,8 +312,8 @@ module OpenvpnPlugin
294
312
  config_item = load_databag_item(databag_name, 'openvpn-config')
295
313
  cert_config = config_item.to_hash
296
314
  user_subject = make_name user_name, cert_config
297
- user_cert, user_key = generate_cert_and_key user_subject, cert_config, false, ca_cert, ca_key
298
- save_databag_item(user_name, server_name, 'cert' => user_cert.to_pem, 'key' => user_key.to_pem)
315
+ user_cert, user_key = generate_cert_and_key user_subject, cert_config, false, ca_cert, ca_key, true
316
+ save_databag_item(user_name, server_name, 'cert' => user_cert.to_pem, 'key' => user_key.to_s)
299
317
  ui.info "Done, now you can upload #{databag_name}/#{user_name}.json"
300
318
  end
301
319
 
@@ -313,6 +331,11 @@ module OpenvpnPlugin
313
331
  require 'chef/search/query'
314
332
  end
315
333
 
334
+ option :databag_secret_file,
335
+ long: '--secret-file PATH',
336
+ description: 'Specifies path to encrypred data bag secret file.',
337
+ default: '.chef/encrypted_data_bag_secret'
338
+
316
339
  def run
317
340
  check_arguments
318
341
  server_name = name_args[0]
@@ -325,19 +348,28 @@ module OpenvpnPlugin
325
348
  def export_user(server_name, user_name)
326
349
  databag_name = get_databag_name server_name
327
350
  ca_item = load_databag_item(databag_name, 'openvpn-ca')
328
- ca_cert, ca_key = load_cert_and_key ca_item['cert'], ca_item['key']
351
+ ca_cert, _ca_key = load_cert_and_key ca_item['cert'], ca_item['key']
352
+
353
+ ta_key = ''
354
+ begin
355
+ ta_item = load_databag_item(databag_name, 'openvpn-ta')
356
+ ta_key = ta_item['ta']
357
+ rescue Net::HTTPServerException
358
+ ui.warn 'Unable to load openvpn-ta, proceding without it. (Ignore unless you use tls-auth)'
359
+ end
329
360
 
330
361
  user_item = load_databag_item(databag_name, user_name)
331
- user_cert, user_key = load_cert_and_key user_item['cert'], user_item['key']
362
+ user_cert, _user_key = load_cert_and_key user_item['cert'], user_item['key']
332
363
  tmpdir = Dir.mktmpdir
333
- ui.info "tmpdir: #{tmpdir}"
364
+ ui.debug "created tmpdir: #{tmpdir}"
334
365
  begin
335
366
  user_dir = "#{tmpdir}/#{user_name}-vpn"
336
367
  Dir.mkdir user_dir
337
- ui.info "userdir: #{user_dir}"
368
+ ui.debug "created userdir: #{user_dir}"
338
369
  export_file "#{user_dir}/ca.crt", ca_cert.to_pem
339
370
  export_file "#{user_dir}/#{user_name}.crt", user_cert.to_pem
340
- export_file "#{user_dir}/#{user_name}.key", user_key.to_pem
371
+ export_file "#{user_dir}/#{user_name}.key", user_item['key'].to_s
372
+ export_file "#{user_dir}/ta.key", ta_key unless ta_key.empty?
341
373
  config_content = generate_client_config server_name, user_name
342
374
  export_file "#{user_dir}/#{user_name}.ovpn", config_content
343
375
  exitcode = system("cd #{tmpdir} && tar cfz /tmp/#{user_name}-vpn.tar.gz *")
@@ -360,22 +392,27 @@ module OpenvpnPlugin
360
392
  query = "openvpn_server_name:#{server_name}"
361
393
  query_nodes = Chef::Search::Query.new
362
394
  search_result = query_nodes.search('node', query)[0]
363
- unless search_result.length == 1
364
- fail_with "Found #{search_result.length} vpn servers for #{server_name}"
395
+ unless search_result.length < 1
396
+ fail_with "Cant find vpn server named '#{server_name}'"
365
397
  end
366
398
  config_content = ''
367
399
  newline = "\n"
368
400
  node = search_result[0]
401
+ config = Chef::Mixin::DeepMerge.merge(node['openvpn']['default'].to_hash, node['openvpn'][server_name].to_hash)
369
402
  config_content << 'client' << newline
370
- config_content << "dev #{node['openvpn'][server_name]['dev']}" << newline
371
- config_content << "proto #{node['openvpn'][server_name]['proto']}" << newline
372
- config_content << "remote #{node['openvpn'][server_name]['remote_host']} "
373
- config_content << "#{node['openvpn'][server_name]['port']}" << newline
374
- config_content << "verb #{node['openvpn'][server_name]['verb']}" << newline
403
+ config_content << "dev #{config['dev']}" << newline
404
+ config_content << "proto #{config['proto']}" << newline
405
+ search_result.each do |result|
406
+ config_content << "remote #{result['openvpn'][server_name]['remote_host']} "
407
+ config_content << "#{config['port']}" << newline
408
+ end
409
+ config_content << "verb #{config['verb']}" << newline
375
410
  config_content << 'comp-lzo' << newline
376
411
  config_content << 'ca ca.crt' << newline
377
412
  config_content << "cert #{user_name}.crt" << newline
378
413
  config_content << "key #{user_name}.key" << newline
414
+ config_content << 'tls-auth ta.key 1' << newline if config['use_tls_auth']
415
+ config_content << 'ns-cert-type server' << newline
379
416
  config_content << 'nobind' << newline
380
417
  config_content << 'persist-key' << newline
381
418
  config_content << 'persist-tun' << newline
@@ -396,6 +433,11 @@ module OpenvpnPlugin
396
433
  require 'chef/search/query'
397
434
  end
398
435
 
436
+ option :databag_secret_file,
437
+ long: '--secret-file PATH',
438
+ description: 'Specifies path to encrypred data bag secret file.',
439
+ default: '.chef/encrypted_data_bag_secret'
440
+
399
441
  def run
400
442
  check_arguments
401
443
  server_name = name_args[0]
@@ -415,11 +457,11 @@ module OpenvpnPlugin
415
457
  old_crl = OpenSSL::X509::CRL.new crl_item['crl']
416
458
  revoke_info = crl_item['revoke_info']
417
459
  rescue
418
- old_crl = issue_crl([], 1, now, now + 3600, [], ca_cert, ca_key, OpenSSL::Digest::SHA1.new)
460
+ old_crl = issue_crl([], 1, now, now + 3600, [], ca_cert, ca_key, OpenSSL::Digest::SHA256.new)
419
461
  revoke_info = []
420
462
  end
421
463
  user_item = load_databag_item(databag_name, user_name)
422
- user_cert, user_key = load_cert_and_key user_item['cert'], user_item['key']
464
+ user_cert, _user_key = load_cert_and_key user_item['cert'], user_item['key']
423
465
  user_revoke_info = [[user_cert.serial, now, 0]]
424
466
  new_revoke_info = revoke_info + user_revoke_info
425
467
  new_crl = add_user_to_crl ca_cert, ca_key, old_crl, new_revoke_info
@@ -428,7 +470,7 @@ module OpenvpnPlugin
428
470
  end
429
471
 
430
472
  def add_user_to_crl(ca_cert, ca_key, old_crl, revoke_info)
431
- new_crl = issue_crl(revoke_info, old_crl.version + 1, Time.at(Time.now.to_i), Time.at(Time.now.to_i) + 3600, [], ca_cert, ca_key, OpenSSL::Digest::SHA1.new)
473
+ new_crl = issue_crl(revoke_info, old_crl.version + 1, Time.at(Time.now.to_i), Time.at(Time.now.to_i) + 3600, [], ca_cert, ca_key, OpenSSL::Digest::SHA256.new)
432
474
  new_crl
433
475
  end
434
476
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: knife-openvpn
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - LLC Express 42
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-01-13 00:00:00.000000000 Z
11
+ date: 2015-09-07 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: A knife plugin for Express 42 openvpn cookbook
14
14
  email: cookbooks@express42.com
@@ -16,6 +16,11 @@ executables: []
16
16
  extensions: []
17
17
  extra_rdoc_files: []
18
18
  files:
19
+ - ".gitignore"
20
+ - ".rubocop.yml"
21
+ - ".travis.yml"
22
+ - Gemfile
23
+ - LICENSE
19
24
  - README.md
20
25
  - knife-openvpn.gemspec
21
26
  - lib/chef/knife/openvpn.rb
@@ -39,7 +44,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
39
44
  version: '0'
40
45
  requirements: []
41
46
  rubyforge_project:
42
- rubygems_version: 2.4.1
47
+ rubygems_version: 2.4.4
43
48
  signing_key:
44
49
  specification_version: 4
45
50
  summary: A knife plugin for Express 42 openvpn cookbook