Class: SymmetricEncryption::Utils::Aws

Inherits:
Object
  • Object
show all
Defined in:
lib/symmetric_encryption/utils/aws.rb

Overview

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.

Constant Summary collapse

AWS_US_REGIONS =
%w[us-east-1 us-east-2 us-west-1 us-west-2].freeze
AWS_KEY_SPEC_MAP =

TODO: Map to OpenSSL ciphers

{
  'aes-256-cbc' => 'AES_256',
  'aes-128-cbc' => 'AES_128'
}.freeze

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(region:, master_key_alias:) ⇒ Aws

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



32
33
34
35
36
37
# 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

Instance Attribute Details

#clientObject (readonly)

Returns the value of attribute client.



10
11
12
# File 'lib/symmetric_encryption/utils/aws.rb', line 10

def client
  @client
end

#master_key_aliasObject (readonly)

Returns the value of attribute master_key_alias.



10
11
12
# File 'lib/symmetric_encryption/utils/aws.rb', line 10

def master_key_alias
  @master_key_alias
end

Instance Method Details

#create_master_keyObject

Creates a new master key along with an alias that points to it. Returns [String] the new master key id that was created.



77
78
79
80
81
# 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(encrypted_data) ⇒ Object

Decrypt data previously encrypted using the cmk



54
55
56
57
58
# 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

#delete_master_key(retention_days: 30) ⇒ Object

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 !!!


89
90
91
92
93
94
95
96
97
# 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_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

#encrypt(data) ⇒ Object

Decrypt data previously encrypted using the cmk



61
62
63
64
65
# 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

#generate_data_key(cipher_name) ⇒ Object

Returns a new DEK in the clear



47
48
49
50
51
# 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

#generate_encrypted_data_key(cipher_name) ⇒ Object

Returns a new DEK encrypted using the CMK



40
41
42
43
44
# 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

#key_spec(cipher_name) ⇒ Object

Returns the AWS KMS key spec that matches the supplied OpenSSL cipher name



68
69
70
71
72
73
# 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