hiera-eyaml 1.3.4 → 1.3.5
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 +7 -0
- data/Gemfile.lock +22 -12
- data/README.md +46 -4
- data/lib/hiera/backend/eyaml.rb +1 -1
- data/lib/hiera/backend/eyaml/CLI.rb +11 -7
- data/lib/hiera/backend/eyaml/actions/decrypt_action.rb +18 -47
- data/lib/hiera/backend/eyaml/actions/edit_action.rb +43 -14
- data/lib/hiera/backend/eyaml/actions/encrypt_action.rb +23 -70
- data/lib/hiera/backend/eyaml/encryptor.rb +2 -2
- data/lib/hiera/backend/eyaml/options.rb +4 -1
- data/lib/hiera/backend/eyaml/parser/encrypted_tokens.rb +135 -0
- data/lib/hiera/backend/eyaml/parser/parser.rb +82 -0
- data/lib/hiera/backend/eyaml/parser/token.rb +49 -0
- data/lib/hiera/backend/eyaml/plugins.rb +1 -1
- data/lib/hiera/backend/eyaml/utils.rb +9 -1
- data/lib/hiera/backend/eyaml_backend.rb +5 -5
- metadata +14 -17
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6991fc6c0e02d5a2fe5d177c48f37c41c8e665b9
|
4
|
+
data.tar.gz: aea670bff868758d3e43529b4df32ad50a7c6d0d
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 87057907d1ffc81c21fb4fafb040f08f3d1a69cf0af00332dcc6ed642144a0e33be9eb5087b2d5ca5fc90f637c2ef3035447d64dde2c3a7062e288e7fcfe0078
|
7
|
+
data.tar.gz: c67e419ec77d72dde2ad5ee6f0aeb51d20696db797db5512b3aec212befe92884d1e61868da5f423ac35c9ac66822d816110b77def803cdc8d718e9b78fdfaa4
|
data/Gemfile.lock
CHANGED
@@ -8,25 +8,34 @@ GEM
|
|
8
8
|
builder (3.2.2)
|
9
9
|
childprocess (0.3.9)
|
10
10
|
ffi (~> 1.0, >= 1.0.11)
|
11
|
-
cucumber (1.3.
|
11
|
+
cucumber (1.3.9)
|
12
12
|
builder (>= 2.1.2)
|
13
13
|
diff-lcs (>= 1.1.3)
|
14
|
-
gherkin (~> 2.12
|
15
|
-
multi_json (
|
14
|
+
gherkin (~> 2.12)
|
15
|
+
multi_json (>= 1.7.5, < 2.0)
|
16
16
|
multi_test (>= 0.0.2)
|
17
|
-
diff-lcs (1.2.
|
18
|
-
|
19
|
-
|
17
|
+
diff-lcs (1.2.5)
|
18
|
+
facter (1.7.3)
|
19
|
+
ffi (1.9.3)
|
20
|
+
gherkin (2.12.2)
|
20
21
|
multi_json (~> 1.3)
|
21
|
-
hiera
|
22
|
+
hiera (1.2.1)
|
23
|
+
json_pure
|
24
|
+
hiera-eyaml (1.3.4)
|
22
25
|
highline (>= 1.6.19)
|
23
26
|
trollop (>= 2.0)
|
24
|
-
hiera-eyaml-plaintext (0.
|
25
|
-
hiera-eyaml (>= 1.
|
26
|
-
highline (1.6.
|
27
|
-
|
27
|
+
hiera-eyaml-plaintext (0.4)
|
28
|
+
hiera-eyaml (>= 1.3.1)
|
29
|
+
highline (1.6.20)
|
30
|
+
json_pure (1.8.1)
|
31
|
+
multi_json (1.8.2)
|
28
32
|
multi_test (0.0.2)
|
29
|
-
|
33
|
+
puppet (3.3.1)
|
34
|
+
facter (~> 1.6)
|
35
|
+
hiera (~> 1.0)
|
36
|
+
rgen (~> 0.6.5)
|
37
|
+
rgen (0.6.6)
|
38
|
+
rspec-expectations (2.14.4)
|
30
39
|
diff-lcs (>= 1.1.3, < 2.0)
|
31
40
|
trollop (2.0)
|
32
41
|
|
@@ -37,4 +46,5 @@ DEPENDENCIES
|
|
37
46
|
aruba
|
38
47
|
hiera-eyaml-plaintext
|
39
48
|
highline
|
49
|
+
puppet
|
40
50
|
trollop
|
data/README.md
CHANGED
@@ -32,6 +32,14 @@ Setup
|
|
32
32
|
### Installing hiera-eyaml
|
33
33
|
|
34
34
|
$ gem install hiera-eyaml
|
35
|
+
|
36
|
+
#### Installing from behind a corporate/application proxy
|
37
|
+
$ export HTTP_PROXY=http://yourcorporateproxy:3128/
|
38
|
+
$ export HTTPS_PROXY=http://yourcorporateproxy:3128/
|
39
|
+
|
40
|
+
then run your install
|
41
|
+
|
42
|
+
$ gem install hiera-eyaml
|
35
43
|
|
36
44
|
### Generate keys
|
37
45
|
|
@@ -41,6 +49,26 @@ The first step is to create a pair of keys:
|
|
41
49
|
|
42
50
|
This creates a public and private key with default names in the default location. (./keys)
|
43
51
|
|
52
|
+
#### Storing the keys securely when using Puppet
|
53
|
+
|
54
|
+
Since the point of using this module is to securely store sensitive information, it's important to store these keys securely.
|
55
|
+
If using Hiera with Puppet, Your puppetmaster will need to access these keys to perform decryption when the puppet agent runs on a remote node.
|
56
|
+
So for this reason, a suggested location might be to store them in:
|
57
|
+
|
58
|
+
/etc/puppet/secure/keys
|
59
|
+
|
60
|
+
(Using a secure/keys/ subfolder is so that you can still store other secure puppet files in the secure/ folder that might not be related to this module.)
|
61
|
+
|
62
|
+
The permissions for this folder should allow the puppet user (normally 'puppet') execute access to the keys directory, read only access to the keys themselves and restrict everyone else:
|
63
|
+
|
64
|
+
$ chown -R puppet:puppet /etc/puppet/secure/keys
|
65
|
+
$ chmod -R 0500 /etc/puppet/secure/keys
|
66
|
+
$ chmod 0400 /etc/puppet/secure/keys/*.pem
|
67
|
+
$ ls -lha /etc/puppet/secure/keys
|
68
|
+
-r-------- 1 puppet puppet 1.7K Sep 24 16:24 private_key.pkcs7.pem
|
69
|
+
-r-------- 1 puppet puppet 1.1K Sep 24 16:24 public_key.pkcs7.pem
|
70
|
+
|
71
|
+
|
44
72
|
### Encryption
|
45
73
|
|
46
74
|
To encrypt something, you only need the public_key, so distribute that to people creating hiera properties
|
@@ -49,9 +77,10 @@ To encrypt something, you only need the public_key, so distribute that to people
|
|
49
77
|
$ eyaml -e -s 'hello there' # Encrypt a string
|
50
78
|
$ eyaml -e -p # Encrypt a password (prompt for it)
|
51
79
|
|
52
|
-
Use the -l parameter to pass in a label for the encrypted value
|
80
|
+
Use the -l parameter to pass in a label for the encrypted value,
|
81
|
+
|
82
|
+
$ eyaml -e -l 'some_easy_to_use_label' -s 'yourSecretString' --pkcs7-private-key /etc/puppet/secure/keys/private_key.pkcs7.pem --pkcs7-public-key /etc/puppet/secure/keys/public_key.pkcs7.pem
|
53
83
|
|
54
|
-
$ eyaml -e -l 'my-secret-key' -s 'very secret stuffs'
|
55
84
|
|
56
85
|
### Decryption
|
57
86
|
|
@@ -108,13 +137,18 @@ To use eyaml with hiera and puppet, first configure hiera.yaml to use the eyaml
|
|
108
137
|
:datadir: '/etc/puppet/hieradata'
|
109
138
|
|
110
139
|
# If using the pkcs7 encryptor (default)
|
111
|
-
:pkcs7_private_key: /path/to/
|
112
|
-
:pkcs7_public_key: /path/to/
|
140
|
+
:pkcs7_private_key: /path/to/private_key.pkcs7.pem
|
141
|
+
:pkcs7_public_key: /path/to/public_key.pkcs7.pem
|
113
142
|
|
114
143
|
</pre>
|
115
144
|
|
116
145
|
Then, edit your hiera yaml files (renaming them with the .eyaml extension), and insert your encrypted values:
|
117
146
|
|
147
|
+
|
148
|
+
*Important Note:*
|
149
|
+
The eYaml backend will not parse internally json formatted yaml files, whereas the regular yaml backend will.
|
150
|
+
You'll need to ensure any existing yaml files using json format are converted to syntactically correct yaml format.
|
151
|
+
|
118
152
|
<pre>
|
119
153
|
---
|
120
154
|
plain-property: You can see me
|
@@ -172,6 +206,14 @@ Notes
|
|
172
206
|
|
173
207
|
If you do not specify an encryption method within ENC[] tags, it will be assumed to be PKCS7
|
174
208
|
|
209
|
+
Also remember that after encrypting your sensitive properties, if anyone has access to your git source,
|
210
|
+
they will see what the property was in previous commits before you encrypted. It's recommended that you
|
211
|
+
roll any passwords when switching from unencrypted to encrypted properties. eg, Developers having write
|
212
|
+
access to a DEV branch will be able to read/view the contents of the PRD branch, as per the design of GIT.
|
213
|
+
|
214
|
+
Github has a great guide on removing sensitive data from repos here:
|
215
|
+
https://help.github.com/articles/remove-sensitive-data
|
216
|
+
|
175
217
|
Authors
|
176
218
|
=======
|
177
219
|
|
data/lib/hiera/backend/eyaml.rb
CHANGED
@@ -33,17 +33,19 @@ Options:
|
|
33
33
|
EOS
|
34
34
|
|
35
35
|
opt :createkeys, "Create public and private keys for use encrypting properties", :short => 'c'
|
36
|
-
opt :decrypt, "Decrypt something"
|
37
|
-
opt :encrypt, "Encrypt something"
|
38
|
-
opt :edit, "Decrypt, Edit, and Reencrypt", :type => :string
|
39
|
-
opt :eyaml, "Source input is an eyaml file", :type => :string
|
36
|
+
opt :decrypt, "Decrypt something", :short => 'd'
|
37
|
+
opt :encrypt, "Encrypt something", :short => 'e'
|
38
|
+
opt :edit, "Decrypt, Edit, and Reencrypt", :short => 'i', :type => :string
|
39
|
+
opt :eyaml, "Source input is an eyaml file", :short => 'y', :type => :string
|
40
40
|
opt :password, "Source input is a password entered on the terminal", :short => 'p'
|
41
41
|
opt :string, "Source input is a string provided as an argument", :short => 's', :type => :string
|
42
42
|
opt :file, "Source input is a file", :short => 'f', :type => :string
|
43
|
-
opt :stdin, "Source input
|
43
|
+
opt :stdin, "Source input is taken from stdin", :short => :none
|
44
44
|
opt :encrypt_method, "Override default encryption and decryption method (default is PKCS7)", :short => 'n', :default => "pkcs7"
|
45
|
-
opt :output, "Output format of final result (examples, block, string)", :type => :string, :default => "examples"
|
45
|
+
opt :output, "Output format of final result (examples, block, string)", :type => :string, :short => 'o', :default => "examples"
|
46
46
|
opt :label, "Apply a label to the encrypted result", :short => 'l', :type => :string
|
47
|
+
opt :debug, "Be more verbose", :short => :none
|
48
|
+
opt :quiet, "Be less verbose", :short => :none
|
47
49
|
|
48
50
|
Hiera::Backend::Eyaml::Plugins.options.each do |name, option|
|
49
51
|
opt name, option[:desc], :type => option[:type], :short => option[:short], :default => option[:default]
|
@@ -90,6 +92,7 @@ Options:
|
|
90
92
|
|
91
93
|
Eyaml.default_encryption_scheme = options[:encrypt_method].upcase if options[:encrypt_method]
|
92
94
|
Eyaml::Options.set options
|
95
|
+
Eyaml::Options.debug
|
93
96
|
|
94
97
|
end
|
95
98
|
|
@@ -98,7 +101,8 @@ Options:
|
|
98
101
|
action = Eyaml::Options[:action]
|
99
102
|
action_class = Module.const_get('Hiera').const_get('Backend').const_get('Eyaml').const_get('Actions').const_get("#{Utils.camelcase action.to_s}Action")
|
100
103
|
|
101
|
-
|
104
|
+
return_value = action_class.execute
|
105
|
+
puts return_value unless return_value.nil?
|
102
106
|
|
103
107
|
end
|
104
108
|
|
@@ -1,5 +1,6 @@
|
|
1
1
|
require 'hiera/backend/eyaml/utils'
|
2
2
|
require 'hiera/backend/eyaml/options'
|
3
|
+
require 'hiera/backend/eyaml/parser/parser'
|
3
4
|
|
4
5
|
class Hiera
|
5
6
|
module Backend
|
@@ -8,57 +9,27 @@ class Hiera
|
|
8
9
|
|
9
10
|
class DecryptAction
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
}
|
29
|
-
|
30
|
-
# strings
|
31
|
-
output.gsub!( REGEX_ENCRYPTED_STRING ) { |match|
|
32
|
-
encryption_scheme = parse_encryption_scheme( $1 )
|
33
|
-
decryptor = Encryptor.find encryption_scheme
|
34
|
-
|
35
|
-
plaintext = decryptor.decrypt( decryptor.decode $2 )
|
36
|
-
"DEC::#{decryptor.tag}[" + plaintext + "]!"
|
37
|
-
}
|
38
|
-
|
39
|
-
output
|
40
|
-
else
|
41
|
-
|
42
|
-
output = Eyaml::Options[:input_data].gsub( REGEX_ENCRYPTED_STRING ) { |match|
|
43
|
-
encryption_scheme = parse_encryption_scheme( $1 )
|
44
|
-
decryptor = Encryptor.find encryption_scheme
|
45
|
-
decryptor.decrypt( decryptor.decode $2 )
|
46
|
-
}
|
47
|
-
|
48
|
-
output
|
12
|
+
def self.execute
|
13
|
+
parser = Parser::ParserFactory.encrypted_parser
|
14
|
+
tokens = parser.parse(Eyaml::Options[:input_data])
|
15
|
+
case Eyaml::Options[:source]
|
16
|
+
when :eyaml
|
17
|
+
decrypted = tokens.map{ |token| token.to_decrypted }
|
18
|
+
decrypted.join
|
19
|
+
else
|
20
|
+
decrypted = tokens.map{ |token|
|
21
|
+
case token.class.name
|
22
|
+
when /::EncToken$/
|
23
|
+
token.plain_text
|
24
|
+
else
|
25
|
+
token.match
|
26
|
+
end
|
27
|
+
}
|
28
|
+
decrypted.join
|
49
29
|
end
|
50
30
|
|
51
|
-
output_data
|
52
|
-
|
53
31
|
end
|
54
32
|
|
55
|
-
protected
|
56
|
-
|
57
|
-
def self.parse_encryption_scheme regex_result
|
58
|
-
regex_result = Eyaml.default_encryption_scheme + "," if regex_result.nil?
|
59
|
-
regex_result.split(",").first
|
60
|
-
end
|
61
|
-
|
62
33
|
end
|
63
34
|
|
64
35
|
end
|
@@ -2,6 +2,7 @@ require 'hiera/backend/eyaml/utils'
|
|
2
2
|
require 'hiera/backend/eyaml/actions/decrypt_action'
|
3
3
|
require 'hiera/backend/eyaml/actions/encrypt_action'
|
4
4
|
require 'hiera/backend/eyaml/options'
|
5
|
+
require 'hiera/backend/eyaml/parser/parser'
|
5
6
|
|
6
7
|
class Hiera
|
7
8
|
module Backend
|
@@ -11,32 +12,60 @@ class Hiera
|
|
11
12
|
class EditAction
|
12
13
|
|
13
14
|
def self.execute
|
14
|
-
|
15
|
-
|
15
|
+
|
16
|
+
encrypted_parser = Parser::ParserFactory.encrypted_parser
|
17
|
+
tokens = encrypted_parser.parse Eyaml::Options[:input_data]
|
18
|
+
decrypted_input = tokens.each_with_index.to_a.map{|(t,index)| t.to_decrypted :index => index}.join
|
16
19
|
decrypted_file = Utils.write_tempfile decrypted_input
|
20
|
+
|
17
21
|
editor = Utils.find_editor
|
18
22
|
system editor, decrypted_file
|
19
23
|
status = $?
|
20
|
-
raise StandardError, "Editor #{editor} has not exited?" unless status.exited?
|
21
|
-
raise StandardError, "Editor did not exit successfully (exit code #{status.exitstatus}), aborting" unless status.exitstatus #TODO: The file is left on the disk
|
22
|
-
raise StandardError, "File was moved by editor" unless File.file? decrypted_file
|
23
24
|
|
25
|
+
raise StandardError, "File was moved by editor" unless File.file? decrypted_file
|
24
26
|
edited_file = File.read decrypted_file
|
25
27
|
Utils.secure_file_delete :file => decrypted_file, :num_bytes => [edited_file.length, decrypted_input.length].max
|
28
|
+
|
29
|
+
raise StandardError, "Editor #{editor} has not exited?" unless status.exited?
|
30
|
+
raise StandardError, "Editor did not exit successfully (exit code #{status.exitstatus}), aborting" unless status.exitstatus
|
31
|
+
|
26
32
|
raise StandardError, "Edited file is blank" if edited_file.empty?
|
27
|
-
raise StandardError, "No changes" if edited_file == decrypted_input
|
28
33
|
|
29
|
-
|
30
|
-
|
34
|
+
if edited_file == decrypted_input
|
35
|
+
Utils.info "No changes detected, exiting"
|
36
|
+
else
|
37
|
+
decrypted_parser = Parser::ParserFactory.decrypted_parser
|
38
|
+
edited_tokens = decrypted_parser.parse(edited_file)
|
39
|
+
|
40
|
+
# check that the tokens haven't been copy / pasted
|
41
|
+
used_ids = edited_tokens.find_all{ |t| t.class.name =~ /::EncToken$/ }.map{ |t| t.id }
|
42
|
+
if used_ids.length != used_ids.uniq.length
|
43
|
+
raise StandardError, "A duplicate DEC(ID) was found so I don't know how to proceed. This is probably because you copy and pasted a value - if you do this please delete the ID in parentheses"
|
44
|
+
end
|
45
|
+
|
46
|
+
# replace untouched values with the source values
|
47
|
+
edited_denoised_tokens = edited_tokens.map{ |token|
|
48
|
+
if token.class.name =~ /::EncToken$/ && !token.id.nil?
|
49
|
+
old_token = tokens[token.id]
|
50
|
+
if old_token.plain_text.eql? token.plain_text
|
51
|
+
old_token
|
52
|
+
else
|
53
|
+
token
|
54
|
+
end
|
55
|
+
else
|
56
|
+
token
|
57
|
+
end
|
58
|
+
}
|
31
59
|
|
32
|
-
|
60
|
+
encrypted_output = edited_denoised_tokens.map{ |t| t.to_encrypted }.join
|
33
61
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
62
|
+
filename = Eyaml::Options[:eyaml]
|
63
|
+
File.open("#{filename}", 'w') { |file|
|
64
|
+
file.write encrypted_output
|
65
|
+
}
|
66
|
+
end
|
38
67
|
|
39
|
-
|
68
|
+
nil
|
40
69
|
end
|
41
70
|
|
42
71
|
end
|
@@ -1,87 +1,40 @@
|
|
1
1
|
require 'hiera/backend/eyaml/options'
|
2
|
+
require 'hiera/backend/eyaml/parser/parser'
|
3
|
+
require 'hiera/backend/eyaml/parser/encrypted_tokens'
|
2
4
|
|
3
5
|
class Hiera
|
4
6
|
module Backend
|
5
7
|
module Eyaml
|
6
8
|
module Actions
|
7
|
-
|
8
9
|
class EncryptAction
|
9
10
|
|
10
|
-
REGEX_DECRYPTED_BLOCK = />\n(\s*)DEC(::\w+)?\[(.+)\]\!/
|
11
|
-
REGEX_DECRYPTED_STRING = /DEC(::\w+)?\[(.+)\]\!/
|
12
|
-
|
13
11
|
def self.execute
|
14
|
-
|
15
12
|
case Eyaml::Options[:source]
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
indentation = $1
|
22
|
-
encryption_scheme = parse_encryption_scheme( $2 )
|
23
|
-
encryptor = Encryptor.find encryption_scheme
|
24
|
-
ciphertext = encryptor.encode( encryptor.encrypt($3) ).gsub(/\n/, "\n" + indentation)
|
25
|
-
">\n" + indentation + "ENC[#{encryptor.tag},#{ciphertext}]"
|
26
|
-
}
|
27
|
-
|
28
|
-
# strings
|
29
|
-
output.gsub( REGEX_DECRYPTED_STRING ) { |match|
|
30
|
-
encryption_scheme = parse_encryption_scheme( $1 )
|
31
|
-
encryptor = Encryptor.find encryption_scheme
|
32
|
-
ciphertext = encryptor.encode( encryptor.encrypt($2) ).gsub(/\n/, "")
|
33
|
-
"ENC[#{encryptor.tag},#{ciphertext}]"
|
34
|
-
}
|
35
|
-
|
36
|
-
else
|
37
|
-
encryptor = Encryptor.find
|
38
|
-
ciphertext = encryptor.encode( encryptor.encrypt(Eyaml::Options[:input_data]) )
|
39
|
-
self.format :data => "ENC[#{encryptor.tag},#{ciphertext}]", :structure => Eyaml::Options[:output], :label => Eyaml::Options[:label]
|
40
|
-
end
|
41
|
-
|
42
|
-
end
|
43
|
-
|
44
|
-
protected
|
45
|
-
|
46
|
-
def self.parse_encryption_scheme regex_result
|
47
|
-
regex_result = "::" + Eyaml.default_encryption_scheme if regex_result.nil?
|
48
|
-
regex_result.split("::").last
|
49
|
-
end
|
50
|
-
|
51
|
-
def self.format_string data, label
|
52
|
-
data_as_string = data.split("\n").join("")
|
53
|
-
prefix = label ? "#{label}: " : ''
|
54
|
-
prefix + data_as_string
|
55
|
-
end
|
56
|
-
|
57
|
-
def self.format_block data, label
|
58
|
-
data_as_block = data.split("\n").join("\n ")
|
59
|
-
prefix = label ? "#{label}: >\n" : ''
|
60
|
-
prefix + " #{data_as_block}"
|
61
|
-
end
|
62
|
-
|
63
|
-
def self.format args
|
64
|
-
data = args[:data]
|
65
|
-
structure = args[:structure]
|
66
|
-
label = args[:label]
|
67
|
-
|
68
|
-
case structure
|
69
|
-
when "examples"
|
70
|
-
self.format_string(data, label || 'string') + "\n\n" +
|
71
|
-
"OR\n\n" +
|
72
|
-
self.format_block(data, label || 'block')
|
73
|
-
when "block"
|
74
|
-
self.format_block data, label
|
75
|
-
when "string"
|
76
|
-
self.format_string data, label
|
13
|
+
when :eyaml
|
14
|
+
parser = Parser::ParserFactory.decrypted_parser
|
15
|
+
tokens = parser.parse(Eyaml::Options[:input_data])
|
16
|
+
encrypted = tokens.map{ |token| token.to_encrypted }
|
17
|
+
encrypted.join
|
77
18
|
else
|
78
|
-
|
79
|
-
|
80
|
-
|
19
|
+
encryptor = Encryptor.find
|
20
|
+
ciphertext = encryptor.encode( encryptor.encrypt(Eyaml::Options[:input_data]) )
|
21
|
+
token = Parser::EncToken.new(:block, Eyaml::Options[:input_data], encryptor, ciphertext, nil, ' ')
|
22
|
+
case Eyaml::Options[:output]
|
23
|
+
when "block"
|
24
|
+
token.to_encrypted :label => Eyaml::Options[:label], :use_chevron => !Eyaml::Options[:label].nil?, :format => :block
|
25
|
+
when "string"
|
26
|
+
token.to_encrypted :label => Eyaml::Options[:label], :format => :string
|
27
|
+
when "examples"
|
28
|
+
string = token.to_encrypted :label => Eyaml::Options[:label] || 'string', :format => :string
|
29
|
+
block = token.to_encrypted :label => Eyaml::Options[:label] || 'block', :format => :block
|
30
|
+
"#{string}\n\nOR\n\n#{block}"
|
31
|
+
else
|
32
|
+
token.to_encrypted :format => :string
|
33
|
+
end
|
81
34
|
end
|
35
|
+
end
|
82
36
|
|
83
37
|
end
|
84
|
-
|
85
38
|
end
|
86
39
|
end
|
87
40
|
end
|
@@ -77,7 +77,7 @@ class Hiera
|
|
77
77
|
if self.hiera?
|
78
78
|
Hiera.debug format_message msg
|
79
79
|
else
|
80
|
-
|
80
|
+
Utils::debug format_message msg
|
81
81
|
end
|
82
82
|
end
|
83
83
|
|
@@ -85,7 +85,7 @@ class Hiera
|
|
85
85
|
if self.hiera?
|
86
86
|
Hiera.warn format_message msg
|
87
87
|
else
|
88
|
-
|
88
|
+
Utils::info format_message msg
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
@@ -21,9 +21,12 @@ class Hiera
|
|
21
21
|
end
|
22
22
|
|
23
23
|
def self.debug
|
24
|
+
Utils::debug "Dump of eyaml tool options dict:"
|
25
|
+
Utils::debug "--------------------------------"
|
24
26
|
@@options.each do |k, v|
|
25
|
-
|
27
|
+
Utils::debug "#{k.class.name}:#{k} = #{v.class.name}:#{v}"
|
26
28
|
end
|
29
|
+
Utils::debug ""
|
27
30
|
end
|
28
31
|
|
29
32
|
end
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'hiera/backend/eyaml/parser/token'
|
2
|
+
require 'hiera/backend/eyaml/utils'
|
3
|
+
require 'hiera/backend/eyaml/encryptor'
|
4
|
+
require 'hiera/backend/eyaml'
|
5
|
+
|
6
|
+
|
7
|
+
class Hiera
|
8
|
+
module Backend
|
9
|
+
module Eyaml
|
10
|
+
module Parser
|
11
|
+
class EncToken < Token
|
12
|
+
attr_reader :format, :cipher, :encryptor, :indentation, :plain_text, :id
|
13
|
+
def self.encrypted_value(format, encryption_scheme, cipher, match, indentation = '')
|
14
|
+
decryptor = Encryptor.find encryption_scheme
|
15
|
+
plain_text = decryptor.decrypt( decryptor.decode cipher )
|
16
|
+
EncToken.new(format, plain_text, decryptor, cipher, match, indentation)
|
17
|
+
end
|
18
|
+
def self.decrypted_value(format, plain_text, encryption_scheme, match, id, indentation = '')
|
19
|
+
encryptor = Encryptor.find encryption_scheme
|
20
|
+
cipher = encryptor.encode( encryptor.encrypt plain_text )
|
21
|
+
id_number = id.nil? ? nil : id.gsub(/\(|\)/, "").to_i
|
22
|
+
EncToken.new(format, plain_text, encryptor, cipher, match, indentation, id_number)
|
23
|
+
end
|
24
|
+
|
25
|
+
def initialize(format, plain_text, encryptor, cipher, match = '', indentation = '', id = nil)
|
26
|
+
@format = format
|
27
|
+
@plain_text = plain_text
|
28
|
+
@encryptor = encryptor
|
29
|
+
@cipher = cipher
|
30
|
+
@indentation = indentation
|
31
|
+
@id = id
|
32
|
+
super(match)
|
33
|
+
end
|
34
|
+
|
35
|
+
def to_encrypted(args={})
|
36
|
+
label = args[:label]
|
37
|
+
label_string = label.nil? ? '' : "#{label}: "
|
38
|
+
format = args[:format].nil? ? @format : args[:format]
|
39
|
+
case format
|
40
|
+
when :block
|
41
|
+
ciphertext = @cipher.gsub(/\n/, "\n" + @indentation)
|
42
|
+
chevron = (args[:use_chevron].nil? || args[:use_chevron]) ? ">\n" : ''
|
43
|
+
"#{label_string}#{chevron}" + @indentation + "ENC[#{@encryptor.tag},#{ciphertext}]"
|
44
|
+
when :string
|
45
|
+
ciphertext = @cipher.gsub(/\n/, "")
|
46
|
+
"#{label_string}ENC[#{@encryptor.tag},#{ciphertext}]"
|
47
|
+
else
|
48
|
+
raise "#{@format} is not a valid format"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def to_decrypted(args={})
|
53
|
+
label = args[:label]
|
54
|
+
label_string = label.nil? ? '' : "#{label}: "
|
55
|
+
format = args[:format].nil? ? @format : args[:format]
|
56
|
+
index = args[:index].nil? ? '' : "(#{args[:index]})"
|
57
|
+
case format
|
58
|
+
when :block
|
59
|
+
chevron = (args[:use_chevron].nil? || args[:use_chevron]) ? ">\n" : ''
|
60
|
+
"#{label_string}#{chevron}" + indentation + "DEC#{index}::#{@encryptor.tag}[" + @plain_text + "]!"
|
61
|
+
when :string
|
62
|
+
"#{label_string}DEC#{index}::#{@encryptor.tag}[" + @plain_text + "]!"
|
63
|
+
else
|
64
|
+
raise "#{@format} is not a valid format"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_plain_text
|
69
|
+
@plain_text
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
class EncTokenType < TokenType
|
75
|
+
def create_enc_token(match, type, enc_comma, cipher, indentation = '')
|
76
|
+
encryption_scheme = enc_comma.nil? ? Eyaml.default_encryption_scheme : enc_comma.split(",").first
|
77
|
+
EncToken.encrypted_value(type, encryption_scheme, cipher, match, indentation)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class EncHieraTokenType < EncTokenType
|
82
|
+
def initialize
|
83
|
+
@regex = /ENC\[(\w+,)?([a-zA-Z0-9\+\/ =\n]+?)\]/
|
84
|
+
@string_token_type = EncStringTokenType.new()
|
85
|
+
end
|
86
|
+
def create_token(string)
|
87
|
+
@string_token_type.create_token(string.gsub(/[ \n]/, ''))
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class EncStringTokenType < EncTokenType
|
92
|
+
def initialize
|
93
|
+
@regex = /ENC\[(\w+,)?([a-zA-Z0-9\+\/=]+?)\]/
|
94
|
+
end
|
95
|
+
def create_token(string)
|
96
|
+
md = @regex.match(string)
|
97
|
+
self.create_enc_token(string, :string, md[1], md[2])
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
class EncBlockTokenType < EncTokenType
|
102
|
+
def initialize
|
103
|
+
@regex = />\n(\s*)ENC\[(\w+,)?([a-zA-Z0-9\+\/ =\n]+?)\]/
|
104
|
+
end
|
105
|
+
def create_token(string)
|
106
|
+
md = @regex.match(string)
|
107
|
+
self.create_enc_token(string, :block, md[2], md[3], md[1])
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class DecStringTokenType < TokenType
|
112
|
+
def initialize
|
113
|
+
@regex = /DEC(\(\d+\))?::(\w+)\[(.+?)\]\!/
|
114
|
+
end
|
115
|
+
def create_token(string)
|
116
|
+
md = @regex.match(string)
|
117
|
+
EncToken.decrypted_value(:string, md[3], md[2], string, md[1])
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class DecBlockTokenType < TokenType
|
122
|
+
def initialize
|
123
|
+
@regex = />\n(\s*)DEC(\(\d+\))?::(\w+)\[(.+?)\]\!/
|
124
|
+
end
|
125
|
+
def create_token(string)
|
126
|
+
md = @regex.match(string)
|
127
|
+
EncToken.decrypted_value(:block, md[4], md[3], string, md[2], md[1])
|
128
|
+
EncToken.decrypted_value(:block, md[4], md[3], string, md[2], md[1])
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'strscan'
|
2
|
+
require 'hiera/backend/eyaml/parser/token'
|
3
|
+
require 'hiera/backend/eyaml/parser/encrypted_tokens'
|
4
|
+
|
5
|
+
class Hiera
|
6
|
+
module Backend
|
7
|
+
module Eyaml
|
8
|
+
module Parser
|
9
|
+
class ParserFactory
|
10
|
+
def self.encrypted_parser
|
11
|
+
enc_string = EncStringTokenType.new()
|
12
|
+
enc_block = EncBlockTokenType.new()
|
13
|
+
Parser.new([enc_string, enc_block])
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.decrypted_parser
|
17
|
+
dec_string = DecStringTokenType.new()
|
18
|
+
dec_block = DecBlockTokenType.new()
|
19
|
+
Parser.new([dec_string, dec_block])
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.hiera_backend_parser
|
23
|
+
enc_hiera = EncHieraTokenType.new()
|
24
|
+
Parser.new([enc_hiera])
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class Parser
|
29
|
+
attr_reader :token_types
|
30
|
+
|
31
|
+
def initialize(token_types)
|
32
|
+
@token_types = token_types
|
33
|
+
end
|
34
|
+
|
35
|
+
def parse text
|
36
|
+
parse_scanner(StringScanner.new(text)).reverse
|
37
|
+
end
|
38
|
+
|
39
|
+
def parse_scanner s
|
40
|
+
if s.eos?
|
41
|
+
[]
|
42
|
+
else
|
43
|
+
# Check if the scanner currently matches a regex
|
44
|
+
current_match = @token_types.find { |token_type|
|
45
|
+
s.match?(token_type.regex)
|
46
|
+
}
|
47
|
+
|
48
|
+
token =
|
49
|
+
if current_match.nil?
|
50
|
+
# No regex matches here. Find the earliest match.
|
51
|
+
next_match_indexes = @token_types.map { |token_type|
|
52
|
+
next_match = s.check_until(token_type.regex)
|
53
|
+
if next_match.nil?
|
54
|
+
nil
|
55
|
+
else
|
56
|
+
next_match.length - s.matched.length
|
57
|
+
end
|
58
|
+
}.reject { |i| i.nil? }
|
59
|
+
non_match_size =
|
60
|
+
if next_match_indexes.length == 0
|
61
|
+
s.rest_size
|
62
|
+
else
|
63
|
+
next_match_indexes.min
|
64
|
+
end
|
65
|
+
non_match = s.peek(non_match_size)
|
66
|
+
# advance scanner
|
67
|
+
s.pos = s.pos + non_match_size
|
68
|
+
NonMatchToken.new(non_match)
|
69
|
+
else
|
70
|
+
# A regex matches so create a token and do a recursive call with the advanced scanner
|
71
|
+
current_match.create_token s.scan(current_match.regex)
|
72
|
+
end
|
73
|
+
|
74
|
+
self.parse_scanner(s) << token
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
class Hiera
|
2
|
+
module Backend
|
3
|
+
module Eyaml
|
4
|
+
module Parser
|
5
|
+
class TokenType
|
6
|
+
attr_reader :regex
|
7
|
+
@regex
|
8
|
+
def create_token string
|
9
|
+
raise 'Abstract method called'
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Token
|
14
|
+
attr_reader :match
|
15
|
+
def initialize(match)
|
16
|
+
@match = match
|
17
|
+
end
|
18
|
+
def to_encrypted(args={})
|
19
|
+
raise 'Abstract method called'
|
20
|
+
end
|
21
|
+
def to_decrypted(args={})
|
22
|
+
raise 'Abstract method called'
|
23
|
+
end
|
24
|
+
def to_plain_text
|
25
|
+
raise 'Abstract method called'
|
26
|
+
end
|
27
|
+
def to_s
|
28
|
+
"#{self.class.name}:#{@match}"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
class NonMatchToken < Token
|
33
|
+
def initialize(non_match)
|
34
|
+
super(non_match)
|
35
|
+
end
|
36
|
+
def to_encrypted(args={})
|
37
|
+
@match
|
38
|
+
end
|
39
|
+
def to_decrypted(args={})
|
40
|
+
@match
|
41
|
+
end
|
42
|
+
def to_plain_text
|
43
|
+
@match
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -40,7 +40,7 @@ class Hiera
|
|
40
40
|
if Gem::VERSION >= "1.8.0"
|
41
41
|
file = spec.matches_for_glob("**/eyaml_init.rb").first
|
42
42
|
else
|
43
|
-
file = Gem.searcher.matching_files(spec, "eyaml_init.rb").first
|
43
|
+
file = Gem.searcher.matching_files(spec, "**/eyaml_init.rb").first
|
44
44
|
end
|
45
45
|
|
46
46
|
next unless file
|
@@ -72,7 +72,7 @@ class Hiera
|
|
72
72
|
unless File.directory? key_dir
|
73
73
|
begin
|
74
74
|
FileUtils.mkdir_p key_dir
|
75
|
-
|
75
|
+
Utils::info "Created key directory: #{key_dir}"
|
76
76
|
rescue
|
77
77
|
raise StandardError, "Cannot create key directory: #{key_dir}"
|
78
78
|
end
|
@@ -80,6 +80,14 @@ class Hiera
|
|
80
80
|
|
81
81
|
end
|
82
82
|
|
83
|
+
def self.info message
|
84
|
+
STDERR.puts message unless Eyaml::Options[:quiet]
|
85
|
+
end
|
86
|
+
|
87
|
+
def self.debug message
|
88
|
+
STDERR.puts message if Eyaml::Options[:debug]
|
89
|
+
end
|
90
|
+
|
83
91
|
end
|
84
92
|
end
|
85
93
|
end
|
@@ -1,6 +1,7 @@
|
|
1
1
|
require 'hiera/backend/eyaml/encryptor'
|
2
2
|
require 'hiera/backend/eyaml/actions/decrypt_action'
|
3
3
|
require 'hiera/backend/eyaml/utils'
|
4
|
+
require 'hiera/backend/eyaml/parser/parser'
|
4
5
|
require 'yaml'
|
5
6
|
|
6
7
|
class Hiera
|
@@ -95,11 +96,10 @@ class Hiera
|
|
95
96
|
|
96
97
|
Eyaml::Options[:source] = "hiera"
|
97
98
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
}
|
99
|
+
parser = Eyaml::Parser::ParserFactory.hiera_backend_parser
|
100
|
+
tokens = parser.parse(value)
|
101
|
+
decrypted = tokens.map{ |token| token.to_plain_text }
|
102
|
+
plaintext = decrypted.join
|
103
103
|
|
104
104
|
plaintext.chomp
|
105
105
|
|
metadata
CHANGED
@@ -1,46 +1,41 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hiera-eyaml
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.3.
|
5
|
-
prerelease:
|
4
|
+
version: 1.3.5
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- Tom Poulton
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-11-12 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: trollop
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
|
-
- -
|
17
|
+
- - '>='
|
20
18
|
- !ruby/object:Gem::Version
|
21
19
|
version: '2.0'
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
|
-
- -
|
24
|
+
- - '>='
|
28
25
|
- !ruby/object:Gem::Version
|
29
26
|
version: '2.0'
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: highline
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
|
-
- -
|
31
|
+
- - '>='
|
36
32
|
- !ruby/object:Gem::Version
|
37
33
|
version: 1.6.19
|
38
34
|
type: :runtime
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
|
-
- -
|
38
|
+
- - '>='
|
44
39
|
- !ruby/object:Gem::Version
|
45
40
|
version: 1.6.19
|
46
41
|
description: Hiera backend for decrypting encrypted yaml properties
|
@@ -68,6 +63,9 @@ files:
|
|
68
63
|
- lib/hiera/backend/eyaml/encryptor.rb
|
69
64
|
- lib/hiera/backend/eyaml/encryptors/pkcs7.rb
|
70
65
|
- lib/hiera/backend/eyaml/options.rb
|
66
|
+
- lib/hiera/backend/eyaml/parser/encrypted_tokens.rb
|
67
|
+
- lib/hiera/backend/eyaml/parser/parser.rb
|
68
|
+
- lib/hiera/backend/eyaml/parser/token.rb
|
71
69
|
- lib/hiera/backend/eyaml/plugins.rb
|
72
70
|
- lib/hiera/backend/eyaml/utils.rb
|
73
71
|
- lib/hiera/backend/eyaml_backend.rb
|
@@ -78,26 +76,25 @@ files:
|
|
78
76
|
homepage: http://github.com/TomPoulton/hiera-eyaml
|
79
77
|
licenses:
|
80
78
|
- MIT
|
79
|
+
metadata: {}
|
81
80
|
post_install_message:
|
82
81
|
rdoc_options: []
|
83
82
|
require_paths:
|
84
83
|
- lib
|
85
84
|
required_ruby_version: !ruby/object:Gem::Requirement
|
86
|
-
none: false
|
87
85
|
requirements:
|
88
|
-
- -
|
86
|
+
- - '>='
|
89
87
|
- !ruby/object:Gem::Version
|
90
88
|
version: '0'
|
91
89
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
92
|
-
none: false
|
93
90
|
requirements:
|
94
|
-
- -
|
91
|
+
- - '>='
|
95
92
|
- !ruby/object:Gem::Version
|
96
93
|
version: '0'
|
97
94
|
requirements: []
|
98
95
|
rubyforge_project:
|
99
|
-
rubygems_version:
|
96
|
+
rubygems_version: 2.0.11
|
100
97
|
signing_key:
|
101
|
-
specification_version:
|
98
|
+
specification_version: 4
|
102
99
|
summary: OpenSSL Encryption backend for Hiera
|
103
100
|
test_files: []
|