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 +4 -4
- data/.gitignore +14 -0
- data/.rubocop.yml +14 -0
- data/.travis.yml +7 -0
- data/Gemfile +5 -0
- data/LICENSE +20 -0
- data/README.md +35 -1
- data/knife-openvpn.gemspec +2 -2
- data/lib/chef/knife/openvpn.rb +77 -35
- metadata +8 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 88392df23f3aa58d807022146707b08fead539ea
|
4
|
+
data.tar.gz: 18252c75306991cb22f8101ae2071c0503632e7f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d9e1e4dff1b795dafd80e1b5ffad74ccc412e819d9fe28c693314fc86a20b00ae041e000de7aa6d726754b898f16ac0a5b3591bfb948b7448fc0a2471ea57fd5
|
7
|
+
data.tar.gz: 724635b4ad05598b6ce0f96cfa8388eb51737f6bca1345a83868a09d623a3d3845dcb7c5dd1aca929c34505f0710e3b6e6bf8b6f8dd91f1350b5843f17b0ca17
|
data/.gitignore
ADDED
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
data/Gemfile
ADDED
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
|
+
[](https://travis-ci.org/express42/knife-openvpn)
|
2
|
+
|
1
3
|
# knife-openvpn
|
2
|
-
|
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
|
data/knife-openvpn.gemspec
CHANGED
@@ -1,9 +1,9 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
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.
|
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']
|
data/lib/chef/knife/openvpn.rb
CHANGED
@@ -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,
|
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
|
72
|
-
databag_secret_file = File.join(Dir.pwd,
|
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::
|
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::
|
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 =
|
184
|
+
secret = load_databag_secret
|
175
185
|
encrypted_data = Chef::EncryptedDataBagItem.encrypt_data_bag_item(item_hash, secret)
|
176
|
-
|
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 =
|
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::
|
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.
|
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,
|
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,
|
362
|
+
user_cert, _user_key = load_cert_and_key user_item['cert'], user_item['key']
|
332
363
|
tmpdir = Dir.mktmpdir
|
333
|
-
ui.
|
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.
|
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",
|
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
|
364
|
-
fail_with "
|
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 #{
|
371
|
-
config_content << "proto #{
|
372
|
-
|
373
|
-
|
374
|
-
|
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::
|
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,
|
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::
|
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.
|
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-
|
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.
|
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
|