net-openvpn 0.3 → 0.8
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/.ruby-gemset +1 -0
- data/.ruby-version +1 -0
- data/Gemfile.lock +1 -1
- data/README.md +194 -0
- data/lib/net/openvpn.rb +32 -1
- data/lib/net/openvpn/errors.rb +8 -0
- data/lib/net/openvpn/generators/keys/authority.rb +39 -0
- data/lib/net/openvpn/generators/keys/base.rb +87 -0
- data/lib/net/openvpn/generators/keys/client.rb +45 -0
- data/lib/net/openvpn/generators/keys/directory.rb +47 -0
- data/lib/net/openvpn/generators/keys/properties.rb +73 -0
- data/lib/net/openvpn/generators/keys/server.rb +37 -0
- data/lib/net/openvpn/version.rb +1 -1
- data/spec/lib/net/openvpn/generators/keys/client_spec.rb +76 -0
- data/spec/lib/net/openvpn/generators/keys/directory_spec.rb +27 -0
- data/spec/lib/net/openvpn/generators/keys/properties_spec.rb +29 -0
- data/spec/spec_helper.rb +38 -0
- metadata +14 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 160d6e02e9cd14fa4f008f6a606ec2108a29cc55
|
4
|
+
data.tar.gz: 6b170ccc82aec4b434f689e65774b45210f77817
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 103124d60d54401a50f90ee13960edaf26b64f416a81f6851d70f0c09736a1849b2bb279ebd92cb8523542e3501d6c491c0135481cf4a534f505e67b48f198ce
|
7
|
+
data.tar.gz: c8b78600a977150ecd8a5376f20d6e8bb32b0c8ba0314831f8403bc68698252f4a9a705ab05eb1d10c71998a32bff90b5ec44fdce56bb4502c0c20920013900c
|
data/.ruby-gemset
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
net-openvpn
|
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
ruby-2.1.2
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -2,6 +2,21 @@
|
|
2
2
|
|
3
3
|
Net-Openvpn is a gem for configuring a local OpenVPN installation.
|
4
4
|
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
* openvpn
|
8
|
+
* easy-rsa
|
9
|
+
|
10
|
+
You can install these on Debian based systems by running this command:
|
11
|
+
|
12
|
+
```sh
|
13
|
+
apt-get install openvpn easy-rsa
|
14
|
+
```
|
15
|
+
|
16
|
+
Sometimes `easy-rsa` is packaged with `openvpn` so if you can't find the `easy-rsa` package anywhere have a
|
17
|
+
look in `/usr/share/doc/openvpn/examples` for the `easy-rsa` folder. Then you can just globally override
|
18
|
+
the property for `:easy_rsa` (see below).
|
19
|
+
|
5
20
|
## Usage
|
6
21
|
|
7
22
|
### Server configuration
|
@@ -52,6 +67,177 @@ host.ip # what is the ip of this host
|
|
52
67
|
host.network # what is the network of this host
|
53
68
|
```
|
54
69
|
|
70
|
+
## Generating certificates and keys
|
71
|
+
|
72
|
+
**WARNING: This functionality is a little bit experimental at the moment, I am sure there are bugs present which would be found with more specs.**
|
73
|
+
|
74
|
+
The goal is to build these generators into the Host (read: Client) and Server classes above so you can do something like `server.generate_keys!`.
|
75
|
+
|
76
|
+
### Default key properties
|
77
|
+
|
78
|
+
You will probably need to set key properties when generating keys. There are some
|
79
|
+
defaults already set and they can be seen by calling `Properties#default` (but are listed here for brevity):
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
> Net::Openvpn::Generators::Keys::Properties.default
|
83
|
+
{
|
84
|
+
:easy_rsa => "/usr/share/easy-rsa",
|
85
|
+
:openssl => "openssl",
|
86
|
+
:pkcs11tool => "pkcs11-tool",
|
87
|
+
:grep => "grep",
|
88
|
+
:key_dir => "/etc/openvpn/keys",
|
89
|
+
:key_dir_owner => "root",
|
90
|
+
:key_dir_group => "root",
|
91
|
+
:key_dir_permission => "700",
|
92
|
+
:pkcs11_module_path => "changeme",
|
93
|
+
:pkcs11_pin => 1234,
|
94
|
+
:key_size => 1024,
|
95
|
+
:ca_expire => 3650,
|
96
|
+
:key_expire => 3650,
|
97
|
+
:key_country => "US",
|
98
|
+
:key_province => "CA",
|
99
|
+
:key_city => "SanFrancisco",
|
100
|
+
:key_org => "Fort-Funston",
|
101
|
+
:key_email => "me@myhost.mydomain",
|
102
|
+
:key_cn => "changeme",
|
103
|
+
:key_name => "changeme",
|
104
|
+
:key_ou => "changeme",
|
105
|
+
:key_config => "/usr/share/easy-rsa/openssl-1.0.0.cnf",
|
106
|
+
:key_index => "/etc/openvpn/keys/index.txt"
|
107
|
+
}
|
108
|
+
```
|
109
|
+
|
110
|
+
### Overriding key properties globally
|
111
|
+
|
112
|
+
Key properties can be overidden by creating the file: `/etc/openvpn/props.yml`
|
113
|
+
|
114
|
+
In this way you can override the default `openssl.cnf` file, the location of your
|
115
|
+
`easy-rsa` folder, key size or any properties listed above!
|
116
|
+
|
117
|
+
```yml
|
118
|
+
---
|
119
|
+
:easy_rsa: /usr/share/doc/openvpn/examples/easy-rsa/2.0
|
120
|
+
:key_config: /path/to/openssl.cnf
|
121
|
+
:key_dir: /path/to/generated/keys
|
122
|
+
```
|
123
|
+
|
124
|
+
Properties set in the YAML file will override the default ones. You can see which properties are specified in the YAML file by checking the `Properties#yaml`.
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
> Net::Openvpn::Generators::Keys::Properties.default
|
128
|
+
{
|
129
|
+
:easy_rsa => "/usr/share/doc/openvpn/examples/easy-rsa/2.0",
|
130
|
+
:key_config => "/path/to/openssl.cnf",
|
131
|
+
:key_dir => "/path/to/generated/keys"
|
132
|
+
}
|
133
|
+
```
|
134
|
+
|
135
|
+
But really you should use `Net::Openvpn#props` to get properties because that will merge the defaults with the properties from the YAML file, the latter overriding keys in the former.
|
136
|
+
|
137
|
+
### Overriding key properties at generation time
|
138
|
+
|
139
|
+
You can also provide key properties when you do the actual generation of the keys as
|
140
|
+
described below. These properties will override properties set in the YAML file.
|
141
|
+
|
142
|
+
These properties can be supplied directly to the `Authority`, `Client`, `Server` and `Directory` classes in the `Generators::Keys` module as arguments to the `new` method:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
Net::Openvpn::Generators::Keys::Directory.new key_dir_permission: 0770
|
146
|
+
|
147
|
+
Net::Openvpn::Generators::Keys::Authority.new key_size: 8192 # this will take hours lol
|
148
|
+
|
149
|
+
Net::Openvpn::Generators::Keys::Client.new(
|
150
|
+
"fred",
|
151
|
+
key_country: "Switzerland",
|
152
|
+
key_province: "Romandy",
|
153
|
+
key_city: "Geneva",
|
154
|
+
key_email: "fred@example.com"
|
155
|
+
)
|
156
|
+
|
157
|
+
Net::Openvpn::Generators::Keys::Server.new(
|
158
|
+
"norvpn01",
|
159
|
+
key_country: "Norway",
|
160
|
+
key_province: "Ostlandet",
|
161
|
+
key_city: "Oslo",
|
162
|
+
key_email: "admin@example.com"
|
163
|
+
)
|
164
|
+
```
|
165
|
+
|
166
|
+
### Key Directory
|
167
|
+
|
168
|
+
To start with the first thing you will need to do is setup the key directory. This can be done with the following line:
|
169
|
+
|
170
|
+
```ruby
|
171
|
+
# keys = Net::Openvpn.generator(:directory).new
|
172
|
+
key_dir = Net::Openvpn::Generators::Keys::Directory.new
|
173
|
+
key_dir.generate
|
174
|
+
key_dir.exist? # check that it worked
|
175
|
+
```
|
176
|
+
|
177
|
+
This should generate the following files/folders:
|
178
|
+
|
179
|
+
* /etc/openvpn/keys
|
180
|
+
* /etc/openvpn/keys/index.txt
|
181
|
+
* /etc/openvpn/keys/serial
|
182
|
+
|
183
|
+
### Certificate Authority
|
184
|
+
|
185
|
+
You will also need to generate the certificate authority and DH key like so.
|
186
|
+
|
187
|
+
```ruby
|
188
|
+
# keys = Net::Openvpn.generator(:authority).new
|
189
|
+
ca = Net::Openvpn::Generators::Keys::Authority.new
|
190
|
+
ca.generate
|
191
|
+
ca.exist?
|
192
|
+
```
|
193
|
+
|
194
|
+
This should generate the following files/folders:
|
195
|
+
|
196
|
+
* /etc/openvpn/keys
|
197
|
+
* /etc/openvpn/keys/ca.crt
|
198
|
+
* /etc/openvpn/keys/ca.key
|
199
|
+
* /etc/openvpn/keys/dh1024.pem
|
200
|
+
|
201
|
+
### Servers
|
202
|
+
|
203
|
+
```ruby
|
204
|
+
# keys = Net::Openvpn.generator(:server).new("swzvpn04")
|
205
|
+
keys = Net::Openvpn::Generators::Keys::Server.new("swzvpn04")
|
206
|
+
keys.generate
|
207
|
+
keys.exist? # returns true if the key files exist
|
208
|
+
keys.valid? # returns true if the keys are valid in the index
|
209
|
+
```
|
210
|
+
|
211
|
+
This should generate the following files/folders:
|
212
|
+
|
213
|
+
* /etc/openvpn/keys
|
214
|
+
* /etc/openvpn/keys/swzvpn04.key
|
215
|
+
* /etc/openvpn/keys/swzvpn04.crt
|
216
|
+
|
217
|
+
### Clients
|
218
|
+
|
219
|
+
```ruby
|
220
|
+
# keys = Net::Openvpn.generator(:client).new("fred")
|
221
|
+
keys = Net::Openvpn::Generators::Keys::Client.new("fred")
|
222
|
+
keys.generate
|
223
|
+
keys.exist? # returns true if the key files exist
|
224
|
+
keys.valid? # returns true if the keys are valid in the index
|
225
|
+
```
|
226
|
+
|
227
|
+
This should generate the following files/folders:
|
228
|
+
|
229
|
+
* /etc/openvpn/keys
|
230
|
+
* /etc/openvpn/keys/fred.key
|
231
|
+
* /etc/openvpn/keys/fred.crt
|
232
|
+
|
233
|
+
Revoke the keys like so (UNTESTED!):
|
234
|
+
|
235
|
+
```ruby
|
236
|
+
keys = Net::Openvpn::Generators::Keys::Client.new("fred")
|
237
|
+
keys.revoke!
|
238
|
+
keys.valid? # returns false
|
239
|
+
```
|
240
|
+
|
55
241
|
## Rails Permissions
|
56
242
|
|
57
243
|
If you are running rails and you want to give the rails user access, you could do it like this:
|
@@ -64,4 +250,12 @@ chmod o-rwx /etc/openvpn -R
|
|
64
250
|
cd /etc/openvpn
|
65
251
|
chmod g-rwx easy-rsa *.key *.crt *.pem
|
66
252
|
usermod -aG openvpn rails-app-user
|
253
|
+
```
|
254
|
+
|
255
|
+
Then override the following properties in your `/etc/openvpn/props.yml` file:
|
256
|
+
|
257
|
+
```yaml
|
258
|
+
---
|
259
|
+
:key_dir_group: "openvpn"
|
260
|
+
:key_dir_permission: 0700
|
67
261
|
```
|
data/lib/net/openvpn.rb
CHANGED
@@ -1,8 +1,18 @@
|
|
1
|
+
require 'fileutils'
|
2
|
+
|
1
3
|
require 'net/openvpn/server'
|
2
4
|
require 'net/openvpn/host'
|
5
|
+
require 'net/openvpn/errors'
|
3
6
|
require 'net/openvpn/client_config'
|
4
7
|
require 'net/openvpn/parser/server_config'
|
5
8
|
|
9
|
+
require 'net/openvpn/generators/keys/base'
|
10
|
+
require 'net/openvpn/generators/keys/directory'
|
11
|
+
require 'net/openvpn/generators/keys/client'
|
12
|
+
require 'net/openvpn/generators/keys/server'
|
13
|
+
require 'net/openvpn/generators/keys/properties'
|
14
|
+
require 'net/openvpn/generators/keys/authority'
|
15
|
+
|
6
16
|
module Net
|
7
17
|
module Openvpn
|
8
18
|
class << self
|
@@ -25,6 +35,27 @@ module Net
|
|
25
35
|
Net::Openvpn::Server.new(name)
|
26
36
|
end
|
27
37
|
|
38
|
+
def generator(type)
|
39
|
+
case type
|
40
|
+
when :client
|
41
|
+
Net::Openvpn::Generators::Keys::Client
|
42
|
+
when :server
|
43
|
+
Net::Openvpn::Generators::Keys::Server
|
44
|
+
when :directory
|
45
|
+
Net::Openvpn::Generators::Keys::Directory
|
46
|
+
when :authority
|
47
|
+
Net::Openvpn::Generators::Keys::Authority
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# Returns the default key properties merged with
|
52
|
+
# the properties stored in /etc/openvpn/props.yml
|
53
|
+
def props
|
54
|
+
props = Openvpn::Generators::Keys::Properties
|
55
|
+
|
56
|
+
props.default.merge props.yaml
|
57
|
+
end
|
58
|
+
|
28
59
|
end
|
29
60
|
end
|
30
|
-
end
|
61
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
module Net
|
2
|
+
module Openvpn
|
3
|
+
module Generators
|
4
|
+
module Keys
|
5
|
+
class Authority < Base
|
6
|
+
|
7
|
+
def initialize(**props)
|
8
|
+
super(nil, props)
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate
|
12
|
+
@key_dir.exist? or raise Errors::KeyGeneration, "Key directory has not been generated yet"
|
13
|
+
!exist? or raise Errors::KeyGeneration, "Authority already exists!"
|
14
|
+
|
15
|
+
FileUtils.cd(@props[:easy_rsa]) do
|
16
|
+
system "#{cli_prop_vars} ./pkitool --initca"
|
17
|
+
system "#{cli_prop_vars} ./build-dh"
|
18
|
+
end
|
19
|
+
|
20
|
+
true
|
21
|
+
end
|
22
|
+
|
23
|
+
def filepaths
|
24
|
+
[
|
25
|
+
"#{@props[:key_dir]}/ca.key",
|
26
|
+
"#{@props[:key_dir]}/ca.crt",
|
27
|
+
"#{@props[:key_dir]}/dh#{@props[:key_size]}.pem"
|
28
|
+
]
|
29
|
+
end
|
30
|
+
|
31
|
+
def self.exist?
|
32
|
+
Authority.new.exist?
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,87 @@
|
|
1
|
+
module Net
|
2
|
+
module Openvpn
|
3
|
+
module Generators
|
4
|
+
module Keys
|
5
|
+
class Base
|
6
|
+
def initialize(name, props)
|
7
|
+
@name = name
|
8
|
+
@props = Openvpn.props.merge props
|
9
|
+
@props[:key_cn] = @name
|
10
|
+
@key_dir = Directory.new(@props)
|
11
|
+
|
12
|
+
Properties.validate! @props
|
13
|
+
end
|
14
|
+
|
15
|
+
def generate
|
16
|
+
raise NotImplementedError
|
17
|
+
end
|
18
|
+
|
19
|
+
# Returns true if all the generated keys exist or false if not
|
20
|
+
def exist?
|
21
|
+
filepaths.each do |file|
|
22
|
+
return false if !File.exist? file
|
23
|
+
end
|
24
|
+
true
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns true if the generated keys are valid by checking
|
28
|
+
# the key index and then checking the pemfile against the crt
|
29
|
+
# file.
|
30
|
+
def valid?
|
31
|
+
# read the index file
|
32
|
+
m = File.read(Openvpn.props[:key_index]).match /^V.*CN=#{@name}.*$/
|
33
|
+
|
34
|
+
return false if m.nil?
|
35
|
+
|
36
|
+
# get the pem number and build the paths
|
37
|
+
pem = m[0].split("\t")[3]
|
38
|
+
pem_path = "#{Openvpn.props[:key_dir]}/#{pem}.pem"
|
39
|
+
crt_path = "#{Openvpn.props[:key_dir]}/#{@name}.crt"
|
40
|
+
|
41
|
+
# Check the pem against the current cert for the name
|
42
|
+
File.read(pem_path) == File.read(crt_path)
|
43
|
+
end
|
44
|
+
|
45
|
+
# Revokes the keys
|
46
|
+
#
|
47
|
+
# Returns true if the keys were revoked or false if the keys do
|
48
|
+
# not exist or are not valid
|
49
|
+
#
|
50
|
+
# raises `Net::Openvpn::Errors::CertificateRevocation` if the key
|
51
|
+
# failed to be revoked
|
52
|
+
#
|
53
|
+
def revoke!
|
54
|
+
return false unless exist? and valid?
|
55
|
+
|
56
|
+
FileUtils.cd(Openvpn.props[:easy_rsa]) do
|
57
|
+
output = %x[#{cli_prop_vars} ./revoke-full #{@name}]
|
58
|
+
raise Errors::CertificateRevocation, "Revoke command failed" if !output.include? "error 23" # error 23 means key was revoked
|
59
|
+
end
|
60
|
+
|
61
|
+
!valid? or raise Errors::CertificateRevocation, "Certificates were still valid after being revoked"
|
62
|
+
|
63
|
+
true
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
|
68
|
+
# Generates the variable string of key properties
|
69
|
+
# to preceed easy-rsa script calls
|
70
|
+
#
|
71
|
+
# An example with just two properties:
|
72
|
+
#
|
73
|
+
# EASY_RSA="/usr/share/easy-rsa" KEY_CN="fred" build-key ...
|
74
|
+
#
|
75
|
+
def cli_prop_vars
|
76
|
+
Properties.to_cli_vars(@props)
|
77
|
+
end
|
78
|
+
|
79
|
+
def filepaths
|
80
|
+
raise NotImplementedError
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
module Net
|
2
|
+
module Openvpn
|
3
|
+
module Generators
|
4
|
+
module Keys
|
5
|
+
class Client < Base
|
6
|
+
|
7
|
+
def initialize(name, **props)
|
8
|
+
super(name, props)
|
9
|
+
end
|
10
|
+
|
11
|
+
# Generates the certificates for a VPN client
|
12
|
+
#
|
13
|
+
# Raises `Net::Openvpn::Errors::KeyGeneration` if there were problems
|
14
|
+
#
|
15
|
+
# Returns true if the generation was successful
|
16
|
+
#
|
17
|
+
def generate
|
18
|
+
@key_dir.exist? or raise Errors::KeyGeneration, "Key directory has not been generated yet"
|
19
|
+
Authority.exist? or raise Errors::KeyGeneration, "Certificate Authority has not been created"
|
20
|
+
|
21
|
+
revoke! if exist? and valid?
|
22
|
+
|
23
|
+
FileUtils.cd(@props[:easy_rsa]) do
|
24
|
+
system "#{cli_prop_vars} ./pkitool #{@name}"
|
25
|
+
end
|
26
|
+
|
27
|
+
exist? or raise Errors::KeyGeneration, "Keys do not exist"
|
28
|
+
valid? or raise Errors::KeyGeneration, "keys are not valid"
|
29
|
+
|
30
|
+
true
|
31
|
+
end
|
32
|
+
|
33
|
+
# Returns an array containing the paths to the generated keys
|
34
|
+
def filepaths
|
35
|
+
[
|
36
|
+
"#{@props[:key_dir]}/#{@name}.key",
|
37
|
+
"#{@props[:key_dir]}/#{@name}.crt"
|
38
|
+
]
|
39
|
+
end
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module Net
|
2
|
+
module Openvpn
|
3
|
+
module Generators
|
4
|
+
module Keys
|
5
|
+
class Directory
|
6
|
+
|
7
|
+
def initialize(**props)
|
8
|
+
@props = Openvpn.props.merge props
|
9
|
+
end
|
10
|
+
|
11
|
+
def exist?
|
12
|
+
File.directory?(@props[:key_dir]) and
|
13
|
+
File.exist?(@props[:key_index]) and
|
14
|
+
File.exist?("#{@props[:key_dir]}/serial")
|
15
|
+
end
|
16
|
+
|
17
|
+
# Sets up the directory where keys are to be generated.
|
18
|
+
# Also creates the serial and index.txt used by the pkitool
|
19
|
+
# that comes with easy-rsa
|
20
|
+
def generate
|
21
|
+
|
22
|
+
FileUtils.mkdir_p @props[:key_dir] unless
|
23
|
+
File.directory? @props[:key_dir]
|
24
|
+
|
25
|
+
FileUtils.cd(@props[:key_dir]) do
|
26
|
+
FileUtils.touch @props[:key_index]
|
27
|
+
File.open("serial", "w") {|f| f.write "01" }
|
28
|
+
end
|
29
|
+
|
30
|
+
FileUtils.chown_R(
|
31
|
+
@props[:key_dir_owner],
|
32
|
+
@props[:key_dir_group],
|
33
|
+
@props[:key_dir]
|
34
|
+
)
|
35
|
+
|
36
|
+
FileUtils.chmod_R(
|
37
|
+
@props[:key_dir_permission],
|
38
|
+
@props[:key_dir]
|
39
|
+
)
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
module Net
|
2
|
+
module Openvpn
|
3
|
+
module Generators
|
4
|
+
module Keys
|
5
|
+
module Properties
|
6
|
+
class << self
|
7
|
+
|
8
|
+
# Returns the properties loaded from a YAML file
|
9
|
+
# located in /etc/openvpn/props.yml
|
10
|
+
def yaml
|
11
|
+
return {} unless File.exist? Openvpn.basepath "props.yml"
|
12
|
+
YAML.load(File.read(Openvpn.basepath "props.yml"))
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns the default set of properties as per the easy-rsa
|
16
|
+
# 'vars' script
|
17
|
+
def default
|
18
|
+
props = {
|
19
|
+
easy_rsa: "/usr/share/easy-rsa",
|
20
|
+
openssl: "openssl",
|
21
|
+
pkcs11tool: "pkcs11-tool",
|
22
|
+
grep: "grep",
|
23
|
+
key_dir: "#{Openvpn.basepath}/keys",
|
24
|
+
key_dir_owner: "root",
|
25
|
+
key_dir_group: "root",
|
26
|
+
key_dir_permission: 0700,
|
27
|
+
pkcs11_module_path: "dummy",
|
28
|
+
pkcs11_pin: "dummy",
|
29
|
+
key_size: 1024,
|
30
|
+
ca_expire: 3650,
|
31
|
+
key_expire: 3650,
|
32
|
+
key_country: "US",
|
33
|
+
key_province: "CA",
|
34
|
+
key_city: "SanFrancisco",
|
35
|
+
key_org: "Fort-Funston",
|
36
|
+
key_email: "me@myhost.mydomain",
|
37
|
+
key_cn: "changeme",
|
38
|
+
key_name: "changeme",
|
39
|
+
key_ou: "changeme",
|
40
|
+
pkcs11_module_path: "changeme",
|
41
|
+
pkcs11_pin: 1234
|
42
|
+
}
|
43
|
+
|
44
|
+
props[:key_config] = "#{props[:easy_rsa]}/openssl-1.0.0.cnf"
|
45
|
+
props[:key_index] = "#{props[:key_dir]}/index.txt"
|
46
|
+
|
47
|
+
props
|
48
|
+
end
|
49
|
+
|
50
|
+
alias_method :defaults, :default # POLS
|
51
|
+
|
52
|
+
# Ensures that all the required properties are available to
|
53
|
+
# stop the easy-rsa scripts having a cry
|
54
|
+
def validate!(props)
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
# Creates a list of variables to preceed a bash command
|
59
|
+
def to_cli_vars(props)
|
60
|
+
string = ""
|
61
|
+
props.each do |key, value|
|
62
|
+
prop = key.to_s.upcase
|
63
|
+
string+= "#{prop}=\"#{value}\" "
|
64
|
+
end
|
65
|
+
"export #{string}; "
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Net
|
2
|
+
module Openvpn
|
3
|
+
module Generators
|
4
|
+
module Keys
|
5
|
+
class Server < Base
|
6
|
+
|
7
|
+
def initialize(name, **props)
|
8
|
+
super(name, props)
|
9
|
+
end
|
10
|
+
|
11
|
+
def generate
|
12
|
+
@key_dir.exist? or raise Errors::KeyGeneration, "Key directory has not been generated yet"
|
13
|
+
Authority.exist? or raise Errors::KeyGeneration, "Certificate Authority has not been created"
|
14
|
+
|
15
|
+
revoke! if exist? and valid?
|
16
|
+
|
17
|
+
FileUtils.cd(@props[:easy_rsa]) do
|
18
|
+
system "#{cli_prop_vars} ./pkitool --server #{@name}"
|
19
|
+
end
|
20
|
+
|
21
|
+
exist? or raise Openvpn::Errors::KeyGeneration, "Keys do not exist"
|
22
|
+
valid? or raise Openvpn::Errors::KeyGeneration, "keys are not valid"
|
23
|
+
|
24
|
+
end
|
25
|
+
|
26
|
+
def filepaths
|
27
|
+
[
|
28
|
+
"#{@props[:key_dir]}/#{@name}.key",
|
29
|
+
"#{@props[:key_dir]}/#{@name}.crt"
|
30
|
+
]
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/lib/net/openvpn/version.rb
CHANGED
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Net::Openvpn::Generators::Keys::Client do
|
4
|
+
subject(:client) { Net::Openvpn::Generators::Keys::Client.new(name, props) }
|
5
|
+
let(:directory) { Net::Openvpn::Generators::Keys::Directory.new }
|
6
|
+
let(:authority) { Net::Openvpn::Generators::Keys::Authority }
|
7
|
+
let(:name) { "test" }
|
8
|
+
let(:props) { {} }
|
9
|
+
|
10
|
+
before(:each) { setup_filesystem(:tmp) }
|
11
|
+
after(:each) { destroy_filesystem(:tmp) }
|
12
|
+
|
13
|
+
context "when a client has not been generated" do
|
14
|
+
it "should not exist" do
|
15
|
+
expect(client).to_not exist
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when the key directory has not been generated" do
|
20
|
+
|
21
|
+
it "should raise an error" do
|
22
|
+
expect { client.generate }.to raise_error(
|
23
|
+
Net::Openvpn::Errors::KeyGeneration,
|
24
|
+
"Key directory has not been generated yet"
|
25
|
+
)
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
context "when the key directory has been generated" do
|
31
|
+
before(:each) { directory.generate }
|
32
|
+
|
33
|
+
context "and the authority has not been generated" do
|
34
|
+
before(:each) { expect(authority).to_not exist }
|
35
|
+
|
36
|
+
it "should raise an error" do
|
37
|
+
expect { client.generate }.to raise_error(
|
38
|
+
Net::Openvpn::Errors::KeyGeneration,
|
39
|
+
"Certificate Authority has not been created"
|
40
|
+
)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "and the authority has been generated" do
|
45
|
+
before(:each) do
|
46
|
+
authority.new.generate
|
47
|
+
expect(authority).to exist
|
48
|
+
end
|
49
|
+
|
50
|
+
context "and the client has not been generated" do
|
51
|
+
it "should not exist" do
|
52
|
+
expect(client).to_not exist
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should not be valid" do
|
56
|
+
expect(client).to_not be_valid
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context "and the client has been generated" do
|
61
|
+
before(:each) do
|
62
|
+
client.generate
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should exist" do
|
66
|
+
expect(client).to exist
|
67
|
+
end
|
68
|
+
|
69
|
+
it "should be valid" do
|
70
|
+
expect(client).to be_valid
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Net::Openvpn::Generators::Keys::Directory, fakefs: true do
|
4
|
+
subject(:dir) { Net::Openvpn::Generators::Keys::Directory.new(props) }
|
5
|
+
let(:props) { {} }
|
6
|
+
|
7
|
+
before(:each) { setup_filesystem(:fake) }
|
8
|
+
|
9
|
+
it "should exist after generation" do
|
10
|
+
dir.generate
|
11
|
+
expect(dir).to exist
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should create the key dir folder" do
|
15
|
+
dir.generate
|
16
|
+
expect(File.exist? "/etc/openvpn/keys").to be_true
|
17
|
+
end
|
18
|
+
|
19
|
+
context "when the key dir property is changed" do
|
20
|
+
let(:props) { { key_dir: "/etc/openvpn/my_keys", key_index: "/etc/openvpn/my_keys/index.txt" } }
|
21
|
+
it "should create the key dir folder" do
|
22
|
+
dir.generate
|
23
|
+
expect(File.exist? "/etc/openvpn/my_keys").to be_true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Net::Openvpn::Generators::Keys::Properties, fakefs: true do
|
4
|
+
subject(:properties) { Net::Openvpn::Generators::Keys::Properties }
|
5
|
+
subject(:defaults) { properties.defaults }
|
6
|
+
subject(:yaml) { properties.yaml }
|
7
|
+
|
8
|
+
context "when there is no props.yml file" do
|
9
|
+
it "should have key size of 1024 from defaults" do
|
10
|
+
expect(defaults[:key_size]).to eq 1024
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should have empty hash from yaml" do
|
14
|
+
expect(yaml).to be_empty
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "when there is a props.yml file" do
|
19
|
+
before(:each) { setup_filesystem(:fake) }
|
20
|
+
|
21
|
+
it "should have key size of 384 from yaml" do
|
22
|
+
expect(yaml[:key_size]).to eq 384
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should have key size of 1024 from defaults" do
|
26
|
+
expect(defaults[:key_size]).to eq 1024
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,44 @@
|
|
1
1
|
require 'net/openvpn'
|
2
2
|
require 'fakefs/spec_helpers'
|
3
|
+
require 'yaml'
|
3
4
|
|
4
5
|
RSpec.configure do |config|
|
5
6
|
config.include FakeFS::SpecHelpers, fakefs: true
|
7
|
+
end
|
8
|
+
|
9
|
+
def setup_overrides(path)
|
10
|
+
|
11
|
+
overrides = {
|
12
|
+
key_dir_owner: ENV["USER"],
|
13
|
+
key_dir_group: ENV["USER"],
|
14
|
+
key_permission: 0770,
|
15
|
+
key_size: 384 # tiny key to speed up the tests
|
16
|
+
}
|
17
|
+
|
18
|
+
File.open("#{path}/props.yml", "w") { |f| f.write overrides.to_yaml }
|
19
|
+
|
20
|
+
end
|
21
|
+
|
22
|
+
def stub_basepath
|
23
|
+
Net::Openvpn.stub(:basepath) do |path|
|
24
|
+
path = "/#{path}" unless path.nil?
|
25
|
+
"/tmp/openvpn#{path}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def setup_filesystem(type)
|
30
|
+
case type
|
31
|
+
when :fake
|
32
|
+
FakeFS::FileSystem.clone "/usr/share/easy-rsa"
|
33
|
+
FileUtils.mkdir_p "/etc/openvpn"
|
34
|
+
setup_overrides "/etc/openvpn"
|
35
|
+
when :tmp
|
36
|
+
FileUtils.mkdir_p "/tmp/openvpn"
|
37
|
+
setup_overrides "/tmp/openvpn"
|
38
|
+
stub_basepath
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def destroy_filesystem(type)
|
43
|
+
FileUtils.rm_rf "/tmp/openvpn"
|
6
44
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: net-openvpn
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: '0.
|
4
|
+
version: '0.8'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Robert McLeod
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -88,17 +88,29 @@ extensions: []
|
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
90
|
- ".gitignore"
|
91
|
+
- ".ruby-gemset"
|
92
|
+
- ".ruby-version"
|
91
93
|
- Gemfile
|
92
94
|
- Gemfile.lock
|
93
95
|
- README.md
|
94
96
|
- Rakefile
|
95
97
|
- lib/net/openvpn.rb
|
96
98
|
- lib/net/openvpn/client_config.rb
|
99
|
+
- lib/net/openvpn/errors.rb
|
100
|
+
- lib/net/openvpn/generators/keys/authority.rb
|
101
|
+
- lib/net/openvpn/generators/keys/base.rb
|
102
|
+
- lib/net/openvpn/generators/keys/client.rb
|
103
|
+
- lib/net/openvpn/generators/keys/directory.rb
|
104
|
+
- lib/net/openvpn/generators/keys/properties.rb
|
105
|
+
- lib/net/openvpn/generators/keys/server.rb
|
97
106
|
- lib/net/openvpn/host.rb
|
98
107
|
- lib/net/openvpn/parser/server_config.rb
|
99
108
|
- lib/net/openvpn/server.rb
|
100
109
|
- lib/net/openvpn/version.rb
|
101
110
|
- net-openvpn.gemspec
|
111
|
+
- spec/lib/net/openvpn/generators/keys/client_spec.rb
|
112
|
+
- spec/lib/net/openvpn/generators/keys/directory_spec.rb
|
113
|
+
- spec/lib/net/openvpn/generators/keys/properties_spec.rb
|
102
114
|
- spec/lib/net/openvpn/host_spec.rb
|
103
115
|
- spec/spec_helper.rb
|
104
116
|
homepage: https://github.com/penguinpowernz/net-openvpn
|