voxpupuli / hiera-eyaml

A backend for Hiera that provides per-value asymmetric encryption of sensitive data
MIT License
527 stars 130 forks source link

`eyaml decrypt` for hiera values with newlines is not well-formed YAML #176

Open r4v5 opened 9 years ago

r4v5 commented 9 years ago

I'm trying to write something that verifies eyaml-encrypted secrets (think SSH or SSL keys and making sure that the public key and private key match within a precommit hook). However, hiera-eyaml 2.0.7 doesn't seem to handle newlines properly in an eyaml decrypt. For instance:

% echo "line1
line2
line3" | eyaml encrypt --stdin -o block -l key
key: >
    ENC[PKCS7,MIIBiQYJKoZIhvcNAQcDoIIBejCCAXYCAQAxggEhMIIBHQIBADAFMAACAQEw
    DQYJKoZIhvcNAQEBBQAEggEAK880nZE8zYawt/V/Xby1xVRs1oGPGPyIYJtx
    JWwxJXSbgXAVVgdOs9GziVm9h5qs3UJh4nyvpSsmkWA7NwyaVqghNfFW9Nrp
    LNBbul/AYpXtRCCzDiM3o6yhVwKiD6O617sxkXbrLEMmMbtNQIjGljhF99UC
    sjS2NAls8bj4S9qWwQreHzbuq1b/hZdNSKEQT/RPgd+UDa5fSsGLjttm+/DN
    r/5yzTQd2lxnjZPXx0M/qpJ+QQ4ysiCZtu1IZOIGmdrtCbaE0+IcKDjyKQOH
    CywUP2IJJvK2CtQoBwTXAIv27tFMfF9tNplqw8U9lAXFNVvlpzEmSVBzW5lz
    JDXfFzBMBgkqhkiG9w0BBwEwHQYJYIZIAWUDBAEqBBA+oruEuGnbeoBV7vVM
    NgeLgCClNIZMfkn4FRm6EiY2R3j7kBq/EA3ECMmXlnPpi/xq0w==]
% echo "line1
line2
line3" | eyaml encrypt --stdin -o block -l key > test.eyaml
% eyaml decrypt -f test.eyaml
key: line1
line2
line3

% eyaml decrypt -f test.eyaml > test.yaml
% irb
2.1.2 :001 > require 'yaml'
 => true
2.1.2 :002 > YAML.load_file('test.yaml')
Psych::SyntaxError: (test.yaml): could not find expected ':' while scanning a simple key at line 2 column 1
        from /Users/mdonahue/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych.rb:370:in `parse'
        from /Users/mdonahue/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych.rb:370:in `parse_stream'
        from /Users/mdonahue/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych.rb:318:in `parse'
        from /Users/mdonahue/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych.rb:245:in `load'
        from /Users/mdonahue/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych.rb:464:in `block in load_file'
        from /Users/mdonahue/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych.rb:464:in `open'
        from /Users/mdonahue/.rvm/rubies/ruby-2.1.2/lib/ruby/2.1.0/psych.rb:464:in `load_file'
        from (irb):2
        from /Users/mdonahue/.rvm/rubies/ruby-2.1.2/bin/irb:11:in `<main>'

I'd expect the output to be parseable by psych. It looks like, if the encrypted value contains a newline, we'd want the output to be similar to:

key: |
  line1
  line2
  line3
j1n6 commented 8 years ago

I have the same issue. Are there any workaround?

TomPoulton commented 8 years ago

You could use a small ruby script to "clean" the string before parsing it to eyaml

# clean.rb
string = ARGF.read
string = string.strip().gsub(/\n/, '\n')
puts "\"#{string}\""
$ echo "line1
line2
line3" | ruby clean.rb | eyaml encrypt --stdin -o block -l key > test.eyaml
$ eyaml decrypt -f test.eyaml > test.yaml
$ cat test.yaml
key: "line1\nline2\nline3"

$ irb
irb(main):001:0> require 'yaml'
=> true
irb(main):002:0> puts YAML.load_file('test.yaml')['key']
line1
line2
line3

This won't use the YAML multiline literal syntax (|) but it will preserve the newlines in the value

The string input version is simpler, you just wrap the string in double and single quotes to preserve the newlines:

$ eyaml encrypt -s '"line1\nline2\nline3"' -o block -l key > test.eyaml
$ eyaml decrypt -f test.eyaml > test.yaml
$ cat test.yaml
key: "line1\nline2\nline3"
peculater commented 8 years ago

I have a branch over at https://github.com/peculater/hiera-eyaml/tree/multiline-values that seems to work for this. I'm not quite confident in it enough to make a PR, but will likely be shortly. We started using it in prod today. ;-)