Class: Hiera::Backend::Eyaml::Encryptors::Gpg

Inherits:
Encryptor
  • Object
show all
Defined in:
lib/hiera/backend/eyaml/encryptors/gpg.rb

Constant Summary collapse

VERSION =
Hiera::Backend::Eyaml::Encryptors::GpgVersion::VERSION

Class Method Summary collapse

Class Method Details

.create_keysObject



158
159
160
# File 'lib/hiera/backend/eyaml/encryptors/gpg.rb', line 158

def self.create_keys
  STDERR.puts 'The GPG encryptor does not support creation of keys, use the GPG command lines tools instead'
end

.decrypt(ciphertext) ⇒ Object



119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
# File 'lib/hiera/backend/eyaml/encryptors/gpg.rb', line 119

def self.decrypt(ciphertext)
  gnupghome = self.gnupghome

  unless defined?(GPGME)
    gpg = Hiera::Backend::Eyaml::GpgPuppetserver
    gpg.config.homedir = gnupghome if gnupghome
    return gpg.decrypt_string(ciphertext)
  end

  GPGME::Engine.home_dir = gnupghome

  ctx = if hiera?
          GPGME::Ctx.new
        else
          GPGME::Ctx.new(passphrase_callback: method(:passfunc))
        end

  if !ctx.keys.empty?
    raw = GPGME::Data.new(ciphertext)
    txt = GPGME::Data.new

    begin
      txt = ctx.decrypt(raw)
    rescue GPGME::Error::DecryptFailed => e
      warn('Fatal: Failed to decrypt ciphertext (check settings and that you are a recipient)')
      raise e
    rescue StandardError => e
      warn('Warning: General exception decrypting GPG file')
      raise e
    end

    txt.seek 0
    txt.read
  else
    warn("No usable keys found in #{gnupghome}. Check :gpg_gnupghome value in hiera.yaml is correct")
    raise ArgumentError, "No usable keys found in #{gnupghome}. Check :gpg_gnupghome value in hiera.yaml is correct"
  end
end

.encrypt(plaintext) ⇒ Object

Raises:

  • (RecoverableError)


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
# File 'lib/hiera/backend/eyaml/encryptors/gpg.rb', line 77

def self.encrypt(plaintext)
  unless defined?(GPGME)
    raise RecoverableError, "Encryption is only supported when using the 'gpgme' gem"
  end

  GPGME::Engine.home_dir = gnupghome

  ctx = GPGME::Ctx.new

  recipients = find_recipients
  debug("Recipents are #{recipients}")

  raise RecoverableError, 'No recipients provided, don\'t know who to encrypt to' if recipients.empty?

  keys = recipients.map do |r|
    key_to_use = ctx.keys(r).first
    if key_to_use.nil?
      raise RecoverableError, "No key found on keyring for #{r}"
    end
    key_to_use
  end
  debug("Keys: #{keys}")

  always_trust = option(:always_trust)
  unless always_trust
    # check validity of recipients (this is possibly naive, but better than the unhelpful
    # error that it would spit out otherwise)
    keys.each do |key|
      unless key.primary_uid.validity >= GPGME::VALIDITY_FULL
        raise RecoverableError, "Key #{key.sha} (#{key.email}) not trusted (if key trust is established by another means then specify always-trust)"
      end
    end
  end

  data = GPGME::Data.from_str(plaintext)
  crypto = GPGME::Crypto.new(always_trust: always_trust)

  ciphertext = crypto.encrypt(data, recipients: keys)
  ciphertext.seek 0
  ciphertext.read
end

.gnupghomeObject



59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/hiera/backend/eyaml/encryptors/gpg.rb', line 59

def self.gnupghome
  gnupghome = if ENV['HIERA_EYAML_GPG_GNUPGHOME'].nil?
                option :gnupghome
              else
                ENV['HIERA_EYAML_GPG_GNUPGHOME']
              end
  debug("GNUPGHOME is #{gnupghome}")
  if gnupghome.nil? || gnupghome.empty?
    warn('No GPG home directory configured, check gpg_gnupghome configuration value is correct')
    raise ArgumentError, 'No GPG home directory configured, check gpg_gnupghome configuration value is correct'
  elsif !File.directory?(gnupghome)
    warn("Configured GPG home directory #{gnupghome} doesn't exist, check gpg_gnupghome configuration value is correct")
    raise ArgumentError, "Configured GPG home directory #{gnupghome} doesn't exist, check gpg_gnupghome configuration value is correct"
  else
    gnupghome
  end
end

.passfunc(_hook, uid_hint, _passphrase_info, _prev_was_bad, fd) ⇒ Object



42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/hiera/backend/eyaml/encryptors/gpg.rb', line 42

def self.passfunc(_hook, uid_hint, _passphrase_info, _prev_was_bad, fd)
  system('stty -echo')

  unless @passphrase_cache.key?(uid_hint)
    @passphrase_cache[uid_hint] = ask("Enter passphrase for #{uid_hint}: ") { |q| q.echo = '' }
    $stderr.puts
  end
  passphrase = @passphrase_cache[uid_hint]

  io = IO.for_fd(fd, 'w')
  io.puts(passphrase)
  io.flush
ensure
  (0...$LAST_READ_LINE.length).each { |i| $LAST_READ_LINE[i] = '0' } if $LAST_READ_LINE
  system('stty echo')
end