module Vault::Transit
Constants
- DEFAULT_ENCODING
The default encoding.
@return [String]
- DEV_WARNING
The warning string to print when running in development mode.
- VERSION
Attributes
Public Class Methods
Decrypt the given ciphertext data using the provided key.
@param [String] key
the key to decrypt at
@param [String] ciphertext
the ciphertext to decrypt
@param [Vault::Client] client
the Vault client to use
@return [String]
the decrypted plaintext text
# File lib/vault/transit.rb, line 60 def decrypt(key, ciphertext, client = self.client) if ciphertext.nil? || ciphertext.empty? return ciphertext end key = key.to_s if !key.is_a?(String) with_retries_and_reauthentication do if self.enabled? result = self.vault_decrypt(key, ciphertext, client) else result = self.memory_decrypt(key, ciphertext, client) end return self.force_encoding(result) end end
Encrypt the given plaintext data using the provided key.
@param [String] key
the key to encrypt at
@param [String] plaintext
the plaintext to encrypt
@param [Vault::Client] client
the Vault client to use
@return [String]
the encrypted cipher text
# File lib/vault/transit.rb, line 89 def encrypt(key, plaintext, client = self.client) if plaintext.nil? || plaintext.empty? return plaintext end key = key.to_s if !key.is_a?(String) with_retries_and_reauthentication do if self.enabled? result = self.vault_encrypt(key, plaintext, client) else result = self.memory_encrypt(key, plaintext, client) end return self.force_encoding(result) end end
Delegate all methods to the client object, essentially making the module object behave like a {Vault::Client}.
# File lib/vault/transit.rb, line 36 def method_missing(m, *args, &block) if client.respond_to?(m) client.public_send(m, *args, &block) else super end end
Delegating `respond_to` to the {Vault::Client}.
# File lib/vault/transit.rb, line 45 def respond_to_missing?(m, include_private = false) client.respond_to?(m, include_private) || super end
Rewrap the given ciphertext data using the provided key.
@param [String] key
the key to rewrap at
@param [String] ciphertext
the ciphertext to rewrap
@param [Vault::Client] client
the Vault client to use
@return [String]
the rewrapped ciphertext text
# File lib/vault/transit.rb, line 118 def rewrap(key, ciphertext, client = self.client) if ciphertext.nil? || ciphertext.empty? return ciphertext end key = key.to_s unless key.is_a?(String) route = File.join("transit", "rewrap", key) with_retries_and_reauthentication do if self.enabled? secret = client.logical.write(route, ciphertext: ciphertext, ) result = secret.data[:ciphertext] else result = ciphertext end return self.force_encoding(result) end end
Rotate the key to a new version
@param [String] key
the key to rotate
@param [Vault::Client] client
the Vault client to use
# File lib/vault/transit.rb, line 146 def rotate(key, client = self.client) key = key.to_s unless key.is_a?(String) route = File.join("transit", "keys", key, "rotate") with_retries_and_reauthentication do if self.enabled? client.logical.write(route) end end end
Set the minimum decryption version a using the provided key.
@param [String] key
the key to configure
@param [int] min_decryption_version
the new minimum decryption version
@param [Vault::Client] client
the Vault client to use
# File lib/vault/transit.rb, line 166 def set_min_decryption_version(key, min_decryption_version, client = self.client) key = key.to_s unless key.is_a?(String) with_retries_and_reauthentication do if self.enabled? route = File.join("transit", "keys", key, "config") client.logical.write(route, min_decryption_version: min_decryption_version, ) end end end
# File lib/vault/transit.rb, line 24 def setup! ::Vault.setup! @client = ::Vault.client @client.class.instance_eval do include ::Vault::Transit::Configurable end self end
Protected Class Methods
Forces the encoding into the default Rails encoding and returns the newly encoded string. @return [String]
# File lib/vault/transit.rb, line 237 def force_encoding(str) encoding = ::Rails.application.config.encoding if defined? ::Rails encoding ||= DEFAULT_ENCODING str.force_encoding(encoding).encode(encoding) end
Perform in-memory decryption. This is useful for testing and development.
# File lib/vault/transit.rb, line 182 def memory_decrypt(key, ciphertext, client) log_warning(DEV_WARNING) return nil if ciphertext.nil? cipher = OpenSSL::Cipher::AES.new(128, :CBC) cipher.decrypt cipher.key = memory_key_for(key) ciphertext = ciphertext.gsub("vault:v0:", "") return cipher.update(Base64.strict_decode64(ciphertext)) + cipher.final end
Perform in-memory encryption. This is useful for testing and development.
# File lib/vault/transit.rb, line 195 def memory_encrypt(key, plaintext, client) log_warning(DEV_WARNING) return nil if plaintext.nil? cipher = OpenSSL::Cipher::AES.new(128, :CBC) cipher.encrypt cipher.key = memory_key_for(key) return "vault:v0:" + Base64.strict_encode64(cipher.update(plaintext) + cipher.final) end
The symmetric key for the given params. @return [String]
# File lib/vault/transit.rb, line 230 def memory_key_for(key) return Base64.strict_encode64(key.ljust(32, "x")) end
Perform decryption using Vault
. This will raise exceptions if Vault
is unavailable.
# File lib/vault/transit.rb, line 208 def vault_decrypt(key, ciphertext, client) return nil if ciphertext.nil? route = File.join("transit", "decrypt", key) secret = client.logical.write(route, ciphertext: ciphertext) return Base64.strict_decode64(secret.data[:plaintext]) end
Perform encryption using Vault
. This will raise exceptions if Vault
is unavailable.
# File lib/vault/transit.rb, line 218 def vault_encrypt(key, plaintext, client) return nil if plaintext.nil? route = File.join("transit", "encrypt", key) secret = client.logical.write(route, plaintext: Base64.strict_encode64(plaintext), ) return secret.data[:ciphertext] end
Private Class Methods
# File lib/vault/transit.rb, line 245 def log_warning(msg) if defined?(::Rails) && ::Rails.logger != nil ::Rails.logger.warn { msg } end end
# File lib/vault/transit.rb, line 251 def permission_denied?(error) error.errors.include? "permission denied" end
# File lib/vault/transit.rb, line 255 def reauthenticate! return nil unless ENV["VAULT_APP_ID"] && ENV["VAULT_SYSTEM_ID"] secret = ::Vault::Transit.auth.app_id(ENV["VAULT_APP_ID"], ENV["VAULT_SYSTEM_ID"]) ::Vault::Transit.token = secret.auth.client_token end
# File lib/vault/transit.rb, line 261 def with_reauthentication(client = self.client, &block) retries ||= 0 reauthenticate! if self.enabled? && self.token.nil? yield rescue ::Vault::HTTPError => error raise unless permission_denied?(error) reauthenticate! retry if (retries += 1) < 2 raise end
# File lib/vault/transit.rb, line 273 def with_retries(client = self.client, &block) exceptions = [Vault::HTTPConnectionError, Vault::HTTPServerError] options = { attempts: self.retry_attempts, base: self.retry_base, max_wait: self.retry_max_wait, } client.with_retries(*exceptions, options) do |i, e| if !e.nil? log_warning "[vault-transit] (#{i}) An error occurred when trying to " \ "communicate with Vault: #{e.message}" end yield end end
# File lib/vault/transit.rb, line 291 def with_retries_and_reauthentication(client = self.client, &block) with_reauthentication do with_retries do yield end end end