ssh_keygen 1.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.kitchen.yml +10 -0
- data/.rubocop.yml +7 -0
- data/Berksfile +24 -0
- data/CHANGELOG.md +7 -0
- data/Gemfile +17 -0
- data/LICENSE +13 -0
- data/README.md +77 -0
- data/Rakefile +15 -0
- data/lib/ssh_keygen.rb +58 -0
- data/lib/ssh_keygen/cheftie.rb +15 -0
- data/lib/ssh_keygen/provider.rb +126 -0
- data/lib/ssh_keygen/version.rb +17 -0
- data/ssh_keygen.gemspec +38 -0
- data/test/cookbooks/ssh_keygen_test/metadata.rb +16 -0
- data/test/cookbooks/ssh_keygen_test/recipes/with_passphrase.rb +22 -0
- data/test/cookbooks/ssh_keygen_test/recipes/with_user_opts.rb +35 -0
- data/test/cookbooks/ssh_keygen_test/recipes/without_passphrase.rb +21 -0
- data/test/integration/default/serverspec/spec_helper.rb +18 -0
- data/test/integration/default/serverspec/with_passphrase_spec.rb +35 -0
- data/test/integration/default/serverspec/with_user_opts_spec.rb +44 -0
- data/test/integration/default/serverspec/without_passphrase_spec.rb +36 -0
- data/test/spec/resources/ssh_keygen_spec.rb +129 -0
- data/test/spec/spec_helper.rb +24 -0
- metadata +121 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 169b68c69d1b643d3e0b34ac0d3f4706b5b9137e
|
4
|
+
data.tar.gz: 34f58971d4057d3a45b5dbdd939d4a64af75ed61
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: b7edf36a70811a8ea3d3c45abdd2221a7f8851fdaa324df012572c5f15807c399b18541ededf623f8089a031c9d2e36174d1aefd2dddf7b43721ca3e231218f7
|
7
|
+
data.tar.gz: e5c208abd0450bc17909e8bf369c4d50b2ce4405c5404c015e0d79c951359cea3e71c6e2488b850b5526fd2f5c7ebbe0ce42081721833b5be350b09f6956fa96
|
data/.gitignore
ADDED
data/.kitchen.yml
ADDED
data/.rubocop.yml
ADDED
data/Berksfile
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
source 'https://supermarket.chef.io'
|
16
|
+
extension 'halite'
|
17
|
+
|
18
|
+
cookbook 'poise', gem: 'poise'
|
19
|
+
cookbook 'ssh_keygen', gem: 'ssh_keygen'
|
20
|
+
|
21
|
+
group :test do
|
22
|
+
cookbook 'ssh_keygen_test', path: 'test/cookbooks/ssh_keygen_test'
|
23
|
+
cookbook 'apt'
|
24
|
+
end
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
source 'https://rubygems.org'
|
16
|
+
|
17
|
+
gemspec
|
data/LICENSE
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
data/README.md
ADDED
@@ -0,0 +1,77 @@
|
|
1
|
+
[![Cookbook Version](https://img.shields.io/cookbook/v/ssh_keygen.svg)](https://supermarket.chef.io/cookbooks/ssh_keygen)
|
2
|
+
|
3
|
+
# ssh_keygen Chef Resource
|
4
|
+
|
5
|
+
This single-purpose cookbook provides a resource to create SSH keys, as you
|
6
|
+
would expect to be created with `ssh-keygen`.
|
7
|
+
|
8
|
+
## Usage and Example
|
9
|
+
|
10
|
+
Say you wanted to create a user (named after `test-kitchen`) and create an
|
11
|
+
SSH key for it:
|
12
|
+
|
13
|
+
```
|
14
|
+
group 'kitchen' do
|
15
|
+
action :create
|
16
|
+
end
|
17
|
+
|
18
|
+
user 'kitchen' do
|
19
|
+
action :create
|
20
|
+
group 'kitchen'
|
21
|
+
home '/home/kitchen'
|
22
|
+
manage_home true
|
23
|
+
end
|
24
|
+
|
25
|
+
directory '/home/kitchen/.ssh' do
|
26
|
+
action :create
|
27
|
+
end
|
28
|
+
|
29
|
+
ssh_keygen '/home/kitchen/.ssh/id_rsa' do
|
30
|
+
action :create
|
31
|
+
owner 'kitchen'
|
32
|
+
group 'kitchen'
|
33
|
+
strength 4096
|
34
|
+
type 'rsa'
|
35
|
+
comment 'kitchen@localhost'
|
36
|
+
passphrase 'changeme'
|
37
|
+
secure_directory true
|
38
|
+
end
|
39
|
+
```
|
40
|
+
|
41
|
+
The following would (after creating the `kitchen` user), generate an SSH private
|
42
|
+
key in `/home/kitchen/.ssh/id_rsa`, a public key in OpenSSH format in
|
43
|
+
`/home/kitchen/.ssh/id_rsa.pub`, and ensure the `.ssh` directory has secure
|
44
|
+
permissions as well (so mode `0700`).
|
45
|
+
|
46
|
+
### Attributes
|
47
|
+
|
48
|
+
The attributes for the `ssh_keygen` resource are:
|
49
|
+
|
50
|
+
* `action`: Only `:create` is supported.
|
51
|
+
* `path`: The path to save the SSH key to (if different from the resource name).
|
52
|
+
* `owner`: The owner of the private and public key files.
|
53
|
+
* `group`: The group ID for the private and public key files.
|
54
|
+
* `strength`: Only `2048` and `4096` are supported currently, default is `2048`.
|
55
|
+
* `type`: Only `rsa` is supported currently.
|
56
|
+
Ed25519 may be supported in future versions (feature request welcome!)
|
57
|
+
* `comment`: Comment for the public key. Defaults to `user@host`.
|
58
|
+
* `passphrase`: Passphrase for an encrypted private key. The default is no passphrase.
|
59
|
+
* `secure_directory`: Sets the directory the key is saved in to mode to `0700`.
|
60
|
+
|
61
|
+
## Author and License
|
62
|
+
|
63
|
+
```
|
64
|
+
Copyright 2015 Chris Marchesi
|
65
|
+
|
66
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
67
|
+
you may not use this file except in compliance with the License.
|
68
|
+
You may obtain a copy of the License at
|
69
|
+
|
70
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
71
|
+
|
72
|
+
Unless required by applicable law or agreed to in writing, software
|
73
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
74
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
75
|
+
See the License for the specific language governing permissions and
|
76
|
+
limitations under the License.
|
77
|
+
```
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'poise_boiler/rakefile'
|
data/lib/ssh_keygen.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'poise'
|
16
|
+
require 'chef/resource'
|
17
|
+
require 'chef/provider'
|
18
|
+
require 'ssh_keygen/provider'
|
19
|
+
|
20
|
+
# resource and provider classes for the ssh_keygen Chef resource
|
21
|
+
module SSHKeygen
|
22
|
+
# resource class for ssh_keygen resource
|
23
|
+
class Resource < Chef::Resource
|
24
|
+
include Poise
|
25
|
+
provides(:ssh_keygen)
|
26
|
+
actions(:create)
|
27
|
+
|
28
|
+
attribute(:path, kind_of: String, name_attribute: true)
|
29
|
+
attribute(:owner, kind_of: String, default: 'root')
|
30
|
+
attribute(:group, kind_of: String, default: lazy { owner })
|
31
|
+
attribute(:strength, equal_to: [2048, 4096], default: 2048)
|
32
|
+
# future proofing - but RSA only for now
|
33
|
+
attribute(:type, equal_to: ['rsa'], default: 'rsa')
|
34
|
+
attribute(:comment, kind_of: String, default: lazy { "#{owner}@#{node['hostname']}" })
|
35
|
+
attribute(:passphrase, kind_of: String, default: nil)
|
36
|
+
attribute(:secure_directory, kind_of: TrueClass, default: false)
|
37
|
+
end
|
38
|
+
|
39
|
+
# provider class for ssh_keygen resource
|
40
|
+
class Provider < Chef::Provider
|
41
|
+
include Poise
|
42
|
+
include SSHKeygen::SSHKeygenProvider
|
43
|
+
provides(:ssh_keygen)
|
44
|
+
|
45
|
+
def action_create
|
46
|
+
# load_sshkey_gem
|
47
|
+
notifying_block do
|
48
|
+
unless ::File.exist?(@new_resource.path)
|
49
|
+
create_key
|
50
|
+
save_private_key
|
51
|
+
save_public_key
|
52
|
+
update_directory_permissions
|
53
|
+
new_resource.updated_by_last_action(true)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'ssh_keygen'
|
@@ -0,0 +1,126 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'openssl'
|
16
|
+
require 'base64'
|
17
|
+
|
18
|
+
module SSHKeygen
|
19
|
+
# Lightweight SSH key generator
|
20
|
+
class Generator
|
21
|
+
def initialize(bits, type, passphrase, comment)
|
22
|
+
# set instance attributes
|
23
|
+
@passphrase = passphrase
|
24
|
+
@comment = comment
|
25
|
+
@type = type
|
26
|
+
|
27
|
+
case @type
|
28
|
+
when 'rsa'
|
29
|
+
@key = ::OpenSSL::PKey::RSA.new(bits)
|
30
|
+
else
|
31
|
+
fail "Invalid key type #{new_resource.type}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# return the public key (encrypted if passphrase is given), in PEM form
|
36
|
+
def private_key
|
37
|
+
if @passphrase.to_s.empty?
|
38
|
+
@key.to_pem
|
39
|
+
else
|
40
|
+
cipher = ::OpenSSL::Cipher.new('AES-128-CBC')
|
41
|
+
@key.export(cipher, @passphrase)
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
# OpenSSH public key
|
46
|
+
def ssh_public_key
|
47
|
+
case @type
|
48
|
+
when 'rsa'
|
49
|
+
enc_pubkey = openssh_rsa_public_key
|
50
|
+
else
|
51
|
+
fail "Invalid key type #{new_resource.type} found in ssh_public_key method - serious error!"
|
52
|
+
end
|
53
|
+
"ssh-#{@type} #{enc_pubkey} #{@comment}\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
# Encode an OpenSSH RSA public key.
|
57
|
+
# Key format is PEM-encoded - size (big-endian), then data:
|
58
|
+
# * Type (ie: len: 7 (size of string), data: ssh-rsa)
|
59
|
+
# * Exponent (len/data)
|
60
|
+
# * Modulus (len+1/NUL+data)
|
61
|
+
def openssh_rsa_public_key
|
62
|
+
enc_type = "#{[7].pack('N')}ssh-rsa"
|
63
|
+
enc_exponent = "#{[@key.public_key.e.num_bytes].pack('N')}#{@key.public_key.e.to_s(2)}"
|
64
|
+
enc_modulus = "#{[@key.public_key.n.num_bytes + 1].pack('N')}\0#{@key.public_key.n.to_s(2)}"
|
65
|
+
Base64.strict_encode64("#{enc_type}#{enc_exponent}#{enc_modulus}")
|
66
|
+
end
|
67
|
+
|
68
|
+
# Fingerprint (SHA1 digest, colon delimited)
|
69
|
+
def key_fingerprint
|
70
|
+
OpenSSL::Digest::SHA1.hexdigest(@key.public_key.to_der).scan(/../).join(':')
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
# provider fucntions for the SSHKeygen Chef resoruce provider class
|
75
|
+
module SSHKeygenProvider
|
76
|
+
def create_key
|
77
|
+
converge_by("Create SSH #{new_resource.type} #{new_resource.strength}-bit key (#{new_resource.comment})") do
|
78
|
+
@key = ::SSHKeygen::Generator.new(
|
79
|
+
new_resource.strength,
|
80
|
+
new_resource.type,
|
81
|
+
new_resource.passphrase,
|
82
|
+
new_resource.comment
|
83
|
+
)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def save_private_key
|
88
|
+
converge_by("Create SSH private key at #{new_resource.path}") do
|
89
|
+
f = file new_resource.path do
|
90
|
+
action :nothing
|
91
|
+
owner new_resource.owner
|
92
|
+
group new_resource.group
|
93
|
+
mode 0600
|
94
|
+
sensitive true
|
95
|
+
end
|
96
|
+
f.content(@key.private_key)
|
97
|
+
f.run_action(:create)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
def save_public_key
|
102
|
+
converge_by("Create SSH public key at #{new_resource.path}") do
|
103
|
+
f = file "#{new_resource.path}.pub" do
|
104
|
+
action :nothing
|
105
|
+
owner new_resource.owner
|
106
|
+
group new_resource.group
|
107
|
+
mode 0600
|
108
|
+
end
|
109
|
+
f.content(@key.ssh_public_key)
|
110
|
+
f.run_action(:create)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def update_directory_permissions
|
115
|
+
return false unless new_resource.secure_directory
|
116
|
+
converge_by("Update directory permissions at #{File.dirname(new_resource.path)}") do
|
117
|
+
directory ::File.dirname(new_resource.path) do
|
118
|
+
action :create
|
119
|
+
owner new_resource.owner
|
120
|
+
group new_resource.group
|
121
|
+
mode 0700
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
module SSHKeygen
|
16
|
+
VERSION = '1.0.3'
|
17
|
+
end
|
data/ssh_keygen.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
lib = File.expand_path('../lib', __FILE__)
|
16
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
17
|
+
require 'ssh_keygen/version'
|
18
|
+
|
19
|
+
Gem::Specification.new do |spec|
|
20
|
+
spec.name = 'ssh_keygen'
|
21
|
+
spec.version = SSHKeygen::VERSION
|
22
|
+
spec.authors = ['Chris Marchesi']
|
23
|
+
spec.email = %w(chrism@vancluevertech.com)
|
24
|
+
spec.description = 'Chef resource for SSH key creation'
|
25
|
+
spec.summary = spec.description
|
26
|
+
spec.homepage = 'https://github.com/vancluever/ssh_keygen'
|
27
|
+
spec.license = 'Apache 2.0'
|
28
|
+
|
29
|
+
spec.files = `git ls-files`.split($INPUT_RECORD_SEPARATOR)
|
30
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
31
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
32
|
+
spec.require_paths = %w(lib)
|
33
|
+
|
34
|
+
spec.add_dependency 'halite', '~> 1.0'
|
35
|
+
spec.add_dependency 'poise', '~> 2.0'
|
36
|
+
|
37
|
+
spec.add_development_dependency 'poise-boiler', '~> 1.0'
|
38
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
name 'ssh_keygen_test'
|
16
|
+
depends 'ssh_keygen'
|
@@ -0,0 +1,22 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
directory '/root/.ssh' do
|
16
|
+
action :create
|
17
|
+
end
|
18
|
+
|
19
|
+
ssh_keygen '/root/.ssh/id_rsa_encrypted' do
|
20
|
+
action :create
|
21
|
+
passphrase 'onetwothreefour'
|
22
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
group 'kitchen' do
|
16
|
+
action :create
|
17
|
+
end
|
18
|
+
|
19
|
+
user 'kitchen' do
|
20
|
+
action :create
|
21
|
+
group 'kitchen'
|
22
|
+
home '/home/kitchen'
|
23
|
+
manage_home true
|
24
|
+
end
|
25
|
+
|
26
|
+
directory '/home/kitchen/.ssh' do
|
27
|
+
action :create
|
28
|
+
end
|
29
|
+
|
30
|
+
ssh_keygen '/home/kitchen/.ssh/id_rsa' do
|
31
|
+
action :create
|
32
|
+
owner 'kitchen'
|
33
|
+
group 'kitchen'
|
34
|
+
secure_directory true
|
35
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
directory '/root/.ssh' do
|
16
|
+
action :create
|
17
|
+
end
|
18
|
+
|
19
|
+
ssh_keygen '/root/.ssh/id_rsa' do
|
20
|
+
action :create
|
21
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'serverspec'
|
16
|
+
require 'openssl'
|
17
|
+
|
18
|
+
set :backend, :exec
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require_relative 'spec_helper'
|
16
|
+
|
17
|
+
describe file('/root/.ssh/id_rsa_encrypted') do
|
18
|
+
it { should exist }
|
19
|
+
it { should be_owned_by 'root' }
|
20
|
+
it { should be_grouped_into 'root' }
|
21
|
+
it { should be_mode 600 }
|
22
|
+
end
|
23
|
+
|
24
|
+
# OpenSSL and OpenSSH private keys are the same
|
25
|
+
describe x509_private_key('/root/.ssh/id_rsa_encrypted') do
|
26
|
+
it { should be_encrypted }
|
27
|
+
end
|
28
|
+
|
29
|
+
describe file('/root/.ssh/id_rsa_encrypted.pub') do
|
30
|
+
it { should exist }
|
31
|
+
it { should be_owned_by 'root' }
|
32
|
+
it { should be_grouped_into 'root' }
|
33
|
+
it { should be_mode 600 }
|
34
|
+
its(:content) { should match %r{^ssh-rsa [a-zA-Z0-9=/+]+ root@[-_.a-zA-Z0-9]} }
|
35
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require_relative 'spec_helper'
|
16
|
+
|
17
|
+
describe file('/home/kitchen/.ssh/id_rsa') do
|
18
|
+
it { should exist }
|
19
|
+
it { should be_owned_by 'kitchen' }
|
20
|
+
it { should be_grouped_into 'kitchen' }
|
21
|
+
it { should be_mode 600 }
|
22
|
+
end
|
23
|
+
|
24
|
+
# OpenSSL and OpenSSH private keys are the same
|
25
|
+
describe x509_private_key('/home/kitchen/.ssh/id_rsa') do
|
26
|
+
it { should be_valid }
|
27
|
+
it { should_not be_encrypted }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe file('/home/kitchen/.ssh/id_rsa.pub') do
|
31
|
+
it { should exist }
|
32
|
+
it { should be_owned_by 'kitchen' }
|
33
|
+
it { should be_grouped_into 'kitchen' }
|
34
|
+
it { should be_mode 600 }
|
35
|
+
its(:content) { should match %r{^ssh-rsa [a-zA-Z0-9=/+]+ kitchen@[-_.a-zA-Z0-9]} }
|
36
|
+
end
|
37
|
+
|
38
|
+
describe file('/home/kitchen/.ssh') do
|
39
|
+
it { should exist }
|
40
|
+
it { should be_directory }
|
41
|
+
it { should be_owned_by 'kitchen' }
|
42
|
+
it { should be_grouped_into 'kitchen' }
|
43
|
+
it { should be_mode 700 }
|
44
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require_relative 'spec_helper'
|
16
|
+
|
17
|
+
describe file('/root/.ssh/id_rsa') do
|
18
|
+
it { should exist }
|
19
|
+
it { should be_owned_by 'root' }
|
20
|
+
it { should be_grouped_into 'root' }
|
21
|
+
it { should be_mode 600 }
|
22
|
+
end
|
23
|
+
|
24
|
+
# OpenSSL and OpenSSH private keys are the same
|
25
|
+
describe x509_private_key('/root/.ssh/id_rsa') do
|
26
|
+
it { should be_valid }
|
27
|
+
it { should_not be_encrypted }
|
28
|
+
end
|
29
|
+
|
30
|
+
describe file('/root/.ssh/id_rsa.pub') do
|
31
|
+
it { should exist }
|
32
|
+
it { should be_owned_by 'root' }
|
33
|
+
it { should be_grouped_into 'root' }
|
34
|
+
it { should be_mode 600 }
|
35
|
+
its(:content) { should match %r{^ssh-rsa [a-zA-Z0-9=/+]+ root@[-_.a-zA-Z0-9]} }
|
36
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'spec_helper'
|
16
|
+
|
17
|
+
describe SSHKeygen::Generator do
|
18
|
+
context 'default options with a bit strength of 2048' do
|
19
|
+
key = ::SSHKeygen::Generator.new(2048, 'rsa', nil, 'test@rspec')
|
20
|
+
|
21
|
+
it 'has a valid PEM-encoded private key' do
|
22
|
+
generator_key_digest = key.key_fingerprint
|
23
|
+
validator_key_digest = create_fingerprint_from_key(key.private_key)
|
24
|
+
|
25
|
+
expect(generator_key_digest).to eq(validator_key_digest)
|
26
|
+
end
|
27
|
+
|
28
|
+
it 'has a valid OpenSSH-style formatted-public key' do
|
29
|
+
expect(key.ssh_public_key).to match(%r{^ssh-rsa [a-zA-Z0-9=/+]+ test@rspec})
|
30
|
+
end
|
31
|
+
|
32
|
+
# it 'has a valid public key for the private key' do
|
33
|
+
# generator_key_digest = key.key_fingerprint
|
34
|
+
# public_key = key.ssh_public_key.split(' ')[1]
|
35
|
+
# public_key_digest = create_fingerprint_from_key(Base64.strict_decode64(public_key))
|
36
|
+
#
|
37
|
+
# expect(generator_key_digest).to eq(public_key_digest)
|
38
|
+
# end
|
39
|
+
end
|
40
|
+
|
41
|
+
context 'with passphrase and a bit strength of 2048' do
|
42
|
+
key = ::SSHKeygen::Generator.new(2048, 'rsa', 'onetwothreefour', 'test@rspec')
|
43
|
+
|
44
|
+
it 'has a valid PEM-encoded private key' do
|
45
|
+
generator_key_digest = key.key_fingerprint
|
46
|
+
validator_key_digest = create_fingerprint_from_key(key.private_key, 'onetwothreefour')
|
47
|
+
|
48
|
+
expect(generator_key_digest).to eq(validator_key_digest)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'has a valid OpenSSH-style formatted-public key' do
|
52
|
+
expect(key.ssh_public_key).to match(%r{^ssh-rsa [a-zA-Z0-9=/+]+ test@rspec})
|
53
|
+
end
|
54
|
+
|
55
|
+
# it 'has a valid public key for the private key' do
|
56
|
+
# generator_key_digest = key.key_fingerprint
|
57
|
+
# public_key = key.ssh_public_key.split(' ')[1]
|
58
|
+
# public_key_digest = create_fingerprint_from_key(Base64.strict_decode64(public_key))
|
59
|
+
#
|
60
|
+
# expect(generator_key_digest).to eq(public_key_digest)
|
61
|
+
# end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
describe SSHKeygen::Resource do
|
66
|
+
step_into(:ssh_keygen)
|
67
|
+
|
68
|
+
context 'base tests without passphrase' do
|
69
|
+
recipe do
|
70
|
+
ssh_keygen '/root/.ssh/id_rsa' do
|
71
|
+
action :create
|
72
|
+
secure_directory true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'creates a file at /root/.ssh/id_rsa with the proper permissions' do
|
77
|
+
expect(chef_run).to create_file('/root/.ssh/id_rsa').with(
|
78
|
+
user: 'root',
|
79
|
+
group: 'root',
|
80
|
+
mode: 0600,
|
81
|
+
sensitive: true
|
82
|
+
)
|
83
|
+
end
|
84
|
+
|
85
|
+
it 'creates a file at /root/.ssh/id_rsa.pub with the proper permissions' do
|
86
|
+
expect(chef_run).to create_file('/root/.ssh/id_rsa.pub').with(
|
87
|
+
user: 'root',
|
88
|
+
group: 'root',
|
89
|
+
mode: 0600,
|
90
|
+
sensitive: false
|
91
|
+
)
|
92
|
+
end
|
93
|
+
|
94
|
+
it 'secures the /root/.ssh directory' do
|
95
|
+
expect(chef_run).to create_directory('/root/.ssh').with(
|
96
|
+
user: 'root',
|
97
|
+
group: 'root',
|
98
|
+
mode: 0700
|
99
|
+
)
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
context 'passphrase-specific tests' do
|
104
|
+
recipe do
|
105
|
+
ssh_keygen '/root/.ssh/id_rsa_encrypted' do
|
106
|
+
action :create
|
107
|
+
passphrase 'onetwothreefour'
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
it 'creates a file at /root/.ssh/id_rsa_encrypted with the proper permissions' do
|
112
|
+
expect(chef_run).to create_file('/root/.ssh/id_rsa_encrypted').with(
|
113
|
+
user: 'root',
|
114
|
+
group: 'root',
|
115
|
+
mode: 0600,
|
116
|
+
sensitive: true
|
117
|
+
)
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'creates a file at /root/.ssh/id_rsa_encrypted.pub with the proper permissions' do
|
121
|
+
expect(chef_run).to create_file('/root/.ssh/id_rsa_encrypted.pub').with(
|
122
|
+
user: 'root',
|
123
|
+
group: 'root',
|
124
|
+
mode: 0600,
|
125
|
+
sensitive: false
|
126
|
+
)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# Copyright 2015 Chris Marchesi
|
2
|
+
#
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
4
|
+
# you may not use this file except in compliance with the License.
|
5
|
+
# You may obtain a copy of the License at
|
6
|
+
#
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
8
|
+
#
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
12
|
+
# See the License for the specific language governing permissions and
|
13
|
+
# limitations under the License.
|
14
|
+
|
15
|
+
require 'poise_boiler/spec_helper'
|
16
|
+
require 'ssh_keygen'
|
17
|
+
|
18
|
+
# a small helper function that creates a SHA1 fingerprint from a private or
|
19
|
+
# public key.
|
20
|
+
def create_fingerprint_from_key(key, passphrase = nil)
|
21
|
+
new_key = OpenSSL::PKey::RSA.new(key, passphrase)
|
22
|
+
new_key_digest = OpenSSL::Digest::SHA1.new(new_key.public_key.to_der).to_s.scan(/../).join(':')
|
23
|
+
new_key_digest
|
24
|
+
end
|
metadata
ADDED
@@ -0,0 +1,121 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ssh_keygen
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.0.3
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Marchesi
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-01-23 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: halite
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: poise
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '2.0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '2.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: poise-boiler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.0'
|
55
|
+
description: Chef resource for SSH key creation
|
56
|
+
email:
|
57
|
+
- chrism@vancluevertech.com
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".kitchen.yml"
|
64
|
+
- ".rubocop.yml"
|
65
|
+
- Berksfile
|
66
|
+
- CHANGELOG.md
|
67
|
+
- Gemfile
|
68
|
+
- LICENSE
|
69
|
+
- README.md
|
70
|
+
- Rakefile
|
71
|
+
- lib/ssh_keygen.rb
|
72
|
+
- lib/ssh_keygen/cheftie.rb
|
73
|
+
- lib/ssh_keygen/provider.rb
|
74
|
+
- lib/ssh_keygen/version.rb
|
75
|
+
- ssh_keygen.gemspec
|
76
|
+
- test/cookbooks/ssh_keygen_test/metadata.rb
|
77
|
+
- test/cookbooks/ssh_keygen_test/recipes/with_passphrase.rb
|
78
|
+
- test/cookbooks/ssh_keygen_test/recipes/with_user_opts.rb
|
79
|
+
- test/cookbooks/ssh_keygen_test/recipes/without_passphrase.rb
|
80
|
+
- test/integration/default/serverspec/spec_helper.rb
|
81
|
+
- test/integration/default/serverspec/with_passphrase_spec.rb
|
82
|
+
- test/integration/default/serverspec/with_user_opts_spec.rb
|
83
|
+
- test/integration/default/serverspec/without_passphrase_spec.rb
|
84
|
+
- test/spec/resources/ssh_keygen_spec.rb
|
85
|
+
- test/spec/spec_helper.rb
|
86
|
+
homepage: https://github.com/vancluever/ssh_keygen
|
87
|
+
licenses:
|
88
|
+
- Apache 2.0
|
89
|
+
metadata: {}
|
90
|
+
post_install_message:
|
91
|
+
rdoc_options: []
|
92
|
+
require_paths:
|
93
|
+
- lib
|
94
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
95
|
+
requirements:
|
96
|
+
- - ">="
|
97
|
+
- !ruby/object:Gem::Version
|
98
|
+
version: '0'
|
99
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
requirements: []
|
105
|
+
rubyforge_project:
|
106
|
+
rubygems_version: 2.2.2
|
107
|
+
signing_key:
|
108
|
+
specification_version: 4
|
109
|
+
summary: Chef resource for SSH key creation
|
110
|
+
test_files:
|
111
|
+
- test/cookbooks/ssh_keygen_test/metadata.rb
|
112
|
+
- test/cookbooks/ssh_keygen_test/recipes/with_passphrase.rb
|
113
|
+
- test/cookbooks/ssh_keygen_test/recipes/with_user_opts.rb
|
114
|
+
- test/cookbooks/ssh_keygen_test/recipes/without_passphrase.rb
|
115
|
+
- test/integration/default/serverspec/spec_helper.rb
|
116
|
+
- test/integration/default/serverspec/with_passphrase_spec.rb
|
117
|
+
- test/integration/default/serverspec/with_user_opts_spec.rb
|
118
|
+
- test/integration/default/serverspec/without_passphrase_spec.rb
|
119
|
+
- test/spec/resources/ssh_keygen_spec.rb
|
120
|
+
- test/spec/spec_helper.rb
|
121
|
+
has_rdoc:
|