Module: Himari::Aws::SecretsmanagerSigningKeyRotationHandler
- Defined in:
- lib/himari/aws/secretsmanager_signing_key_rotation_handler.rb
Defined Under Namespace
Classes: RotationRequest
Class Method Summary collapse
- .create_secret(req) ⇒ Object
- .finish_secret(req) ⇒ Object
- .generate_secret(req, _current) ⇒ Object
- .handler(event:, context:) ⇒ Object
-
.parse_keygen_param(str) ⇒ Object
Scan k=v,k2=v2.
- .prerequisite_check!(event) ⇒ Object
- .set_secret(req) ⇒ Object
- .test_secret(req) ⇒ Object
Class Method Details
.create_secret(req) ⇒ Object
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/himari/aws/secretsmanager_signing_key_rotation_handler.rb', line 50 def self.create_secret(req) current = begin @secretsmanager.get_secret_value(secret_id: req.id, version_stage: 'AWSCURRENT') rescue ::Aws::SecretsManager::Errors::ResourceNotFoundException nil end puts "createSecret: current version is: #{current.version_id} @ #{current.arn}" if current begin @secretsmanager.get_secret_value(secret_id: req.id, version_id: req.token, version_stage: 'AWSPENDING') rescue ::Aws::SecretsManager::Errors::ResourceNotFoundException puts "createSecret: generating for #{req.token} @ #{req.id}" @secretsmanager.put_secret_value( secret_id: req.id, client_request_token: req.token, secret_string: generate_secret(req, current), ) else puts "createSecret: do nothing for #{req.token} @ #{req.id}" end end |
.finish_secret(req) ⇒ Object
128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
# File 'lib/himari/aws/secretsmanager_signing_key_rotation_handler.rb', line 128 def self.finish_secret(req) current_version = req.secret.version_ids_to_stages.find { |k,v| v.include?('AWSCURRENT') }.first if current_version == req.token puts "finishSecret: #{current_version} on #{req.id} is on AWSCURRENT, do nothing" return end puts "finishSecret: update_secret_version_stage AWSCURRENT to #{req.token} from #{current_version} for #{req.id}" @secretsmanager.update_secret_version_stage( secret_id: req.id, version_stage: 'AWSCURRENT', move_to_version_id: req.token, remove_from_version_id: current_version, ) end |
.generate_secret(req, _current) ⇒ Object
73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 |
# File 'lib/himari/aws/secretsmanager_signing_key_rotation_handler.rb', line 73 def self.generate_secret(req, _current) param_raw = req.secret.&.find { |t| t.key == ENV.fetch('HIMARI_KEYGEN_PARAM_TAG_KEY', 'HimariKey') }&.value || ENV.fetch('HIMARI_KEYGEN_PARAM_DEFAULT', '{"kty": "rsa", "len": 2048}') param = parse_keygen_param(param_raw) puts "createSecret: generate_secret with #{param.inspect}" case param.fetch(:kty, 'rsa').downcase when 'rsa' rsa = OpenSSL::PKey::RSA.generate(param.fetch(:len, 2048).to_i) JSON.pretty_generate({kind: 'himari.signing_key', kty: 'rsa', rsa: {pem: rsa.to_pem}}) when 'ec' curve = case param.fetch(:len, 256).to_i when 256; 'prime256v1' when 384; 'secp384r1' when 521; 'secp521r1' else raise ArgumentError, "unknown len: #{param.inspect}" end ec = OpenSSL::PKey::EC.generate(curve) JSON.pretty_generate({kind: 'himari.signing_key', kty: 'ec', ec: {pem: ec.to_pem}}) else raise ArgumentError, "unknown kty: #{param.inspect}" end end |
.handler(event:, context:) ⇒ Object
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 |
# File 'lib/himari/aws/secretsmanager_signing_key_rotation_handler.rb', line 13 def self.handler(event:, context:) @secretsmanager ||= ::Aws::SecretsManager::Client.new() secret = prerequisite_check!(event) req = RotationRequest.new( step: event.fetch('Step'), token: event.fetch('ClientRequestToken'), id: event.fetch('SecretId'), secret: secret, ) puts JSON.generate(plan: {step: req.step, token: req.token, id: req.id}) case req.step when 'createSecret' create_secret(req) when 'setSecret' set_secret(req) when 'testSecret' test_secret(req) when 'finishSecret' finish_secret(req) else raise "Unknown Step: #{req.step}" end end |
.parse_keygen_param(str) ⇒ Object
Scan k=v,k2=v2
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 |
# File 'lib/himari/aws/secretsmanager_signing_key_rotation_handler.rb', line 98 def self.parse_keygen_param(str) begin ary = str.scan(/(.+?)=(.+?)(?:,|$)/) unless ary.empty? return ary.to_h.transform_keys(&:to_sym) end end if str.start_with?('eyJ') return JSON.parse(Base64.decode64(str), symbolize_names: true) end begin return JSON.parse(str, symbolize_names: true) rescue JSON::ParserError end raise "cannot parse keygen param #{str.inspect}" end |
.prerequisite_check!(event) ⇒ Object
40 41 42 43 44 45 46 47 48 |
# File 'lib/himari/aws/secretsmanager_signing_key_rotation_handler.rb', line 40 def self.prerequisite_check!(event) secret = @secretsmanager.describe_secret(secret_id: event.fetch('SecretId')) raise "secret #{secret.arn.inspect} have not enabled rotation" unless secret.rotation_enabled stages = secret.version_ids_to_stages[event.fetch('ClientRequestToken')] raise "Secret version #{event.fetch('ClientRequestToken').inspect} has no stage for secret #{secret.arn.inspect}" unless stages raise "Secret version #{event.fetch('ClientRequestToken').inspect} is on AWSCURRENT for secret #{secret.arn.inspect}" if stages.include?('AWSCURRENT') && !stages.include?('AWSPENDING') raise "Secret version #{event.fetch('ClientRequestToken').inspect} is not on AWSPENDING for secret #{secret.arn.inspect}" unless stages.include?('AWSPENDING') secret end |
.set_secret(req) ⇒ Object
118 119 120 121 |
# File 'lib/himari/aws/secretsmanager_signing_key_rotation_handler.rb', line 118 def self.set_secret(req) _check = @secretsmanager.get_secret_value(secret_id: req.id, version_id: req.token, version_stage: 'AWSPENDING') puts "setSecret: do nothing for #{req.token} @ #{req.id}" end |
.test_secret(req) ⇒ Object
123 124 125 126 |
# File 'lib/himari/aws/secretsmanager_signing_key_rotation_handler.rb', line 123 def self.test_secret(req) _check = @secretsmanager.get_secret_value(secret_id: req.id, version_id: req.token, version_stage: 'AWSPENDING') puts "testSecret: do nothing for #{req.token} @ #{req.id}" end |