net-openvpn 0.3 → 0.8
Sign up to get free protection for your applications and to get access to all the features.
- 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
|