-
Notifications
You must be signed in to change notification settings - Fork 369
Expand file tree
/
Copy pathrotate_database_key.rb
More file actions
78 lines (66 loc) · 2.54 KB
/
rotate_database_key.rb
File metadata and controls
78 lines (66 loc) · 2.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
module VCAP::CloudController
class RotateDatabaseKey
class << self
def perform(batch_size: 1000)
@logger = Steno.logger('cc.rotate_database_key')
no_encryption_key! if Encryptor.current_encryption_key_label.blank?
Encryptor.encrypted_classes.each do |klass|
logger.info("Rotating encryption key for class #{klass}")
rotate_for_class(klass.constantize, batch_size)
logger.info("Done rotating encryption key for class #{klass}")
end
end
private
attr_accessor :logger
def no_encryption_key!
raise CloudController::Errors::ApiError.new_from_details('NoCurrentEncryptionKey')
end
def rotate_for_class(klass, batch_size)
current_key_label = Encryptor.current_encryption_key_label
rows_needing_rotation = klass.
exclude(encryption_key_label: current_key_label).
or(encryption_key_label: nil)
logger.info("#{rows_needing_rotation.count} rows of #{klass} are not encrypted with the current key and will be rotated")
loop do
rows = rows_needing_rotation.
limit(batch_size).
all
break if rows.none?
klass.instance_exec do
@allow_manual_timestamp_update = true
end
klass.descendants.select { |m| m.to_s.start_with?('VCAP::CloudController::') }.each do |model|
model.instance_exec { @allow_manual_timestamp_update = true }
end
rotate_batch(klass, rows)
logger.info("Rotated batch of #{rows.count} rows of #{klass}")
end
end
def rotate_batch(klass, rows)
encrypted_fields = klass.all_encrypted_fields
rows.each do |row|
row.db.transaction do
row.lock!
encrypt_row(encrypted_fields, row)
row.modified!(:updated_at)
row.save(validate: false, changed: true)
rescue Sequel::NoExistingObject
raise Sequel::Rollback
rescue StandardError => e
logger.error("Error '#{e.class}' occurred while updating record: #{row.class}, id: #{row.id}")
raise
end
end
end
def encrypt_row(encrypted_fields, row)
encrypted_fields.each do |field|
encrypt_field(field, row)
end
end
def encrypt_field(field, row)
field_name = field[:field_name]
row.public_send(:"#{field_name}=", row.public_send(field_name.to_sym))
end
end
end
end