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.
@@ -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
@@ -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.5)
11
+ cucumber (1.3.9)
12
12
  builder (>= 2.1.2)
13
13
  diff-lcs (>= 1.1.3)
14
- gherkin (~> 2.12.0)
15
- multi_json (~> 1.7.5)
14
+ gherkin (~> 2.12)
15
+ multi_json (>= 1.7.5, < 2.0)
16
16
  multi_test (>= 0.0.2)
17
- diff-lcs (1.2.4)
18
- ffi (1.9.0)
19
- gherkin (2.12.0)
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-eyaml (1.2.0)
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.1)
25
- hiera-eyaml (>= 1.2.0)
26
- highline (1.6.19)
27
- multi_json (1.7.8)
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
- rspec-expectations (2.14.0)
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/private_key_file.pem
112
- :pkcs7_public_key: /path/to/public_key_file.pem
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
 
@@ -2,7 +2,7 @@ class Hiera
2
2
  module Backend
3
3
  module Eyaml
4
4
 
5
- VERSION = "1.3.4"
5
+ VERSION = "1.3.5"
6
6
 
7
7
  def self.default_encryption_scheme= new_encryption
8
8
  @@default_encryption_scheme = new_encryption
@@ -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 it taken from stdin", :short => 'z'
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
- puts action_class.execute
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
- REGEX_ENCRYPTED_BLOCK = />\n(\s*)ENC\[(\w+,)?([a-zA-Z0-9\+\/ =\n]+)\]/
12
- REGEX_ENCRYPTED_STRING = /ENC\[(\w+,)?([a-zA-Z0-9\+\/=]+)\]/
13
-
14
- def self.execute
15
-
16
- output_data = case Eyaml::Options[:source]
17
- when :eyaml
18
- encryptions = []
19
-
20
- # blocks
21
- output = Eyaml::Options[:input_data].gsub( REGEX_ENCRYPTED_BLOCK ) { |match|
22
- indentation = $1
23
- encryption_scheme = parse_encryption_scheme( $2 )
24
- decryptor = Encryptor.find encryption_scheme
25
- ciphertext = $3.gsub(/[ \n]/, '')
26
- plaintext = decryptor.decrypt( decryptor.decode ciphertext )
27
- ">\n" + indentation + "DEC::#{decryptor.tag}[" + plaintext + "]!"
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
- decrypted_input = DecryptAction.execute
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
- Eyaml::Options[:input_data] = edited_file
30
- Eyaml::Options[:output] = "raw"
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
- encrypted_output = EncryptAction.execute
60
+ encrypted_output = edited_denoised_tokens.map{ |t| t.to_encrypted }.join
33
61
 
34
- filename = Eyaml::Options[:eyaml]
35
- File.open("#{filename}", 'w') { |file|
36
- file.write encrypted_output
37
- }
62
+ filename = Eyaml::Options[:eyaml]
63
+ File.open("#{filename}", 'w') { |file|
64
+ file.write encrypted_output
65
+ }
66
+ end
38
67
 
39
- true
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
- when :eyaml
17
- encryptions = []
18
-
19
- # blocks
20
- output = Eyaml::Options[:input_data].gsub( REGEX_DECRYPTED_BLOCK ) { |match|
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
- data.to_s
79
- end
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
- STDERR.puts format_message msg
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
- STDERR.puts format_message msg
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
- puts "#{k.class.name}:#{k} = #{v.class.name}:#{v}"
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
- puts "Created key directory: #{key_dir}"
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
- plaintext = value.gsub( /ENC\[([^\]]*)\]/ ) { |match|
99
- Eyaml::Options[:input_data] = deblock match.to_s
100
- Eyaml::Options[:output] = "raw"
101
- Eyaml::Actions::DecryptAction.execute
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.4
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-09-10 00:00:00.000000000 Z
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: 1.8.25
96
+ rubygems_version: 2.0.11
100
97
  signing_key:
101
- specification_version: 3
98
+ specification_version: 4
102
99
  summary: OpenSSL Encryption backend for Hiera
103
100
  test_files: []