knife-openvpn 0.0.1 → 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Build Status](https://travis-ci.org/express42/knife-openvpn.svg)](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
|