class SymmetricEncryption::Utils::Aws
Wrap the AWS KMS client so that it automatically creates the Customer Master Key
, if one does not already exist.
Map OpenSSL cipher names to AWS KMS key specs.
Constants
- AWS_KEY_SPEC_MAP
TODO: Map to OpenSSL ciphers
- AWS_US_REGIONS
Attributes
Public Class Methods
TODO: Move to Keystore::Aws
Rotate the Customer Master key in each of the supplied regions. After the master key has been rotated, use `.write_key_files` to generate a new DEK and re-encrypt with the new CMK in each region. def self.rotate_master_key(master_key_alias
:, cipher_name:, regions: AWS_US_REGIONS
)
Array(regions).collect do |region| key_manager = new(region: region, master_key_alias: master_key_alias, cipher_name: cipher_name) key_id = key_manager.create_master_key key_manager.create_alias(key_id) end
end
# File lib/symmetric_encryption/utils/aws.rb, line 32 def initialize(region:, master_key_alias:) # Can region be read from environment? # Region is required for filename / env var name @client = ::Aws::KMS::Client.new(region: region) @master_key_alias = master_key_alias end
Public Instance Methods
Creates a new master key along with an alias that points to it. Returns [String] the new master key id that was created.
# File lib/symmetric_encryption/utils/aws.rb, line 77 def create_master_key key_id = create_new_master_key create_alias(key_id) key_id end
Decrypt data previously encrypted using the cmk
# File lib/symmetric_encryption/utils/aws.rb, line 54 def decrypt(encrypted_data) auto_create_master_key do client.decrypt(ciphertext_blob: encrypted_data).plaintext end end
Deletes the current master key and its alias.
retention_days: Number of days to keep the CMK before completely destroying it.
NOTE:
Use with caution, only intended for testing purposes !!!
# File lib/symmetric_encryption/utils/aws.rb, line 89 def delete_master_key(retention_days: 30) key_info = client.describe_key(key_id: master_key_alias) ap key_info resp = client.schedule_key_deletion(key_id: key_info.key_metadata.key_id, pending_window_in_days: retention_days) ap client.delete_alias(alias_name: master_key_alias) resp.deletion_date rescue ::Aws::KMS::Errors::NotFoundException nil end
Decrypt data previously encrypted using the cmk
# File lib/symmetric_encryption/utils/aws.rb, line 61 def encrypt(data) auto_create_master_key do client.encrypt(key_id: master_key_alias, plaintext: data).ciphertext_blob end end
Returns a new DEK in the clear
# File lib/symmetric_encryption/utils/aws.rb, line 47 def generate_data_key(cipher_name) auto_create_master_key do client.generate_data_key(key_id: master_key_alias, key_spec: key_spec(cipher_name)).plaintext end end
Returns a new DEK encrypted using the CMK
# File lib/symmetric_encryption/utils/aws.rb, line 40 def generate_encrypted_data_key(cipher_name) auto_create_master_key do client.generate_data_key_without_plaintext(key_id: master_key_alias, key_spec: key_spec(cipher_name)).ciphertext_blob end end
Returns the AWS KMS key spec that matches the supplied OpenSSL cipher name
# File lib/symmetric_encryption/utils/aws.rb, line 68 def key_spec(cipher_name) key_spec = AWS_KEY_SPEC_MAP[cipher_name] raise("OpenSSL Cipher: #{cipher_name} has not yet been mapped to an AWS key spec.") unless key_spec key_spec end
Private Instance Methods
# File lib/symmetric_encryption/utils/aws.rb, line 127 def auto_create_master_key attempt = 1 yield rescue ::Aws::KMS::Errors::NotFoundException raise if attempt >= 2 create_master_key attempt += 1 retry end
# File lib/symmetric_encryption/utils/aws.rb, line 121 def create_alias(key_id) # TODO: Add error handling and retry # TODO: Move existing alias if any client.create_alias(alias_name: master_key_alias, target_key_id: key_id) end
Creates a new Customer Master Key
for Symmetric Encryption use.
# File lib/symmetric_encryption/utils/aws.rb, line 108 def create_new_master_key # TODO: Add error handling and retry resp = client.create_key( description: "Symmetric Encryption for Ruby Customer Masker Key", tags: [ {tag_key: "CreatedAt", tag_value: Time.now.to_s}, {tag_key: "CreatedBy", tag_value: whoami} ] ) resp.key_metadata.key_id end
# File lib/symmetric_encryption/utils/aws.rb, line 101 def whoami @whoami ||= `whoami`.strip rescue StandardError @whoami = "unknown" end